mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-25 00:32:31 +00:00
2135a40b1c
Frame-threaded decoders with inter-frame dependencies use the ThreadFrame API for syncing. It works as follows: During init each thread allocates an AVFrame for every ThreadFrame. Thread A reads the header of its packet and allocates a buffer for an AVFrame with ff_thread_get_ext_buffer() (which also allocates a small structure that is shared with other references to this frame) and sets its fields, including side data. Then said thread calls ff_thread_finish_setup(). From that moment onward it is not allowed to change any of the AVFrame fields at all any more, but it may change fields which are an indirection away, like the content of AVFrame.data or already existing side data. After thread A has called ff_thread_finish_setup(), another thread (the user one) calls the codec's update_thread_context callback which in turn calls ff_thread_ref_frame() which calls av_frame_ref() which reads every field of A's AVFrame; hence the above restriction on modifications of the AVFrame (as any modification of the AVFrame by A after ff_thread_finish_setup() would be a data race). Of course, this av_frame_ref() also incurs allocations and therefore needs to be checked. ff_thread_ref_frame() also references the small structure used for communicating progress. This av_frame_ref() makes it awkward to propagate values that only become known during decoding to later threads (in case of frame reordering or other mechanisms of delayed output (like show-existing-frames) it's not the decoding thread, but a later thread that returns the AVFrame). E.g. for VP9 when exporting video encoding parameters as side data the number of blocks only becomes known during decoding, so one can't allocate the side data before ff_thread_finish_setup(). It is currently being done afterwards and this leads to a data race in the vp9-encparams test when using frame-threading. Returning decode_error_flags is also complicated by this. To perform this exchange a buffer shared between the references is needed (notice that simply giving the later threads a pointer to the original AVFrame does not work, because said AVFrame will be reused lateron when thread A decodes the next packet given to it). One could extend the buffer already used for progress for this or use a new one (requiring yet another allocation), yet both of these approaches have the drawback of being unnatural, ugly and requiring quite a lot of ad-hoc code. E.g. in case of the VP9 side data mentioned above one could not simply use the helper that allocates and adds the side data to an AVFrame in one go. The ProgressFrame API meanwhile offers a different solution to all of this. It is based around the idea that the most natural shared object for sharing information about an AVFrame between decoding threads is the AVFrame itself. To actually implement this the AVFrame needs to be reference counted. This is achieved by putting a (ownership) pointer into a shared (and opaque) structure that is managed by the RefStruct API and which also contains the stuff necessary for progress reporting. The users get a pointer to this AVFrame with the understanding that the owner may set all the fields until it has indicated that it has finished decoding this AVFrame; then the users are allowed to read everything. Every decoder may of course employ a different contract than the one outlined above. Given that there is no underlying av_frame_ref(), creating references to a ProgressFrame can't fail. Only ff_thread_progress_get_buffer() can fail, but given that it will replace calls to ff_thread_get_ext_buffer() it is at places where errors are already expected and properly taken care of. The ProgressFrames are empty (i.e. the AVFrame pointer is NULL and the AVFrames are not allocated during init at all) while not being in use; ff_thread_progress_get_buffer() both sets up the actual ProgressFrame and already calls ff_thread_get_buffer(). So instead of checking for ThreadFrame.f->data[0] or ThreadFrame.f->buf[0] being NULL for "this reference frame is non-existing" one should check for ProgressFrame.f. This also implies that one can only set AVFrame properties after having allocated the buffer. This restriction is not deep: if it becomes onerous for any codec, ff_thread_progress_get_buffer() can be broken up. The user would then have to get a buffer himself. In order to avoid unnecessary allocations, the shared structure is pooled, so that both the structure as well as the AVFrame itself are reused. This means that there won't be lots of unnecessary allocations in case of non-frame-threaded decoding. It might even turn out to have fewer than the current code (the current code allocates AVFrames for every DPB slot, but these are often excessively large and not completely used; the new code allocates them on demand). Pooling relies on the reset function of the RefStruct pool API, it would be impossible to implement with the AVBufferPool API. Finally, ProgressFrames have no notion of owner; they are built on top of the ThreadProgress API which also lacks such a concept. Instead every ThreadProgress and every ProgressFrame contains its own mutex and condition variable, making it completely independent of pthread_frame.c. Just like the ThreadFrame API it is simply presumed that only the actual owner/producer of a frame reports progress on said frame. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
192 lines
5.4 KiB
C
192 lines
5.4 KiB
C
/*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* FFmpeg is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* FFmpeg 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* common internal api header.
|
|
*/
|
|
|
|
#ifndef AVCODEC_INTERNAL_H
|
|
#define AVCODEC_INTERNAL_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "libavutil/channel_layout.h"
|
|
#include "avcodec.h"
|
|
#include "config.h"
|
|
|
|
#if CONFIG_LCMS2
|
|
# include "fflcms2.h"
|
|
#endif
|
|
|
|
#define FF_SANE_NB_CHANNELS 512U
|
|
|
|
#if HAVE_SIMD_ALIGN_64
|
|
# define STRIDE_ALIGN 64 /* AVX-512 */
|
|
#elif HAVE_SIMD_ALIGN_32
|
|
# define STRIDE_ALIGN 32
|
|
#elif HAVE_SIMD_ALIGN_16
|
|
# define STRIDE_ALIGN 16
|
|
#else
|
|
# define STRIDE_ALIGN 8
|
|
#endif
|
|
|
|
typedef struct AVCodecInternal {
|
|
/**
|
|
* When using frame-threaded decoding, this field is set for the first
|
|
* worker thread (e.g. to decode extradata just once).
|
|
*/
|
|
int is_copy;
|
|
|
|
/**
|
|
* Audio encoders can set this flag during init to indicate that they
|
|
* want the small last frame to be padded to a multiple of pad_samples.
|
|
*/
|
|
int pad_samples;
|
|
|
|
struct FramePool *pool;
|
|
|
|
struct FFRefStructPool *progress_frame_pool;
|
|
|
|
void *thread_ctx;
|
|
|
|
/**
|
|
* This packet is used to hold the packet given to decoders
|
|
* implementing the .decode API; it is unused by the generic
|
|
* code for decoders implementing the .receive_frame API and
|
|
* may be freely used (but not freed) by them with the caveat
|
|
* that the packet will be unreferenced generically in
|
|
* avcodec_flush_buffers().
|
|
*/
|
|
AVPacket *in_pkt;
|
|
struct AVBSFContext *bsf;
|
|
|
|
/**
|
|
* Properties (timestamps+side data) extracted from the last packet passed
|
|
* for decoding.
|
|
*/
|
|
AVPacket *last_pkt_props;
|
|
|
|
/**
|
|
* temporary buffer used for encoders to store their bitstream
|
|
*/
|
|
uint8_t *byte_buffer;
|
|
unsigned int byte_buffer_size;
|
|
|
|
void *frame_thread_encoder;
|
|
|
|
/**
|
|
* The input frame is stored here for encoders implementing the simple
|
|
* encode API.
|
|
*
|
|
* Not allocated in other cases.
|
|
*/
|
|
AVFrame *in_frame;
|
|
|
|
/**
|
|
* When the AV_CODEC_FLAG_RECON_FRAME flag is used. the encoder should store
|
|
* here the reconstructed frame corresponding to the last returned packet.
|
|
*
|
|
* Not allocated in other cases.
|
|
*/
|
|
AVFrame *recon_frame;
|
|
|
|
/**
|
|
* If this is set, then FFCodec->close (if existing) needs to be called
|
|
* for the parent AVCodecContext.
|
|
*/
|
|
int needs_close;
|
|
|
|
/**
|
|
* Number of audio samples to skip at the start of the next decoded frame
|
|
*/
|
|
int skip_samples;
|
|
|
|
/**
|
|
* hwaccel-specific private data
|
|
*/
|
|
void *hwaccel_priv_data;
|
|
|
|
/**
|
|
* checks API usage: after codec draining, flush is required to resume operation
|
|
*/
|
|
int draining;
|
|
|
|
/**
|
|
* Temporary buffers for newly received or not yet output packets/frames.
|
|
*/
|
|
AVPacket *buffer_pkt;
|
|
AVFrame *buffer_frame;
|
|
int draining_done;
|
|
|
|
#if FF_API_DROPCHANGED
|
|
/* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */
|
|
int changed_frames_dropped;
|
|
int initial_format;
|
|
int initial_width, initial_height;
|
|
int initial_sample_rate;
|
|
AVChannelLayout initial_ch_layout;
|
|
#endif
|
|
|
|
#if CONFIG_LCMS2
|
|
FFIccContext icc; /* used to read and write embedded ICC profiles */
|
|
#endif
|
|
|
|
/**
|
|
* Set when the user has been warned about a failed allocation from
|
|
* a fixed frame pool.
|
|
*/
|
|
int warned_on_failed_allocation_from_fixed_pool;
|
|
} AVCodecInternal;
|
|
|
|
/**
|
|
* Return the index into tab at which {a,b} match elements {[0],[1]} of tab.
|
|
* If there is no such matching pair then size is returned.
|
|
*/
|
|
int ff_match_2uint16(const uint16_t (*tab)[2], int size, int a, int b);
|
|
|
|
unsigned int ff_toupper4(unsigned int x);
|
|
|
|
int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx);
|
|
|
|
int avpriv_codec_get_cap_skip_frame_fill_param(const AVCodec *codec);
|
|
|
|
/**
|
|
* Check AVFrame for S12M timecode side data and allocate and fill TC SEI message with timecode info
|
|
*
|
|
* @param frame Raw frame to get S12M timecode side data from
|
|
* @param rate The frame rate
|
|
* @param prefix_len Number of bytes to allocate before SEI message
|
|
* @param data Pointer to a variable to store allocated memory
|
|
* Upon return the variable will hold NULL on error or if frame has no S12M timecode info.
|
|
* Otherwise it will point to prefix_len uninitialized bytes followed by
|
|
* *sei_size SEI message
|
|
* @param sei_size Pointer to a variable to store generated SEI message length
|
|
* @return Zero on success, negative error code on failure
|
|
*/
|
|
int ff_alloc_timecode_sei(const AVFrame *frame, AVRational rate, size_t prefix_len,
|
|
void **data, size_t *sei_size);
|
|
|
|
/**
|
|
* Get an estimated video bitrate based on frame size, frame rate and coded
|
|
* bits per pixel.
|
|
*/
|
|
int64_t ff_guess_coded_bitrate(AVCodecContext *avctx);
|
|
|
|
#endif /* AVCODEC_INTERNAL_H */
|