You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
492 lines
16 KiB
492 lines
16 KiB
4 years ago
|
/*
|
||
|
* 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 */
|