1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
|
/*
* tcframes.h -- common generic audio/video/whatever frame allocation/disposal
* routines for transcode.
* (C) 2005-2010 - Francesco Romani <fromani -at- gmail -dot- com>
*
* This file is part of transcode, a video stream processing tool.
*
* transcode is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* transcode is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TCFRAMES_H
#define TCFRAMES_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdarg.h>
#include <stdint.h>
#include <sys/types.h>
#include "libtc/libtc.h"
#include "libtc/tctimer.h"
#include "libtc/tccodecs.h"
/*************************************************************************/
/* frame attributes */
typedef enum tcframeattributes_ TCFrameAttributes;
enum tcframeattributes_ {
TC_FRAME_IS_KEYFRAME = 1,
TC_FRAME_IS_INTERLACED = 2,
TC_FRAME_IS_BROKEN = 4,
TC_FRAME_IS_SKIPPED = 8,
TC_FRAME_IS_CLONED = 16,
TC_FRAME_WAS_CLONED = 32,
TC_FRAME_IS_OUT_OF_RANGE = 64,
TC_FRAME_IS_DELAYED = 128,
TC_FRAME_IS_END_OF_STREAM = 256,
};
#define TC_FRAME_NEED_PROCESSING(PTR) \
(!((PTR)->attributes & TC_FRAME_IS_OUT_OF_RANGE) \
&& !((PTR)->attributes & TC_FRAME_IS_END_OF_STREAM))
typedef enum tcframestatus_ TCFrameStatus;
enum tcframestatus_ {
TC_FRAME_NULL = -1, /* on the frame pool, not yet claimed */
TC_FRAME_EMPTY = 0, /* claimed and being filled by decoder */
TC_FRAME_WAIT, /* needs further processing (filtering) */
TC_FRAME_LOCKED, /* being procedded by filter layer */
TC_FRAME_READY, /* ready to be processed by encoder */
};
/*
* frame status transitions scheme (overview)
*
*
* .-------<----- +-------<------+------<------+-------<-------.
* | ^ ^ ^ ^
* V | | | |
* FRAME_NULL -> FRAME_EMPTY -> FRAME_WAIT -> FRAME_LOCKED -> FRAME_READY
* :_buffer_: \_decoder_/ \______filter_stage______/ \encoder_%/
* \__pool__/ | : ^ :
* | \_______________encoder $__________|____/
* V ^
* `-------------->------------->---------------'
*
* Notes:
* % - regular case, frame (processing) threads avalaibles
* $ - practical (default) case, filtering is carried by encoder thread.
*/
/*************************************************************************/
/*
* NOTE: The following warning will become irrelevant once NMS is
* in place, and frame_list_t can go away completely. --AC
* (here's a FIXME tag so we don't forget)
*
* BIG FAT WARNING:
*
* These structures must be kept in sync: meaning that if you add
* another field to the vframe_list_t you must add it at the end
* of the structure.
*
* aframe_list_t, vframe_list_t and the wrapper frame_list_t share
* the same offsets to their elements up to the field "size". That
* means that when a filter is called with at init time with the
* anonymouse frame_list_t, it can already access the size.
*
* -- tibit
*/
/* This macro factorizes common frame data fields.
* Is not possible to completely factor out all frame_list_t fields
* because video and audio typess uses different names for same fields,
* and existing code relies on this assumption.
* Fixing this is stuff for 1.2.0 and beyond, for which I would like
* to introduce some generic frame structure or something like it. -- FR.
*/
#define TC_FRAME_COMMON \
int id; /* frame id (sequential uint) */ \
int bufid; /* buffer id */ \
int tag; /* init, open, close, ... */ \
int filter_id; /* filter instance to run */ \
TCFrameStatus status; /* see enumeration above */ \
TCFrameAttributes attributes; /* see enumeration above */ \
TCTimestamp timestamp; \
/* BEWARE: semicolon NOT NEEDED */
/*
* Size vs Length
*
* Size represent the effective size of audio/video buffer,
* while length represent the amount of valid data into buffer.
* Until 1.1.0, there isn't such distinction, and 'size'
* have approximatively a mixed meaning of above.
*
* In the long shot[1] (post-1.1.0) transcode will start
* intelligently allocate frame buffers based on highest
* request of all modules (core included) through filter
* mangling pipeline. This will lead on circumstances on
* which valid data into a buffer is less than buffer size:
* think to demuxer->decoder transition or RGB24->YUV420.
*
* There also are more specific cases like a full-YUV420P
* pipeline with final conversion to RGB24 and raw output,
* so we can have something like
*
* framebuffer size = sizeof(RGB24_frame)
* after demuxer:
* frame length << frame size (compressed data)
* after decoder:
* frame length < frame size (YUV420P smaller than RGB24)
* in filtering:
* frame length < frame size (as above)
* after encoding (in fact just colorspace transition):
* frame length == frame size (data becomes RGB24)
* into muxer:
* frame length == frame size (as above)
*
* In all those cases having a distinct 'lenght' fields help
* make things nicer and easier.
*
* +++
*
* [1] in 1.1.0 that not happens due to module interface constraints
* since we're still bound to Old Module System.
*/
#define TC_FRAME_GET_TIMESTAMP_UINT(FP) ((FP)->timestamp.u)
#define TC_FRAME_GET_TIMESTAMP_DOUBLE(FP) ((FP)->timestamp.d)
#define TC_FRAME_SET_TIMESTAMP_UINT(FP, TS) ((FP)->timestamp.u = (uint64_t)(TS))
#define TC_FRAME_SET_TIMESTAMP_DOUBLE(FP, TS) ((FP)->timestamp.d = (double)(TS))
typedef struct tcframe_ TCFrame;
struct tcframe_ {
TC_FRAME_COMMON
int codec; /* codec identifier */
int size; /* buffer size avalaible */
int len; /* how much data is valid? */
int param1; /* v_width or a_rate */
int param2; /* v_height or a_bits */
int param3; /* v_bpp or a_chan */
struct tcframe_ *next;
struct tcframe_ *prev;
};
typedef struct tcframe_ frame_list_t;
typedef struct tcframevideo_ TCFrameVideo;
struct tcframevideo_ {
TC_FRAME_COMMON
/* frame physical parameter */
int v_codec; /* codec identifier */
int video_size; /* buffer size avalaible */
int video_len; /* how much data is valid? */
int v_width;
int v_height;
int v_bpp;
struct tcframevideo_ *next;
struct tcframevideo_ *prev;
uint8_t *video_buf; /* pointer to current buffer */
uint8_t *video_buf2; /* pointer to backup buffer */
int free; /* flag */
#ifdef STATBUFFER
uint8_t *internal_video_buf_0;
uint8_t *internal_video_buf_1;
#else
uint8_t internal_video_buf_0[SIZE_RGB_FRAME];
uint8_t internal_video_buf_1[SIZE_RGB_FRAME];
#endif
int deinter_flag;
/* set to N for internal de-interlacing with "-I N" */
uint8_t *video_buf_RGB[2];
uint8_t *video_buf_Y[2];
uint8_t *video_buf_U[2];
uint8_t *video_buf_V[2];
};
typedef struct tcframevideo_ vframe_list_t;
typedef struct tcframeaudio_ TCFrameAudio;
struct tcframeaudio_ {
TC_FRAME_COMMON
int a_codec; /* codec identifier */
int audio_size; /* buffer size avalaible */
int audio_len; /* how much data is valid? */
int a_rate;
int a_bits;
int a_chan;
struct tcframeaudio_ *next;
struct tcframeaudio_ *prev;
uint8_t *audio_buf;
uint8_t *audio_buf2;
int free; /* flag */
#ifdef STATBUFFER
uint8_t *internal_audio_buf;
uint8_t *internal_audio_buf_1;
#else
uint8_t internal_audio_buf[SIZE_PCM_FRAME * 2];
uint8_t internal_audio_buf_1[SIZE_PCM_FRAME * 2];
#endif
};
typedef struct tcframeaudio_ aframe_list_t;
/*
* generic pointer type, needed at least by internal code.
* In the long (long) shot I'd like to use a unique generic
* data container, like AVPacket (libavcodec) or something like it.
* (see note about TC_FRAME_COMMON above) -- FR
*/
typedef union tcframeptr_ TCFramePtr;
union tcframeptr_ {
TCFrame *generic;
TCFrameVideo *video;
TCFrameAudio *audio;
};
/*************************************************************************/
/*
* tc_video_planes_size:
* compute the size of video planes given frame size and frame format.
* Recognizes only video formats used in transcode.
*
* Parameters:
* psizes: array of size that will be filled with size of respective
* plane, in order. If given format isn't a planar one, only
* first element in array is significant.
* width: width of video frame
* height: height of video frame
* format: format of video frame
* Return Value:
* >= 0 if succesfull,
* TC_NULL_MATCH otherwise (wrong/unknown parameters)
*/
int tc_video_planes_size(size_t psizes[3],
int width, int height, int format);
/*
* tc_video_frame_size:
* little helper function that returns the full dimension of a
* video frame given dimensions and format.
*
* Parameters:
* width: width of video frame
* height: height of video frame
* format: format of video frame
* Return Value:
* size in bytes of video frame
*/
#ifdef HAVE_GCC_ATTRIBUTES
__attribute__((unused))
#endif
static size_t tc_video_frame_size(int width, int height, int format)
{
size_t psizes[3] = { 0, 0, 0 };
tc_video_planes_size(psizes, width, height, format);
return (psizes[0] + psizes[1] + psizes[2]);
}
/*
* OK, we have sample rate. But sample rate means "[audio] samples PER SECOND"
* and we want audio samples PER FRAME.
*/
#define TC_AUDIO_SAMPLES_IN_FRAME(rate, fps) ((double)rate/(double)fps)
/*
* tc_audio_frame_size:
* compute the size of buffer needed to store the audio data described by
* given specifiers.
*
* Parameters:
* samples: audio samples PER FRAME. Can (and it's likely that it will)
* be a real numner (values after the point are significant!)
* channels: audio channels.
* bits: audio BITS for sample.
* adjust: store here adjustement value. Such value means how much extra
* buffer size it's needed to safely store extra samples.
* We have extra samples when rate/fps != 0, so we can
* spread all samples in frames, there is something that
* "exceed" :)
* (OK, there is *A LOT* of room for improvement here. But this
* API it's also driven by legacy code).
* Return Value:
* amount of buffer needed.
* Preconditions:
* adjust != NULL.
*/
size_t tc_audio_frame_size(double samples, int channels,
int bits, int *adjust);
/*
* tc_alloc_{video,audio}_frame:
* allocate, but NOT initialize, a {TCFrameVideo,TCFrameAudio},
* large enough to hold a video frame large as given size.
* This function guarantee that video buffer(s) memory will
* be page-aligned.
*
* Parameters:
* size: size in bytes of video frame that will be contained.
* partial: if !0, doesn't allocate secondary video buffer,
* but only primary. This allow to save memory since
* secondary video buffer isn't ALWAYS needed.
* Return Value:
* pointer to a new TCFrameVideo (free it using tc_del_video_frame,
* not manually! ) if succesfull, NULL otherwise.
*/
TCFrameVideo *tc_alloc_video_frame(size_t size, int partial);
TCFrameAudio *tc_alloc_audio_frame(size_t size);
/*
* tc_init_video_frame:
* properly (re)initialize an already-allocated video frame, by
* asjusting plane pointers, (re)setting video buffer pointers,
* cleaning flags et. al.
* You usually always need to use this function unless you
* perfectly knows what you're doing.
* Do nothing if missing TCFrameVideo to (re)initialize of
* one or more parameter are wrong.
*
* Parameters:
* vptr: pointer to TCFrameVideo to (re)initialize.
* width: video frame width.
* height: video frame height.
* format: video frame format.
* Return Value:
* None
* Preconditions:
* given TCFrameVideo MUST be already allocated to be large
* enough to safely store a video frame with given
* parameters. This function DO NOT check if this precondition
* is respected.
*/
void tc_init_video_frame(TCFrameVideo *vptr,
int width, int height, int format);
/*
* tc_init_audio_frame:
* properly (re)initialize an already-allocated audio frame,
* (re)setting video buffer pointers,cleaning flags et. al.
* You usually always need to use this function unless you
* perfectly knows what you're doing.
* Do nothing if missing TCFrameAudio to (re)initialize of
* one or more parameter are wrong.
*
* Parameters:
* aptr: pointer to TCFrameAudio to (re)initialize.
* samples: audio frame samples that this audio frame
* will contain (WARNING: TCFrameAudio MUST
* be allocated accordingly).
* channels: audio frame channels.
* bits: audio frame bit for sample.
* Return Value:
* None
* Preconditions:
* given TCFrameAudio MUST be already allocated to be large
* enough to safely store an audio frame with given
* parameters. This function DO NOT check if this precondition
* is respected.
*/
void tc_init_audio_frame(TCFrameAudio *aptr,
double samples, int channels, int bits);
/*
* tc_new_video_frame:
* allocate and initialize a new TCFrameVideo large enough
* to hold a video frame represented by given parameters.
* This function guarantee that video buffer(s) memory will
* be page-aligned.
*
* Parameters:
* width: video frame width.
* height: video frame height.
* format: video frame format.
* partial: if !0, doesn't allocate secondary video buffer,
* but only primary. This allow to save memory since
* secondary video buffer isn't ALWAYS needed.
* Return Value:
* pointer to a new TCFrameVideo (free it using tc_del_video_frame,
* not manually! ) if succesfull, NULL otherwise.
*/
TCFrameVideo *tc_new_video_frame(int width, int height, int format,
int partial);
/*
* tc_new_audio_frame:
* allocate and initialize a new TCFrameAudio large enough
* to hold an audio frame represented by given parameters.
* This function guarantee that audio buffer memory will
* be page-aligned.
*
* Parameters:
* samples: audio frame samples that this audio frame
* will contain (WARNING: TCFrameAudio MUST
* be allocated accordingly).
* channels: audio frame channels.
* bits: audio frame bit for sample.
* Return Value:
* pointer to a new TCFrameAudio (free it using tc_del_audio_frame,
* not manually! ) if succesfull, NULL otherwise.
*/
TCFrameAudio *tc_new_audio_frame(double samples, int channels, int bits);
/*
* tc_del_{video,audio}_frame:
* safely deallocate memory obtained with tc_new_{video,audio}_frame
* or tc_alloc_{video,audio}_frame.
*
* Parameters:
* {vptr,aptr}: a pointer to a TCFrame{Video,Audio} obtained by calling
* tc_new_{video,audio}_frame or tc_alloc_{video,audio}_frame.
* Return Value:
* None
*/
void tc_del_video_frame(TCFrameVideo *vptr);
void tc_del_audio_frame(TCFrameAudio *aptr);
/*
* tc_blank_{video,audio}_frame:
* fill a provided frame with per-format valid but blank (null)
* content.
*
* Parameters:
* ptr: pointer to frame to fill.
* Return Value:
* None.
*/
void tc_blank_video_frame(TCFrameVideo *ptr);
void tc_blank_audio_frame(TCFrameAudio *ptr);
#endif /* TCFRAMES_H */
|