|
|
|
/*
|
|
|
|
* generic decoding-related code
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#if CONFIG_ICONV
|
|
|
|
# include <iconv.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "libavutil/avassert.h"
|
|
|
|
#include "libavutil/channel_layout.h"
|
|
|
|
#include "libavutil/common.h"
|
|
|
|
#include "libavutil/emms.h"
|
|
|
|
#include "libavutil/frame.h"
|
|
|
|
#include "libavutil/hwcontext.h"
|
|
|
|
#include "libavutil/imgutils.h"
|
|
|
|
#include "libavutil/internal.h"
|
|
|
|
#include "libavutil/mastering_display_metadata.h"
|
|
|
|
#include "libavutil/mem.h"
|
|
|
|
|
|
|
|
#include "avcodec.h"
|
|
|
|
#include "avcodec_internal.h"
|
|
|
|
#include "bytestream.h"
|
|
|
|
#include "bsf.h"
|
|
|
|
#include "codec_desc.h"
|
|
|
|
#include "codec_internal.h"
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
#include "decode.h"
|
|
|
|
#include "hwaccel_internal.h"
|
|
|
|
#include "hwconfig.h"
|
|
|
|
#include "internal.h"
|
|
|
|
#include "packet_internal.h"
|
avcodec/decode: Add new ProgressFrame API
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>
2 years ago
|
|
|
#include "progressframe.h"
|
|
|
|
#include "refstruct.h"
|
|
|
|
#include "thread.h"
|
avcodec/decode: Add new ProgressFrame API
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>
2 years ago
|
|
|
#include "threadprogress.h"
|
|
|
|
|
|
|
|
typedef struct DecodeContext {
|
|
|
|
AVCodecInternal avci;
|
|
|
|
|
|
|
|
/* to prevent infinite loop on errors when draining */
|
|
|
|
int nb_draining_errors;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The caller has submitted a NULL packet on input.
|
|
|
|
*/
|
|
|
|
int draining_started;
|
|
|
|
|
|
|
|
int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far
|
|
|
|
int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far
|
|
|
|
int64_t pts_correction_last_pts; /// PTS of the last frame
|
|
|
|
int64_t pts_correction_last_dts; /// DTS of the last frame
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Bitmask indicating for which side data types we prefer user-supplied
|
|
|
|
* (global or attached to packets) side data over bytestream.
|
|
|
|
*/
|
|
|
|
uint64_t side_data_pref_mask;
|
|
|
|
} DecodeContext;
|
|
|
|
|
|
|
|
static DecodeContext *decode_ctx(AVCodecInternal *avci)
|
|
|
|
{
|
|
|
|
return (DecodeContext *)avci;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int apply_param_change(AVCodecContext *avctx, const AVPacket *avpkt)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
size_t size;
|
|
|
|
const uint8_t *data;
|
|
|
|
uint32_t flags;
|
|
|
|
int64_t val;
|
|
|
|
|
|
|
|
data = av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, &size);
|
|
|
|
if (!data)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(avctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE)) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "This decoder does not support parameter "
|
|
|
|
"changes, but PARAM_CHANGE side data was sent to it.\n");
|
|
|
|
ret = AVERROR(EINVAL);
|
|
|
|
goto fail2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size < 4)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
flags = bytestream_get_le32(&data);
|
|
|
|
size -= 4;
|
|
|
|
|
|
|
|
if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) {
|
|
|
|
if (size < 4)
|
|
|
|
goto fail;
|
|
|
|
val = bytestream_get_le32(&data);
|
|
|
|
if (val <= 0 || val > INT_MAX) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid sample rate");
|
|
|
|
ret = AVERROR_INVALIDDATA;
|
|
|
|
goto fail2;
|
|
|
|
}
|
|
|
|
avctx->sample_rate = val;
|
|
|
|
size -= 4;
|
|
|
|
}
|
|
|
|
if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) {
|
|
|
|
if (size < 8)
|
|
|
|
goto fail;
|
|
|
|
avctx->width = bytestream_get_le32(&data);
|
|
|
|
avctx->height = bytestream_get_le32(&data);
|
|
|
|
size -= 8;
|
|
|
|
ret = ff_set_dimensions(avctx, avctx->width, avctx->height);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "PARAM_CHANGE side data too small.\n");
|
|
|
|
ret = AVERROR_INVALIDDATA;
|
|
|
|
fail2:
|
|
|
|
if (ret < 0) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
|
|
|
|
if (avctx->err_recognition & AV_EF_EXPLODE)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
av_packet_unref(avci->last_pkt_props);
|
|
|
|
if (pkt) {
|
|
|
|
ret = av_packet_copy_props(avci->last_pkt_props, pkt);
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
#if FF_API_FRAME_PKT
|
|
|
|
if (!ret)
|
|
|
|
avci->last_pkt_props->stream_index = pkt->size; // Needed for ff_decode_frame_props().
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int decode_bsfs_init(AVCodecContext *avctx)
|
|
|
|
{
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
const FFCodec *const codec = ffcodec(avctx->codec);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (avci->bsf)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = av_bsf_list_parse_str(codec->bsfs, &avci->bsf);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Error parsing decoder bitstream filters '%s': %s\n", codec->bsfs, av_err2str(ret));
|
|
|
|
if (ret != AVERROR(ENOMEM))
|
|
|
|
ret = AVERROR_BUG;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We do not currently have an API for passing the input timebase into decoders,
|
|
|
|
* but no filters used here should actually need it.
|
|
|
|
* So we make up some plausible-looking number (the MPEG 90kHz timebase) */
|
|
|
|
avci->bsf->time_base_in = (AVRational){ 1, 90000 };
|
|
|
|
ret = avcodec_parameters_from_context(avci->bsf->par_in, avctx);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
ret = av_bsf_init(avci->bsf);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
|
|
av_bsf_free(&avci->bsf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int decode_get_packet(AVCodecContext *avctx, AVPacket *pkt)
|
|
|
|
{
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = av_bsf_receive_packet(avci->bsf, pkt);
|
|
|
|
if (ret == AVERROR_EOF)
|
|
|
|
avci->draining = 1;
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
|
|
|
|
if (!(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) {
|
|
|
|
ret = extract_packet_props(avctx->internal, pkt);
|
|
|
|
if (ret < 0)
|
|
|
|
goto finish;
|
|
|
|
}
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
|
|
|
|
ret = apply_param_change(avctx, pkt);
|
|
|
|
if (ret < 0)
|
|
|
|
goto finish;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
finish:
|
|
|
|
av_packet_unref(pkt);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt)
|
|
|
|
{
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
DecodeContext *dc = decode_ctx(avci);
|
|
|
|
|
|
|
|
if (avci->draining)
|
|
|
|
return AVERROR_EOF;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int ret = decode_get_packet(avctx, pkt);
|
|
|
|
if (ret == AVERROR(EAGAIN) &&
|
|
|
|
(!AVPACKET_IS_EMPTY(avci->buffer_pkt) || dc->draining_started)) {
|
|
|
|
ret = av_bsf_send_packet(avci->bsf, avci->buffer_pkt);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_packet_unref(avci->buffer_pkt);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempt to guess proper monotonic timestamps for decoded video frames
|
|
|
|
* which might have incorrect times. Input timestamps may wrap around, in
|
|
|
|
* which case the output will as well.
|
|
|
|
*
|
|
|
|
* @param pts the pts field of the decoded AVPacket, as passed through
|
|
|
|
* AVFrame.pts
|
|
|
|
* @param dts the dts field of the decoded AVPacket
|
|
|
|
* @return one of the input values, may be AV_NOPTS_VALUE
|
|
|
|
*/
|
|
|
|
static int64_t guess_correct_pts(DecodeContext *dc,
|
|
|
|
int64_t reordered_pts, int64_t dts)
|
|
|
|
{
|
|
|
|
int64_t pts = AV_NOPTS_VALUE;
|
|
|
|
|
|
|
|
if (dts != AV_NOPTS_VALUE) {
|
|
|
|
dc->pts_correction_num_faulty_dts += dts <= dc->pts_correction_last_dts;
|
|
|
|
dc->pts_correction_last_dts = dts;
|
|
|
|
} else if (reordered_pts != AV_NOPTS_VALUE)
|
|
|
|
dc->pts_correction_last_dts = reordered_pts;
|
|
|
|
|
|
|
|
if (reordered_pts != AV_NOPTS_VALUE) {
|
|
|
|
dc->pts_correction_num_faulty_pts += reordered_pts <= dc->pts_correction_last_pts;
|
|
|
|
dc->pts_correction_last_pts = reordered_pts;
|
|
|
|
} else if(dts != AV_NOPTS_VALUE)
|
|
|
|
dc->pts_correction_last_pts = dts;
|
|
|
|
|
|
|
|
if ((dc->pts_correction_num_faulty_pts<=dc->pts_correction_num_faulty_dts || dts == AV_NOPTS_VALUE)
|
|
|
|
&& reordered_pts != AV_NOPTS_VALUE)
|
|
|
|
pts = reordered_pts;
|
|
|
|
else
|
|
|
|
pts = dts;
|
|
|
|
|
|
|
|
return pts;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int discard_samples(AVCodecContext *avctx, AVFrame *frame, int64_t *discarded_samples)
|
|
|
|
{
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
AVFrameSideData *side;
|
|
|
|
uint32_t discard_padding = 0;
|
|
|
|
uint8_t skip_reason = 0;
|
|
|
|
uint8_t discard_reason = 0;
|
|
|
|
|
|
|
|
side = av_frame_get_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES);
|
|
|
|
if (side && side->size >= 10) {
|
|
|
|
avci->skip_samples = AV_RL32(side->data);
|
|
|
|
avci->skip_samples = FFMAX(0, avci->skip_samples);
|
|
|
|
discard_padding = AV_RL32(side->data + 4);
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "skip %d / discard %d samples due to side data\n",
|
|
|
|
avci->skip_samples, (int)discard_padding);
|
|
|
|
skip_reason = AV_RL8(side->data + 8);
|
|
|
|
discard_reason = AV_RL8(side->data + 9);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {
|
|
|
|
if (!side && (avci->skip_samples || discard_padding))
|
|
|
|
side = av_frame_new_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES, 10);
|
|
|
|
if (side && (avci->skip_samples || discard_padding)) {
|
|
|
|
AV_WL32(side->data, avci->skip_samples);
|
|
|
|
AV_WL32(side->data + 4, discard_padding);
|
|
|
|
AV_WL8(side->data + 8, skip_reason);
|
|
|
|
AV_WL8(side->data + 9, discard_reason);
|
|
|
|
avci->skip_samples = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
av_frame_remove_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES);
|
|
|
|
|
|
|
|
if ((frame->flags & AV_FRAME_FLAG_DISCARD)) {
|
|
|
|
avci->skip_samples = FFMAX(0, avci->skip_samples - frame->nb_samples);
|
|
|
|
*discarded_samples += frame->nb_samples;
|
|
|
|
return AVERROR(EAGAIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (avci->skip_samples > 0) {
|
|
|
|
if (frame->nb_samples <= avci->skip_samples){
|
|
|
|
*discarded_samples += frame->nb_samples;
|
|
|
|
avci->skip_samples -= frame->nb_samples;
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "skip whole frame, skip left: %d\n",
|
|
|
|
avci->skip_samples);
|
|
|
|
return AVERROR(EAGAIN);
|
|
|
|
} else {
|
|
|
|
av_samples_copy(frame->extended_data, frame->extended_data, 0, avci->skip_samples,
|
|
|
|
frame->nb_samples - avci->skip_samples, avctx->ch_layout.nb_channels, frame->format);
|
|
|
|
if (avctx->pkt_timebase.num && avctx->sample_rate) {
|
|
|
|
int64_t diff_ts = av_rescale_q(avci->skip_samples,
|
|
|
|
(AVRational){1, avctx->sample_rate},
|
|
|
|
avctx->pkt_timebase);
|
|
|
|
if (frame->pts != AV_NOPTS_VALUE)
|
|
|
|
frame->pts += diff_ts;
|
|
|
|
if (frame->pkt_dts != AV_NOPTS_VALUE)
|
|
|
|
frame->pkt_dts += diff_ts;
|
|
|
|
if (frame->duration >= diff_ts)
|
|
|
|
frame->duration -= diff_ts;
|
|
|
|
} else
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for skipped samples.\n");
|
|
|
|
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "skip %d/%d samples\n",
|
|
|
|
avci->skip_samples, frame->nb_samples);
|
|
|
|
*discarded_samples += avci->skip_samples;
|
|
|
|
frame->nb_samples -= avci->skip_samples;
|
|
|
|
avci->skip_samples = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (discard_padding > 0 && discard_padding <= frame->nb_samples) {
|
|
|
|
if (discard_padding == frame->nb_samples) {
|
|
|
|
*discarded_samples += frame->nb_samples;
|
|
|
|
return AVERROR(EAGAIN);
|
|
|
|
} else {
|
|
|
|
if (avctx->pkt_timebase.num && avctx->sample_rate) {
|
|
|
|
int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding,
|
|
|
|
(AVRational){1, avctx->sample_rate},
|
|
|
|
avctx->pkt_timebase);
|
|
|
|
frame->duration = diff_ts;
|
|
|
|
} else
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n");
|
|
|
|
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "discard %d/%d samples\n",
|
|
|
|
(int)discard_padding, frame->nb_samples);
|
|
|
|
frame->nb_samples -= discard_padding;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
/*
|
|
|
|
* The core of the receive_frame_wrapper for the decoders implementing
|
|
|
|
* the simple API. Certain decoders might consume partial packets without
|
|
|
|
* returning any output, so this function needs to be called in a loop until it
|
|
|
|
* returns EAGAIN.
|
|
|
|
**/
|
|
|
|
static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, int64_t *discarded_samples)
|
|
|
|
{
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
AVPacket *const pkt = avci->in_pkt;
|
|
|
|
const FFCodec *const codec = ffcodec(avctx->codec);
|
|
|
|
int got_frame, consumed;
|
|
|
|
int ret;
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
if (!pkt->data && !avci->draining) {
|
|
|
|
av_packet_unref(pkt);
|
|
|
|
ret = ff_decode_get_packet(avctx, pkt);
|
|
|
|
if (ret < 0 && ret != AVERROR_EOF)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Some codecs (at least wma lossless) will crash when feeding drain packets
|
|
|
|
// after EOF was signaled.
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
if (avci->draining_done)
|
|
|
|
return AVERROR_EOF;
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
if (!pkt->data &&
|
|
|
|
!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY ||
|
|
|
|
avctx->active_thread_type & FF_THREAD_FRAME))
|
|
|
|
return AVERROR_EOF;
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
got_frame = 0;
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) {
|
|
|
|
consumed = ff_thread_decode_frame(avctx, frame, &got_frame, pkt);
|
|
|
|
} else {
|
|
|
|
consumed = codec->cb.decode(avctx, frame, &got_frame, pkt);
|
|
|
|
|
|
|
|
if (!(codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS))
|
|
|
|
frame->pkt_dts = pkt->dts;
|
|
|
|
if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
#if FF_API_FRAME_PKT
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
if(!avctx->has_b_frames)
|
|
|
|
frame->pkt_pos = pkt->pos;
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
emms_c();
|
|
|
|
|
|
|
|
if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
|
|
|
|
ret = (!got_frame || frame->flags & AV_FRAME_FLAG_DISCARD)
|
|
|
|
? AVERROR(EAGAIN)
|
|
|
|
: 0;
|
|
|
|
} else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
|
|
|
|
ret = !got_frame ? AVERROR(EAGAIN)
|
|
|
|
: discard_samples(avctx, frame, discarded_samples);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == AVERROR(EAGAIN))
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
av_frame_unref(frame);
|
|
|
|
|
|
|
|
// FF_CODEC_CB_TYPE_DECODE decoders must not return AVERROR EAGAIN
|
|
|
|
// code later will add AVERROR(EAGAIN) to a pointer
|
|
|
|
av_assert0(consumed != AVERROR(EAGAIN));
|
|
|
|
if (consumed < 0)
|
|
|
|
ret = consumed;
|
|
|
|
if (consumed >= 0 && avctx->codec->type == AVMEDIA_TYPE_VIDEO)
|
|
|
|
consumed = pkt->size;
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
av_assert0(frame->buf[0]);
|
|
|
|
if (ret == AVERROR(EAGAIN))
|
|
|
|
ret = 0;
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
|
|
|
|
/* do not stop draining when got_frame != 0 or ret < 0 */
|
|
|
|
if (avci->draining && !got_frame) {
|
|
|
|
if (ret < 0) {
|
|
|
|
/* prevent infinite loop if a decoder wrongly always return error on draining */
|
|
|
|
/* reasonable nb_errors_max = maximum b frames + thread count */
|
|
|
|
int nb_errors_max = 20 + (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME ?
|
|
|
|
avctx->thread_count : 1);
|
|
|
|
|
|
|
|
if (decode_ctx(avci)->nb_draining_errors++ >= nb_errors_max) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Too many errors when draining, this is a bug. "
|
|
|
|
"Stop draining and force EOF.\n");
|
|
|
|
avci->draining_done = 1;
|
|
|
|
ret = AVERROR_BUG;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
avci->draining_done = 1;
|
|
|
|
}
|
|
|
|
}
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
|
|
|
|
if (consumed >= pkt->size || ret < 0) {
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
av_packet_unref(pkt);
|
|
|
|
} else {
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
pkt->data += consumed;
|
|
|
|
pkt->size -= consumed;
|
|
|
|
pkt->pts = AV_NOPTS_VALUE;
|
|
|
|
pkt->dts = AV_NOPTS_VALUE;
|
|
|
|
if (!(codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) {
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
#if FF_API_FRAME_PKT
|
|
|
|
// See extract_packet_props() comment.
|
|
|
|
avci->last_pkt_props->stream_index = avci->last_pkt_props->stream_index - consumed;
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
#endif
|
|
|
|
avci->last_pkt_props->pts = AV_NOPTS_VALUE;
|
|
|
|
avci->last_pkt_props->dts = AV_NOPTS_VALUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
}
|
|
|
|
|
|
|
|
#if CONFIG_LCMS2
|
|
|
|
static int detect_colorspace(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
enum AVColorTransferCharacteristic trc;
|
|
|
|
AVColorPrimariesDesc coeffs;
|
|
|
|
enum AVColorPrimaries prim;
|
|
|
|
cmsHPROFILE profile;
|
|
|
|
AVFrameSideData *sd;
|
|
|
|
int ret;
|
|
|
|
if (!(avctx->flags2 & AV_CODEC_FLAG2_ICC_PROFILES))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE);
|
|
|
|
if (!sd || !sd->size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!avci->icc.avctx) {
|
|
|
|
ret = ff_icc_context_init(&avci->icc, avctx);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
profile = cmsOpenProfileFromMemTHR(avci->icc.ctx, sd->data, sd->size);
|
|
|
|
if (!profile)
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
|
|
|
ret = ff_icc_profile_sanitize(&avci->icc, profile);
|
|
|
|
if (!ret)
|
|
|
|
ret = ff_icc_profile_read_primaries(&avci->icc, profile, &coeffs);
|
|
|
|
if (!ret)
|
|
|
|
ret = ff_icc_profile_detect_transfer(&avci->icc, profile, &trc);
|
|
|
|
cmsCloseProfile(profile);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
prim = av_csp_primaries_id_from_desc(&coeffs);
|
|
|
|
if (prim != AVCOL_PRI_UNSPECIFIED)
|
|
|
|
frame->color_primaries = prim;
|
|
|
|
if (trc != AVCOL_TRC_UNSPECIFIED)
|
|
|
|
frame->color_trc = trc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else /* !CONFIG_LCMS2 */
|
|
|
|
static int detect_colorspace(av_unused AVCodecContext *c, av_unused AVFrame *f)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int fill_frame_props(const AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (frame->color_primaries == AVCOL_PRI_UNSPECIFIED)
|
|
|
|
frame->color_primaries = avctx->color_primaries;
|
|
|
|
if (frame->color_trc == AVCOL_TRC_UNSPECIFIED)
|
|
|
|
frame->color_trc = avctx->color_trc;
|
|
|
|
if (frame->colorspace == AVCOL_SPC_UNSPECIFIED)
|
|
|
|
frame->colorspace = avctx->colorspace;
|
|
|
|
if (frame->color_range == AVCOL_RANGE_UNSPECIFIED)
|
|
|
|
frame->color_range = avctx->color_range;
|
|
|
|
if (frame->chroma_location == AVCHROMA_LOC_UNSPECIFIED)
|
|
|
|
frame->chroma_location = avctx->chroma_sample_location;
|
|
|
|
|
|
|
|
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
|
|
|
if (!frame->sample_aspect_ratio.num) frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
|
|
|
|
if (frame->format == AV_PIX_FMT_NONE) frame->format = avctx->pix_fmt;
|
|
|
|
} else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
|
|
|
|
if (frame->format == AV_SAMPLE_FMT_NONE)
|
|
|
|
frame->format = avctx->sample_fmt;
|
|
|
|
if (!frame->ch_layout.nb_channels) {
|
|
|
|
ret = av_channel_layout_copy(&frame->ch_layout, &avctx->ch_layout);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (!frame->sample_rate)
|
|
|
|
frame->sample_rate = avctx->sample_rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int64_t discarded_samples = 0;
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
|
|
|
|
while (!frame->buf[0]) {
|
|
|
|
if (discarded_samples > avctx->max_samples)
|
|
|
|
return AVERROR(EAGAIN);
|
|
|
|
ret = decode_simple_internal(avctx, frame, &discarded_samples);
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
DecodeContext *dc = decode_ctx(avci);
|
|
|
|
const FFCodec *const codec = ffcodec(avctx->codec);
|
|
|
|
int ret, ok;
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
av_assert0(!frame->buf[0]);
|
|
|
|
|
|
|
|
if (codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME) {
|
|
|
|
ret = codec->cb.receive_frame(avctx, frame);
|
|
|
|
emms_c();
|
|
|
|
if (!ret) {
|
|
|
|
if (avctx->codec->type == AVMEDIA_TYPE_VIDEO)
|
|
|
|
ret = (frame->flags & AV_FRAME_FLAG_DISCARD) ? AVERROR(EAGAIN) : 0;
|
|
|
|
else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
|
|
|
|
int64_t discarded_samples = 0;
|
|
|
|
ret = discard_samples(avctx, frame, &discarded_samples);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
ret = decode_simple_receive_frame(avctx, frame);
|
|
|
|
|
|
|
|
if (ret == AVERROR_EOF)
|
|
|
|
avci->draining_done = 1;
|
|
|
|
|
|
|
|
/* preserve ret */
|
|
|
|
ok = detect_colorspace(avctx, frame);
|
|
|
|
if (ok < 0) {
|
|
|
|
av_frame_unref(frame);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
|
|
|
if (!frame->width)
|
|
|
|
frame->width = avctx->width;
|
|
|
|
if (!frame->height)
|
|
|
|
frame->height = avctx->height;
|
|
|
|
} else
|
|
|
|
frame->flags |= AV_FRAME_FLAG_KEY;
|
|
|
|
|
|
|
|
ret = fill_frame_props(avctx, frame);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_frame_unref(frame);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if FF_API_FRAME_KEY
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
frame->key_frame = !!(frame->flags & AV_FRAME_FLAG_KEY);
|
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
#if FF_API_INTERLACED_FRAME
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
frame->interlaced_frame = !!(frame->flags & AV_FRAME_FLAG_INTERLACED);
|
|
|
|
frame->top_field_first = !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST);
|
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
frame->best_effort_timestamp = guess_correct_pts(dc,
|
|
|
|
frame->pts,
|
|
|
|
frame->pkt_dts);
|
|
|
|
|
|
|
|
/* the only case where decode data is not set should be decoders
|
|
|
|
* that do not call ff_get_buffer() */
|
|
|
|
av_assert0((frame->private_ref && frame->private_ref->size == sizeof(FrameDecodeData)) ||
|
|
|
|
!(avctx->codec->capabilities & AV_CODEC_CAP_DR1));
|
|
|
|
|
|
|
|
if (frame->private_ref) {
|
|
|
|
FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
|
|
|
|
|
|
|
|
if (fdd->post_process) {
|
|
|
|
ret = fdd->post_process(avctx, frame);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_frame_unref(frame);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free the per-frame decode data */
|
|
|
|
av_buffer_unref(&frame->private_ref);
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
|
|
|
|
{
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
DecodeContext *dc = decode_ctx(avci);
|
|
|
|
int ret;
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
|
|
|
|
if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
|
|
|
|
if (dc->draining_started)
|
|
|
|
return AVERROR_EOF;
|
|
|
|
|
|
|
|
if (avpkt && !avpkt->size && avpkt->data)
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
|
|
|
|
if (avpkt && (avpkt->data || avpkt->side_data_elems)) {
|
|
|
|
if (!AVPACKET_IS_EMPTY(avci->buffer_pkt))
|
|
|
|
return AVERROR(EAGAIN);
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
ret = av_packet_ref(avci->buffer_pkt, avpkt);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
} else
|
|
|
|
dc->draining_started = 1;
|
|
|
|
|
|
|
|
if (!avci->buffer_frame->buf[0] && !dc->draining_started) {
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
ret = decode_receive_frame_internal(avctx, avci->buffer_frame);
|
|
|
|
if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int apply_cropping(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
|
|
|
/* make sure we are noisy about decoders returning invalid cropping data */
|
|
|
|
if (frame->crop_left >= INT_MAX - frame->crop_right ||
|
|
|
|
frame->crop_top >= INT_MAX - frame->crop_bottom ||
|
|
|
|
(frame->crop_left + frame->crop_right) >= frame->width ||
|
|
|
|
(frame->crop_top + frame->crop_bottom) >= frame->height) {
|
|
|
|
av_log(avctx, AV_LOG_WARNING,
|
|
|
|
"Invalid cropping information set by a decoder: "
|
|
|
|
"%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER" "
|
|
|
|
"(frame size %dx%d). This is a bug, please report it\n",
|
|
|
|
frame->crop_left, frame->crop_right, frame->crop_top, frame->crop_bottom,
|
|
|
|
frame->width, frame->height);
|
|
|
|
frame->crop_left = 0;
|
|
|
|
frame->crop_right = 0;
|
|
|
|
frame->crop_top = 0;
|
|
|
|
frame->crop_bottom = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!avctx->apply_cropping)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return av_frame_apply_cropping(frame, avctx->flags & AV_CODEC_FLAG_UNALIGNED ?
|
|
|
|
AV_FRAME_CROP_UNALIGNED : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure frames returned to the caller are valid
|
|
|
|
static int frame_validate(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
|
|
|
if (!frame->buf[0] || frame->format < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
switch (avctx->codec_type) {
|
|
|
|
case AVMEDIA_TYPE_VIDEO:
|
|
|
|
if (frame->width <= 0 || frame->height <= 0)
|
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case AVMEDIA_TYPE_AUDIO:
|
|
|
|
if (!av_channel_layout_check(&frame->ch_layout) ||
|
|
|
|
frame->sample_rate <= 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
break;
|
|
|
|
default: av_assert0(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "An invalid frame was output by a decoder. "
|
|
|
|
"This is a bug, please report it.\n");
|
|
|
|
return AVERROR_BUG;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
|
decode: restructure the core decoding code
Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.
Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.
The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.
avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
8 years ago
|
|
|
if (avci->buffer_frame->buf[0]) {
|
|
|
|
av_frame_move_ref(frame, avci->buffer_frame);
|
|
|
|
} else {
|
|
|
|
ret = decode_receive_frame_internal(avctx, frame);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = frame_validate(avctx, frame);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
|
|
|
ret = apply_cropping(avctx, frame);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
avctx->frame_num++;
|
|
|
|
|
|
|
|
#if FF_API_DROPCHANGED
|
|
|
|
if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) {
|
|
|
|
|
|
|
|
if (avctx->frame_num == 1) {
|
|
|
|
avci->initial_format = frame->format;
|
|
|
|
switch(avctx->codec_type) {
|
|
|
|
case AVMEDIA_TYPE_VIDEO:
|
|
|
|
avci->initial_width = frame->width;
|
|
|
|
avci->initial_height = frame->height;
|
|
|
|
break;
|
|
|
|
case AVMEDIA_TYPE_AUDIO:
|
|
|
|
avci->initial_sample_rate = frame->sample_rate ? frame->sample_rate :
|
|
|
|
avctx->sample_rate;
|
|
|
|
ret = av_channel_layout_copy(&avci->initial_ch_layout, &frame->ch_layout);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (avctx->frame_num > 1) {
|
|
|
|
int changed = avci->initial_format != frame->format;
|
|
|
|
|
|
|
|
switch(avctx->codec_type) {
|
|
|
|
case AVMEDIA_TYPE_VIDEO:
|
|
|
|
changed |= avci->initial_width != frame->width ||
|
|
|
|
avci->initial_height != frame->height;
|
|
|
|
break;
|
|
|
|
case AVMEDIA_TYPE_AUDIO:
|
|
|
|
changed |= avci->initial_sample_rate != frame->sample_rate ||
|
|
|
|
avci->initial_sample_rate != avctx->sample_rate ||
|
|
|
|
av_channel_layout_compare(&avci->initial_ch_layout, &frame->ch_layout);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
|
|
|
avci->changed_frames_dropped++;
|
|
|
|
av_log(avctx, AV_LOG_INFO, "dropped changed frame #%"PRId64" pts %"PRId64
|
|
|
|
" drop count: %d \n",
|
|
|
|
avctx->frame_num, frame->pts,
|
|
|
|
avci->changed_frames_dropped);
|
|
|
|
ret = AVERROR_INPUT_CHANGED;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
|
|
av_frame_unref(frame);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_subtitle_defaults(AVSubtitle *sub)
|
|
|
|
{
|
|
|
|
memset(sub, 0, sizeof(*sub));
|
|
|
|
sub->pts = AV_NOPTS_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define UTF8_MAX_BYTES 4 /* 5 and 6 bytes sequences should not be used */
|
|
|
|
static int recode_subtitle(AVCodecContext *avctx, const AVPacket **outpkt,
|
|
|
|
const AVPacket *inpkt, AVPacket *buf_pkt)
|
|
|
|
{
|
|
|
|
#if CONFIG_ICONV
|
|
|
|
iconv_t cd = (iconv_t)-1;
|
|
|
|
int ret = 0;
|
|
|
|
char *inb, *outb;
|
|
|
|
size_t inl, outl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_PRE_DECODER || inpkt->size == 0) {
|
|
|
|
*outpkt = inpkt;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if CONFIG_ICONV
|
|
|
|
inb = inpkt->data;
|
|
|
|
inl = inpkt->size;
|
|
|
|
|
|
|
|
if (inl >= INT_MAX / UTF8_MAX_BYTES - AV_INPUT_BUFFER_PADDING_SIZE) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Subtitles packet is too big for recoding\n");
|
|
|
|
return AVERROR(ERANGE);
|
|
|
|
}
|
|
|
|
|
|
|
|
cd = iconv_open("UTF-8", avctx->sub_charenc);
|
|
|
|
av_assert0(cd != (iconv_t)-1);
|
|
|
|
|
|
|
|
ret = av_new_packet(buf_pkt, inl * UTF8_MAX_BYTES);
|
|
|
|
if (ret < 0)
|
|
|
|
goto end;
|
|
|
|
ret = av_packet_copy_props(buf_pkt, inpkt);
|
|
|
|
if (ret < 0)
|
|
|
|
goto end;
|
|
|
|
outb = buf_pkt->data;
|
|
|
|
outl = buf_pkt->size;
|
|
|
|
|
|
|
|
if (iconv(cd, &inb, &inl, &outb, &outl) == (size_t)-1 ||
|
|
|
|
iconv(cd, NULL, NULL, &outb, &outl) == (size_t)-1 ||
|
|
|
|
outl >= buf_pkt->size || inl != 0) {
|
|
|
|
ret = FFMIN(AVERROR(errno), -1);
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to recode subtitle event \"%s\" "
|
|
|
|
"from %s to UTF-8\n", inpkt->data, avctx->sub_charenc);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
buf_pkt->size -= outl;
|
|
|
|
memset(buf_pkt->data + buf_pkt->size, 0, outl);
|
|
|
|
*outpkt = buf_pkt;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
end:
|
|
|
|
if (ret < 0)
|
|
|
|
av_packet_unref(buf_pkt);
|
|
|
|
if (cd != (iconv_t)-1)
|
|
|
|
iconv_close(cd);
|
|
|
|
return ret;
|
|
|
|
#else
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "requesting subtitles recoding without iconv");
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int utf8_check(const uint8_t *str)
|
|
|
|
{
|
|
|
|
const uint8_t *byte;
|
|
|
|
uint32_t codepoint, min;
|
|
|
|
|
|
|
|
while (*str) {
|
|
|
|
byte = str;
|
|
|
|
GET_UTF8(codepoint, *(byte++), return 0;);
|
|
|
|
min = byte - str == 1 ? 0 : byte - str == 2 ? 0x80 :
|
|
|
|
1 << (5 * (byte - str) - 4);
|
|
|
|
if (codepoint < min || codepoint >= 0x110000 ||
|
|
|
|
codepoint == 0xFFFE /* BOM */ ||
|
|
|
|
codepoint >= 0xD800 && codepoint <= 0xDFFF /* surrogates */)
|
|
|
|
return 0;
|
|
|
|
str = byte;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
|
|
|
|
int *got_sub_ptr, const AVPacket *avpkt)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (!avpkt->data && avpkt->size) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n");
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
}
|
|
|
|
if (!avctx->codec)
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
if (ffcodec(avctx->codec)->cb_type != FF_CODEC_CB_TYPE_DECODE_SUB) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Codec not subtitle decoder\n");
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
*got_sub_ptr = 0;
|
|
|
|
get_subtitle_defaults(sub);
|
|
|
|
|
|
|
|
if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size) {
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
const AVPacket *pkt;
|
|
|
|
|
|
|
|
ret = recode_subtitle(avctx, &pkt, avpkt, avci->buffer_pkt);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (avctx->pkt_timebase.num && avpkt->pts != AV_NOPTS_VALUE)
|
|
|
|
sub->pts = av_rescale_q(avpkt->pts,
|
|
|
|
avctx->pkt_timebase, AV_TIME_BASE_Q);
|
|
|
|
ret = ffcodec(avctx->codec)->cb.decode_sub(avctx, sub, got_sub_ptr, pkt);
|
|
|
|
if (pkt == avci->buffer_pkt) // did we recode?
|
|
|
|
av_packet_unref(avci->buffer_pkt);
|
|
|
|
if (ret < 0) {
|
|
|
|
*got_sub_ptr = 0;
|
|
|
|
avsubtitle_free(sub);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
av_assert1(!sub->num_rects || *got_sub_ptr);
|
|
|
|
|
|
|
|
if (sub->num_rects && !sub->end_display_time && avpkt->duration &&
|
|
|
|
avctx->pkt_timebase.num) {
|
|
|
|
AVRational ms = { 1, 1000 };
|
|
|
|
sub->end_display_time = av_rescale_q(avpkt->duration,
|
|
|
|
avctx->pkt_timebase, ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB)
|
|
|
|
sub->format = 0;
|
|
|
|
else if (avctx->codec_descriptor->props & AV_CODEC_PROP_TEXT_SUB)
|
|
|
|
sub->format = 1;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < sub->num_rects; i++) {
|
|
|
|
if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_IGNORE &&
|
|
|
|
sub->rects[i]->ass && !utf8_check(sub->rects[i]->ass)) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
|
|
"Invalid UTF-8 in decoded subtitles text; "
|
|
|
|
"maybe missing -sub_charenc option\n");
|
|
|
|
avsubtitle_free(sub);
|
|
|
|
*got_sub_ptr = 0;
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*got_sub_ptr)
|
|
|
|
avctx->frame_num++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *avctx,
|
|
|
|
const enum AVPixelFormat *fmt)
|
|
|
|
{
|
|
|
|
const AVPixFmtDescriptor *desc;
|
|
|
|
const AVCodecHWConfig *config;
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
// If a device was supplied when the codec was opened, assume that the
|
|
|
|
// user wants to use it.
|
|
|
|
if (avctx->hw_device_ctx && ffcodec(avctx->codec)->hw_configs) {
|
|
|
|
AVHWDeviceContext *device_ctx =
|
|
|
|
(AVHWDeviceContext*)avctx->hw_device_ctx->data;
|
|
|
|
for (i = 0;; i++) {
|
|
|
|
config = &ffcodec(avctx->codec)->hw_configs[i]->public;
|
|
|
|
if (!config)
|
|
|
|
break;
|
|
|
|
if (!(config->methods &
|
|
|
|
AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
|
|
|
|
continue;
|
|
|
|
if (device_ctx->type != config->device_type)
|
|
|
|
continue;
|
|
|
|
for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) {
|
|
|
|
if (config->pix_fmt == fmt[n])
|
|
|
|
return fmt[n];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// No device or other setup, so we have to choose from things which
|
|
|
|
// don't any other external information.
|
|
|
|
|
|
|
|
// If the last element of the list is a software format, choose it
|
|
|
|
// (this should be best software format if any exist).
|
|
|
|
for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++);
|
|
|
|
desc = av_pix_fmt_desc_get(fmt[n - 1]);
|
|
|
|
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
|
|
|
|
return fmt[n - 1];
|
|
|
|
|
|
|
|
// Finally, traverse the list in order and choose the first entry
|
|
|
|
// with no external dependencies (if there is no hardware configuration
|
|
|
|
// information available then this just picks the first entry).
|
|
|
|
for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) {
|
|
|
|
for (i = 0;; i++) {
|
|
|
|
config = avcodec_get_hw_config(avctx->codec, i);
|
|
|
|
if (!config)
|
|
|
|
break;
|
|
|
|
if (config->pix_fmt == fmt[n])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!config) {
|
|
|
|
// No specific config available, so the decoder must be able
|
|
|
|
// to handle this format without any additional setup.
|
|
|
|
return fmt[n];
|
|
|
|
}
|
|
|
|
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_INTERNAL) {
|
|
|
|
// Usable with only internal setup.
|
|
|
|
return fmt[n];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing is usable, give up.
|
|
|
|
return AV_PIX_FMT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_get_hw_frames_ctx(AVCodecContext *avctx,
|
|
|
|
enum AVHWDeviceType dev_type)
|
|
|
|
{
|
|
|
|
AVHWDeviceContext *device_ctx;
|
|
|
|
AVHWFramesContext *frames_ctx;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!avctx->hwaccel)
|
|
|
|
return AVERROR(ENOSYS);
|
|
|
|
|
|
|
|
if (avctx->hw_frames_ctx)
|
|
|
|
return 0;
|
|
|
|
if (!avctx->hw_device_ctx) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "A hardware frames or device context is "
|
|
|
|
"required for hardware accelerated decoding.\n");
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
device_ctx = (AVHWDeviceContext *)avctx->hw_device_ctx->data;
|
|
|
|
if (device_ctx->type != dev_type) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Device type %s expected for hardware "
|
|
|
|
"decoding, but got %s.\n", av_hwdevice_get_type_name(dev_type),
|
|
|
|
av_hwdevice_get_type_name(device_ctx->type));
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = avcodec_get_hw_frames_parameters(avctx,
|
|
|
|
avctx->hw_device_ctx,
|
|
|
|
avctx->hwaccel->pix_fmt,
|
|
|
|
&avctx->hw_frames_ctx);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
|
|
|
|
|
|
|
|
|
|
|
|
if (frames_ctx->initial_pool_size) {
|
|
|
|
// We guarantee 4 base work surfaces. The function above guarantees 1
|
|
|
|
// (the absolute minimum), so add the missing count.
|
|
|
|
frames_ctx->initial_pool_size += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = av_hwframe_ctx_init(avctx->hw_frames_ctx);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_buffer_unref(&avctx->hw_frames_ctx);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int avcodec_get_hw_frames_parameters(AVCodecContext *avctx,
|
|
|
|
AVBufferRef *device_ref,
|
|
|
|
enum AVPixelFormat hw_pix_fmt,
|
|
|
|
AVBufferRef **out_frames_ref)
|
|
|
|
{
|
|
|
|
AVBufferRef *frames_ref = NULL;
|
|
|
|
const AVCodecHWConfigInternal *hw_config;
|
|
|
|
const FFHWAccel *hwa;
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
for (i = 0;; i++) {
|
|
|
|
hw_config = ffcodec(avctx->codec)->hw_configs[i];
|
|
|
|
if (!hw_config)
|
|
|
|
return AVERROR(ENOENT);
|
|
|
|
if (hw_config->public.pix_fmt == hw_pix_fmt)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
hwa = hw_config->hwaccel;
|
|
|
|
if (!hwa || !hwa->frame_params)
|
|
|
|
return AVERROR(ENOENT);
|
|
|
|
|
|
|
|
frames_ref = av_hwframe_ctx_alloc(device_ref);
|
|
|
|
if (!frames_ref)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
if (!avctx->internal->hwaccel_priv_data) {
|
|
|
|
avctx->internal->hwaccel_priv_data =
|
|
|
|
av_mallocz(hwa->priv_data_size);
|
|
|
|
if (!avctx->internal->hwaccel_priv_data) {
|
|
|
|
av_buffer_unref(&frames_ref);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = hwa->frame_params(avctx, frames_ref);
|
|
|
|
if (ret >= 0) {
|
|
|
|
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)frames_ref->data;
|
|
|
|
|
|
|
|
if (frames_ctx->initial_pool_size) {
|
|
|
|
// If the user has requested that extra output surfaces be
|
|
|
|
// available then add them here.
|
|
|
|
if (avctx->extra_hw_frames > 0)
|
|
|
|
frames_ctx->initial_pool_size += avctx->extra_hw_frames;
|
|
|
|
|
|
|
|
// If frame threading is enabled then an extra surface per thread
|
|
|
|
// is also required.
|
|
|
|
if (avctx->active_thread_type & FF_THREAD_FRAME)
|
|
|
|
frames_ctx->initial_pool_size += avctx->thread_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_frames_ref = frames_ref;
|
|
|
|
} else {
|
|
|
|
av_buffer_unref(&frames_ref);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hwaccel_init(AVCodecContext *avctx,
|
|
|
|
const FFHWAccel *hwaccel)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (hwaccel->p.capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL &&
|
|
|
|
avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "Ignoring experimental hwaccel: %s\n",
|
|
|
|
hwaccel->p.name);
|
|
|
|
return AVERROR_PATCHWELCOME;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!avctx->internal->hwaccel_priv_data && hwaccel->priv_data_size) {
|
|
|
|
avctx->internal->hwaccel_priv_data =
|
|
|
|
av_mallocz(hwaccel->priv_data_size);
|
|
|
|
if (!avctx->internal->hwaccel_priv_data)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
avctx->hwaccel = &hwaccel->p;
|
|
|
|
if (hwaccel->init) {
|
|
|
|
err = hwaccel->init(avctx);
|
|
|
|
if (err < 0) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Failed setup for format %s: "
|
|
|
|
"hwaccel initialisation returned error.\n",
|
|
|
|
av_get_pix_fmt_name(hwaccel->p.pix_fmt));
|
|
|
|
av_freep(&avctx->internal->hwaccel_priv_data);
|
|
|
|
avctx->hwaccel = NULL;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ff_hwaccel_uninit(AVCodecContext *avctx)
|
|
|
|
{
|
|
|
|
if (FF_HW_HAS_CB(avctx, uninit))
|
|
|
|
FF_HW_SIMPLE_CALL(avctx, uninit);
|
|
|
|
|
|
|
|
av_freep(&avctx->internal->hwaccel_priv_data);
|
|
|
|
|
|
|
|
avctx->hwaccel = NULL;
|
|
|
|
|
|
|
|
av_buffer_unref(&avctx->hw_frames_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
|
|
|
|
{
|
|
|
|
const AVPixFmtDescriptor *desc;
|
|
|
|
enum AVPixelFormat *choices;
|
|
|
|
enum AVPixelFormat ret, user_choice;
|
|
|
|
const AVCodecHWConfigInternal *hw_config;
|
|
|
|
const AVCodecHWConfig *config;
|
|
|
|
int i, n, err;
|
|
|
|
|
|
|
|
// Find end of list.
|
|
|
|
for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++);
|
|
|
|
// Must contain at least one entry.
|
|
|
|
av_assert0(n >= 1);
|
|
|
|
// If a software format is available, it must be the last entry.
|
|
|
|
desc = av_pix_fmt_desc_get(fmt[n - 1]);
|
|
|
|
if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
|
|
|
|
// No software format is available.
|
|
|
|
} else {
|
|
|
|
avctx->sw_pix_fmt = fmt[n - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
choices = av_memdup(fmt, (n + 1) * sizeof(*choices));
|
|
|
|
if (!choices)
|
|
|
|
return AV_PIX_FMT_NONE;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
// Remove the previous hwaccel, if there was one.
|
|
|
|
ff_hwaccel_uninit(avctx);
|
|
|
|
|
|
|
|
user_choice = avctx->get_format(avctx, choices);
|
|
|
|
if (user_choice == AV_PIX_FMT_NONE) {
|
|
|
|
// Explicitly chose nothing, give up.
|
|
|
|
ret = AV_PIX_FMT_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc = av_pix_fmt_desc_get(user_choice);
|
|
|
|
if (!desc) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid format returned by "
|
|
|
|
"get_format() callback.\n");
|
|
|
|
ret = AV_PIX_FMT_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "Format %s chosen by get_format().\n",
|
|
|
|
desc->name);
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (choices[i] == user_choice)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == n) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid return from get_format(): "
|
|
|
|
"%s not in possible list.\n", desc->name);
|
|
|
|
ret = AV_PIX_FMT_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ffcodec(avctx->codec)->hw_configs) {
|
|
|
|
for (i = 0;; i++) {
|
|
|
|
hw_config = ffcodec(avctx->codec)->hw_configs[i];
|
|
|
|
if (!hw_config)
|
|
|
|
break;
|
|
|
|
if (hw_config->public.pix_fmt == user_choice)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hw_config = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hw_config) {
|
|
|
|
// No config available, so no extra setup required.
|
|
|
|
ret = user_choice;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
config = &hw_config->public;
|
|
|
|
|
|
|
|
if (config->methods &
|
|
|
|
AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX &&
|
|
|
|
avctx->hw_frames_ctx) {
|
|
|
|
const AVHWFramesContext *frames_ctx =
|
|
|
|
(AVHWFramesContext*)avctx->hw_frames_ctx->data;
|
|
|
|
if (frames_ctx->format != user_choice) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: "
|
|
|
|
"does not match the format of the provided frames "
|
|
|
|
"context.\n", desc->name);
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
} else if (config->methods &
|
|
|
|
AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
|
|
|
|
avctx->hw_device_ctx) {
|
|
|
|
const AVHWDeviceContext *device_ctx =
|
|
|
|
(AVHWDeviceContext*)avctx->hw_device_ctx->data;
|
|
|
|
if (device_ctx->type != config->device_type) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: "
|
|
|
|
"does not match the type of the provided device "
|
|
|
|
"context.\n", desc->name);
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
} else if (config->methods &
|
|
|
|
AV_CODEC_HW_CONFIG_METHOD_INTERNAL) {
|
|
|
|
// Internal-only setup, no additional configuration.
|
|
|
|
} else if (config->methods &
|
|
|
|
AV_CODEC_HW_CONFIG_METHOD_AD_HOC) {
|
|
|
|
// Some ad-hoc configuration we can't see and can't check.
|
|
|
|
} else {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: "
|
|
|
|
"missing configuration.\n", desc->name);
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
if (hw_config->hwaccel) {
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "Format %s requires hwaccel %s "
|
|
|
|
"initialisation.\n", desc->name, hw_config->hwaccel->p.name);
|
|
|
|
err = hwaccel_init(avctx, hw_config->hwaccel);
|
|
|
|
if (err < 0)
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
ret = user_choice;
|
|
|
|
break;
|
|
|
|
|
|
|
|
try_again:
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "Format %s not usable, retrying "
|
|
|
|
"get_format() without it.\n", desc->name);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (choices[i] == user_choice)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (; i + 1 < n; i++)
|
|
|
|
choices[i] = choices[i + 1];
|
|
|
|
--n;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
ff_hwaccel_uninit(avctx);
|
|
|
|
|
|
|
|
av_freep(&choices);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
const AVPacketSideData *ff_get_coded_side_data(const AVCodecContext *avctx,
|
|
|
|
enum AVPacketSideDataType type)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < avctx->nb_coded_side_data; i++)
|
|
|
|
if (avctx->coded_side_data[i].type == type)
|
|
|
|
return &avctx->coded_side_data[i];
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int add_metadata_from_side_data(const AVPacket *avpkt, AVFrame *frame)
|
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
const uint8_t *side_metadata;
|
|
|
|
|
|
|
|
AVDictionary **frame_md = &frame->metadata;
|
|
|
|
|
|
|
|
side_metadata = av_packet_get_side_data(avpkt,
|
|
|
|
AV_PKT_DATA_STRINGS_METADATA, &size);
|
|
|
|
return av_packet_unpack_dictionary(side_metadata, size, frame_md);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_frame_props_from_pkt(const AVCodecContext *avctx,
|
|
|
|
AVFrame *frame, const AVPacket *pkt)
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
enum AVPacketSideDataType packet;
|
|
|
|
enum AVFrameSideDataType frame;
|
|
|
|
} sd[] = {
|
|
|
|
{ AV_PKT_DATA_A53_CC, AV_FRAME_DATA_A53_CC },
|
|
|
|
{ AV_PKT_DATA_AFD, AV_FRAME_DATA_AFD },
|
|
|
|
{ AV_PKT_DATA_DYNAMIC_HDR10_PLUS, AV_FRAME_DATA_DYNAMIC_HDR_PLUS },
|
|
|
|
{ AV_PKT_DATA_S12M_TIMECODE, AV_FRAME_DATA_S12M_TIMECODE },
|
|
|
|
{ AV_PKT_DATA_SKIP_SAMPLES, AV_FRAME_DATA_SKIP_SAMPLES },
|
|
|
|
};
|
|
|
|
|
|
|
|
frame->pts = pkt->pts;
|
|
|
|
frame->duration = pkt->duration;
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
#if FF_API_FRAME_PKT
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
frame->pkt_pos = pkt->pos;
|
|
|
|
frame->pkt_size = pkt->size;
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (int i = 0; ff_sd_global_map[i].packet < AV_PKT_DATA_NB; i++) {
|
|
|
|
size_t size;
|
|
|
|
const uint8_t *packet_sd = av_packet_get_side_data(pkt, ff_sd_global_map[i].packet, &size);
|
|
|
|
if (packet_sd) {
|
|
|
|
AVFrameSideData *frame_sd;
|
|
|
|
|
|
|
|
frame_sd = av_frame_new_side_data(frame, ff_sd_global_map[i].frame, size);
|
|
|
|
if (!frame_sd)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
memcpy(frame_sd->data, packet_sd, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < FF_ARRAY_ELEMS(sd); i++) {
|
|
|
|
size_t size;
|
|
|
|
uint8_t *packet_sd = av_packet_get_side_data(pkt, sd[i].packet, &size);
|
|
|
|
if (packet_sd) {
|
|
|
|
AVFrameSideData *frame_sd = av_frame_new_side_data(frame,
|
|
|
|
sd[i].frame,
|
|
|
|
size);
|
|
|
|
if (!frame_sd)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
memcpy(frame_sd->data, packet_sd, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add_metadata_from_side_data(pkt, frame);
|
|
|
|
|
|
|
|
if (pkt->flags & AV_PKT_FLAG_DISCARD) {
|
|
|
|
frame->flags |= AV_FRAME_FLAG_DISCARD;
|
|
|
|
} else {
|
|
|
|
frame->flags = (frame->flags & ~AV_FRAME_FLAG_DISCARD);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
|
|
|
|
int ret = av_buffer_replace(&frame->opaque_ref, pkt->opaque_ref);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
frame->opaque = pkt->opaque;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (int i = 0; ff_sd_global_map[i].packet < AV_PKT_DATA_NB; i++) {
|
|
|
|
const AVPacketSideData *packet_sd = ff_get_coded_side_data(avctx,
|
|
|
|
ff_sd_global_map[i].packet);
|
|
|
|
if (packet_sd) {
|
|
|
|
AVFrameSideData *frame_sd = av_frame_new_side_data(frame,
|
|
|
|
ff_sd_global_map[i].frame,
|
|
|
|
packet_sd->size);
|
|
|
|
if (!frame_sd)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
memcpy(frame_sd->data, packet_sd->data, packet_sd->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) {
|
|
|
|
const AVPacket *pkt = avctx->internal->last_pkt_props;
|
|
|
|
|
|
|
|
ret = ff_decode_frame_props_from_pkt(avctx, frame, pkt);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
#if FF_API_FRAME_PKT
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
frame->pkt_size = pkt->stream_index;
|
lavu/frame: deprecate AVFrame.pkt_{pos,size}
These fields are supposed to store information about the packet the
frame was decoded from, specifically the byte offset it was stored at
and its size.
However,
- the fields are highly ad-hoc - there is no strong reason why
specifically those (and not any other) packet properties should have a
dedicated field in AVFrame; unlike e.g. the timestamps, there is no
fundamental link between coded packet offset/size and decoded frames
- they only make sense for frames produced by decoding demuxed packets,
and even then it is not always the case that the encoded data was
stored in the file as a contiguous sequence of bytes (in order for pos
to be well-defined)
- pkt_pos was added without much explanation, apparently to allow
passthrough of this information through lavfi in order to handle byte
seeking in ffplay. That is now implemented using arbitrary user data
passthrough in AVFrame.opaque_ref.
- several filters use pkt_pos as a variable available to user-supplied
expressions, but there seems to be no established motivation for using them.
- pkt_size was added for use in ffprobe, but that too is now handled
without using this field. Additonally, the values of this field
produced by libavcodec are flawed, as described in the previous
ffprobe conversion commit.
In summary - these fields are ill-defined and insufficiently motivated,
so deprecate them.
2 years ago
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = fill_frame_props(avctx, frame);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
switch (avctx->codec->type) {
|
|
|
|
case AVMEDIA_TYPE_VIDEO:
|
|
|
|
if (frame->width && frame->height &&
|
|
|
|
av_image_check_sar(frame->width, frame->height,
|
|
|
|
frame->sample_aspect_ratio) < 0) {
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
|
|
|
|
frame->sample_aspect_ratio.num,
|
|
|
|
frame->sample_aspect_ratio.den);
|
|
|
|
frame->sample_aspect_ratio = (AVRational){ 0, 1 };
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame)
|
|
|
|
{
|
|
|
|
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
|
|
|
int i;
|
|
|
|
int num_planes = av_pix_fmt_count_planes(frame->format);
|
|
|
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
|
|
|
|
int flags = desc ? desc->flags : 0;
|
|
|
|
if (num_planes == 1 && (flags & AV_PIX_FMT_FLAG_PAL))
|
|
|
|
num_planes = 2;
|
|
|
|
for (i = 0; i < num_planes; i++) {
|
|
|
|
av_assert0(frame->data[i]);
|
|
|
|
}
|
|
|
|
// For formats without data like hwaccel allow unused pointers to be non-NULL.
|
|
|
|
for (i = num_planes; num_planes > 0 && i < FF_ARRAY_ELEMS(frame->data); i++) {
|
|
|
|
if (frame->data[i])
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Buffer returned by get_buffer2() did not zero unused plane pointers\n");
|
|
|
|
frame->data[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void decode_data_free(void *opaque, uint8_t *data)
|
|
|
|
{
|
|
|
|
FrameDecodeData *fdd = (FrameDecodeData*)data;
|
|
|
|
|
|
|
|
if (fdd->post_process_opaque_free)
|
|
|
|
fdd->post_process_opaque_free(fdd->post_process_opaque);
|
|
|
|
|
|
|
|
if (fdd->hwaccel_priv_free)
|
|
|
|
fdd->hwaccel_priv_free(fdd->hwaccel_priv);
|
|
|
|
|
|
|
|
av_freep(&fdd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_attach_decode_data(AVFrame *frame)
|
|
|
|
{
|
|
|
|
AVBufferRef *fdd_buf;
|
|
|
|
FrameDecodeData *fdd;
|
|
|
|
|
|
|
|
av_assert1(!frame->private_ref);
|
|
|
|
av_buffer_unref(&frame->private_ref);
|
|
|
|
|
|
|
|
fdd = av_mallocz(sizeof(*fdd));
|
|
|
|
if (!fdd)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
fdd_buf = av_buffer_create((uint8_t*)fdd, sizeof(*fdd), decode_data_free,
|
|
|
|
NULL, AV_BUFFER_FLAG_READONLY);
|
|
|
|
if (!fdd_buf) {
|
|
|
|
av_freep(&fdd);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
frame->private_ref = fdd_buf;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
|
|
|
|
{
|
|
|
|
const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
|
|
|
|
int override_dimensions = 1;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
av_assert0(av_codec_is_decoder(avctx->codec));
|
|
|
|
|
|
|
|
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
|
|
|
if ((unsigned)avctx->width > INT_MAX - STRIDE_ALIGN ||
|
|
|
|
(ret = av_image_check_size2(FFALIGN(avctx->width, STRIDE_ALIGN), avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) < 0 || avctx->pix_fmt<0) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "video_get_buffer: image parameters invalid\n");
|
|
|
|
ret = AVERROR(EINVAL);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame->width <= 0 || frame->height <= 0) {
|
|
|
|
frame->width = FFMAX(avctx->width, AV_CEIL_RSHIFT(avctx->coded_width, avctx->lowres));
|
|
|
|
frame->height = FFMAX(avctx->height, AV_CEIL_RSHIFT(avctx->coded_height, avctx->lowres));
|
|
|
|
override_dimensions = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame->data[0] || frame->data[1] || frame->data[2] || frame->data[3]) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "pic->data[*]!=NULL in get_buffer_internal\n");
|
|
|
|
ret = AVERROR(EINVAL);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
} else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
|
|
|
|
if (frame->nb_samples * (int64_t)avctx->ch_layout.nb_channels > avctx->max_samples) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "samples per frame %d, exceeds max_samples %"PRId64"\n", frame->nb_samples, avctx->max_samples);
|
|
|
|
ret = AVERROR(EINVAL);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = ff_decode_frame_props(avctx, frame);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (hwaccel) {
|
|
|
|
if (hwaccel->alloc_frame) {
|
|
|
|
ret = hwaccel->alloc_frame(avctx, frame);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
avctx->sw_pix_fmt = avctx->pix_fmt;
|
|
|
|
|
|
|
|
ret = avctx->get_buffer2(avctx, frame, flags);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
validate_avframe_allocation(avctx, frame);
|
|
|
|
|
|
|
|
ret = ff_attach_decode_data(frame);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
|
|
|
|
!(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) {
|
|
|
|
frame->width = avctx->width;
|
|
|
|
frame->height = avctx->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (ret < 0) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
|
|
|
|
av_frame_unref(frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int reget_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags)
|
|
|
|
{
|
|
|
|
AVFrame *tmp;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
av_assert0(avctx->codec_type == AVMEDIA_TYPE_VIDEO);
|
|
|
|
|
|
|
|
if (frame->data[0] && (frame->width != avctx->width || frame->height != avctx->height || frame->format != avctx->pix_fmt)) {
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "Picture changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s in reget buffer()\n",
|
|
|
|
frame->width, frame->height, av_get_pix_fmt_name(frame->format), avctx->width, avctx->height, av_get_pix_fmt_name(avctx->pix_fmt));
|
|
|
|
av_frame_unref(frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!frame->data[0])
|
|
|
|
return ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF);
|
|
|
|
|
|
|
|
if ((flags & FF_REGET_BUFFER_FLAG_READONLY) || av_frame_is_writable(frame))
|
|
|
|
return ff_decode_frame_props(avctx, frame);
|
|
|
|
|
|
|
|
tmp = av_frame_alloc();
|
|
|
|
if (!tmp)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
av_frame_move_ref(tmp, frame);
|
|
|
|
|
|
|
|
ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_frame_free(&tmp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
av_frame_copy(frame, tmp);
|
|
|
|
av_frame_free(&tmp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
|
|
|
|
{
|
|
|
|
int ret = reget_buffer_internal(avctx, frame, flags);
|
|
|
|
if (ret < 0)
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
avcodec/decode: Add new ProgressFrame API
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>
2 years ago
|
|
|
typedef struct ProgressInternal {
|
|
|
|
ThreadProgress progress;
|
|
|
|
struct AVFrame *f;
|
|
|
|
} ProgressInternal;
|
|
|
|
|
|
|
|
static void check_progress_consistency(const ProgressFrame *f)
|
|
|
|
{
|
|
|
|
av_assert1(!!f->f == !!f->progress);
|
|
|
|
av_assert1(!f->progress || f->progress->f == f->f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int progress_frame_get(AVCodecContext *avctx, ProgressFrame *f)
|
|
|
|
{
|
|
|
|
FFRefStructPool *pool = avctx->internal->progress_frame_pool;
|
|
|
|
|
|
|
|
av_assert1(!f->f && !f->progress);
|
|
|
|
|
|
|
|
f->progress = ff_refstruct_pool_get(pool);
|
|
|
|
if (!f->progress)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
f->f = f->progress->f;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_progress_frame_get_buffer(AVCodecContext *avctx, ProgressFrame *f, int flags)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = progress_frame_get(avctx, f);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = ff_thread_get_buffer(avctx, f->progress->f, flags);
|
|
|
|
if (ret < 0) {
|
|
|
|
f->f = NULL;
|
|
|
|
ff_refstruct_unref(&f->progress);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ff_progress_frame_ref(ProgressFrame *dst, const ProgressFrame *src)
|
|
|
|
{
|
|
|
|
av_assert1(src->progress && src->f && src->f == src->progress->f);
|
|
|
|
av_assert1(!dst->f && !dst->progress);
|
|
|
|
dst->f = src->f;
|
|
|
|
dst->progress = ff_refstruct_ref(src->progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ff_progress_frame_unref(ProgressFrame *f)
|
|
|
|
{
|
|
|
|
check_progress_consistency(f);
|
|
|
|
f->f = NULL;
|
|
|
|
ff_refstruct_unref(&f->progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ff_progress_frame_replace(ProgressFrame *dst, const ProgressFrame *src)
|
|
|
|
{
|
|
|
|
if (dst == src)
|
|
|
|
return;
|
|
|
|
ff_progress_frame_unref(dst);
|
|
|
|
check_progress_consistency(src);
|
|
|
|
if (src->f)
|
|
|
|
ff_progress_frame_ref(dst, src);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ff_progress_frame_report(ProgressFrame *f, int n)
|
|
|
|
{
|
|
|
|
ff_thread_progress_report(&f->progress->progress, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ff_progress_frame_await(const ProgressFrame *f, int n)
|
|
|
|
{
|
|
|
|
ff_thread_progress_await(&f->progress->progress, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !HAVE_THREADS
|
|
|
|
enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset)
|
|
|
|
{
|
|
|
|
return FF_THREAD_NO_FRAME_THREADING;
|
|
|
|
}
|
|
|
|
#endif /* !HAVE_THREADS */
|
|
|
|
|
avcodec/decode: Add new ProgressFrame API
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>
2 years ago
|
|
|
static av_cold int progress_frame_pool_init_cb(FFRefStructOpaque opaque, void *obj)
|
|
|
|
{
|
|
|
|
const AVCodecContext *avctx = opaque.nc;
|
|
|
|
ProgressInternal *progress = obj;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = ff_thread_progress_init(&progress->progress, avctx->active_thread_type & FF_THREAD_FRAME);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
progress->f = av_frame_alloc();
|
|
|
|
if (!progress->f)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void progress_frame_pool_reset_cb(FFRefStructOpaque unused, void *obj)
|
|
|
|
{
|
|
|
|
ProgressInternal *progress = obj;
|
|
|
|
|
|
|
|
ff_thread_progress_reset(&progress->progress);
|
|
|
|
av_frame_unref(progress->f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static av_cold void progress_frame_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj)
|
|
|
|
{
|
|
|
|
ProgressInternal *progress = obj;
|
|
|
|
|
|
|
|
ff_thread_progress_destroy(&progress->progress);
|
|
|
|
av_frame_free(&progress->f);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_preinit(AVCodecContext *avctx)
|
|
|
|
{
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
DecodeContext *dc = decode_ctx(avci);
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* if the decoder init function was already called previously,
|
|
|
|
* free the already allocated subtitle_header before overwriting it */
|
|
|
|
av_freep(&avctx->subtitle_header);
|
|
|
|
|
|
|
|
if (avctx->codec->max_lowres < avctx->lowres || avctx->lowres < 0) {
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
|
|
|
|
avctx->codec->max_lowres);
|
|
|
|
avctx->lowres = avctx->codec->max_lowres;
|
|
|
|
}
|
|
|
|
if (avctx->sub_charenc) {
|
|
|
|
if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Character encoding is only "
|
|
|
|
"supported with subtitles codecs\n");
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
} else if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB) {
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "Codec '%s' is bitmap-based, "
|
|
|
|
"subtitles character encoding will be ignored\n",
|
|
|
|
avctx->codec_descriptor->name);
|
|
|
|
avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_DO_NOTHING;
|
|
|
|
} else {
|
|
|
|
/* input character encoding is set for a text based subtitle
|
|
|
|
* codec at this point */
|
|
|
|
if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_AUTOMATIC)
|
|
|
|
avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_PRE_DECODER;
|
|
|
|
|
|
|
|
if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_PRE_DECODER) {
|
|
|
|
#if CONFIG_ICONV
|
|
|
|
iconv_t cd = iconv_open("UTF-8", avctx->sub_charenc);
|
|
|
|
if (cd == (iconv_t)-1) {
|
|
|
|
ret = AVERROR(errno);
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to open iconv context "
|
|
|
|
"with input character encoding \"%s\"\n", avctx->sub_charenc);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
iconv_close(cd);
|
|
|
|
#else
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Character encoding subtitles "
|
|
|
|
"conversion needs a libavcodec built with iconv support "
|
|
|
|
"for this codec\n");
|
|
|
|
return AVERROR(ENOSYS);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dc->pts_correction_num_faulty_pts =
|
|
|
|
dc->pts_correction_num_faulty_dts = 0;
|
|
|
|
dc->pts_correction_last_pts =
|
|
|
|
dc->pts_correction_last_dts = INT64_MIN;
|
|
|
|
|
|
|
|
if ( !CONFIG_GRAY && avctx->flags & AV_CODEC_FLAG_GRAY
|
|
|
|
&& avctx->codec_descriptor->type == AVMEDIA_TYPE_VIDEO)
|
|
|
|
av_log(avctx, AV_LOG_WARNING,
|
|
|
|
"gray decoding requested but not enabled at configuration time\n");
|
|
|
|
if (avctx->flags2 & AV_CODEC_FLAG2_EXPORT_MVS) {
|
|
|
|
avctx->export_side_data |= AV_CODEC_EXPORT_DATA_MVS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (avctx->nb_side_data_prefer_packet == 1 &&
|
|
|
|
avctx->side_data_prefer_packet[0] == -1)
|
|
|
|
dc->side_data_pref_mask = ~0ULL;
|
|
|
|
else {
|
|
|
|
for (unsigned i = 0; i < avctx->nb_side_data_prefer_packet; i++) {
|
|
|
|
int val = avctx->side_data_prefer_packet[i];
|
|
|
|
|
|
|
|
if (val < 0 || val >= AV_PKT_DATA_NB) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid side data type: %d\n", val);
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned j = 0; ff_sd_global_map[j].packet < AV_PKT_DATA_NB; j++) {
|
|
|
|
if (ff_sd_global_map[j].packet == val) {
|
|
|
|
val = ff_sd_global_map[j].frame;
|
|
|
|
|
|
|
|
// this code will need to be changed when we have more than
|
|
|
|
// 64 frame side data types
|
|
|
|
if (val >= 64) {
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Side data type too big\n");
|
|
|
|
return AVERROR_BUG;
|
|
|
|
}
|
|
|
|
|
|
|
|
dc->side_data_pref_mask |= 1ULL << val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
avci->in_pkt = av_packet_alloc();
|
|
|
|
avci->last_pkt_props = av_packet_alloc();
|
|
|
|
if (!avci->in_pkt || !avci->last_pkt_props)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
avcodec/decode: Add new ProgressFrame API
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>
2 years ago
|
|
|
if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_USES_PROGRESSFRAMES) {
|
|
|
|
avci->progress_frame_pool =
|
|
|
|
ff_refstruct_pool_alloc_ext(sizeof(ProgressInternal),
|
|
|
|
FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR,
|
|
|
|
avctx, progress_frame_pool_init_cb,
|
|
|
|
progress_frame_pool_reset_cb,
|
|
|
|
progress_frame_pool_free_entry_cb, NULL);
|
|
|
|
if (!avci->progress_frame_pool)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
ret = decode_bsfs_init(avctx);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
#if FF_API_DROPCHANGED
|
|
|
|
if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED)
|
|
|
|
av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check side data preference and clear existing side data from frame
|
|
|
|
* if needed.
|
|
|
|
*
|
|
|
|
* @retval 0 side data of this type can be added to frame
|
|
|
|
* @retval 1 side data of this type should not be added to frame
|
|
|
|
*/
|
|
|
|
static int side_data_pref(const AVCodecContext *avctx, AVFrameSideData ***sd,
|
|
|
|
int *nb_sd, enum AVFrameSideDataType type)
|
|
|
|
{
|
|
|
|
DecodeContext *dc = decode_ctx(avctx->internal);
|
|
|
|
|
|
|
|
// Note: could be skipped for `type` without corresponding packet sd
|
|
|
|
if (av_frame_side_data_get(*sd, *nb_sd, type)) {
|
|
|
|
if (dc->side_data_pref_mask & (1ULL << type))
|
|
|
|
return 1;
|
|
|
|
av_frame_side_data_remove(sd, nb_sd, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ff_frame_new_side_data(const AVCodecContext *avctx, AVFrame *frame,
|
|
|
|
enum AVFrameSideDataType type, size_t size,
|
|
|
|
AVFrameSideData **psd)
|
|
|
|
{
|
|
|
|
AVFrameSideData *sd;
|
|
|
|
|
|
|
|
if (side_data_pref(avctx, &frame->side_data, &frame->nb_side_data, type)) {
|
|
|
|
if (psd)
|
|
|
|
*psd = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sd = av_frame_new_side_data(frame, type, size);
|
|
|
|
if (psd)
|
|
|
|
*psd = sd;
|
|
|
|
|
|
|
|
return sd ? 0 : AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_frame_new_side_data_from_buf_ext(const AVCodecContext *avctx,
|
|
|
|
AVFrameSideData ***sd, int *nb_sd,
|
|
|
|
enum AVFrameSideDataType type,
|
|
|
|
AVBufferRef **buf)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (side_data_pref(avctx, sd, nb_sd, type))
|
|
|
|
goto finish;
|
|
|
|
|
|
|
|
if (!av_frame_side_data_add(sd, nb_sd, type, buf, 0))
|
|
|
|
ret = AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
finish:
|
|
|
|
av_buffer_unref(buf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx,
|
|
|
|
AVFrame *frame, enum AVFrameSideDataType type,
|
|
|
|
AVBufferRef **buf, AVFrameSideData **psd)
|
|
|
|
{
|
|
|
|
return ff_frame_new_side_data_from_buf_ext(avctx,
|
|
|
|
&frame->side_data, &frame->nb_side_data,
|
|
|
|
type, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_mastering_display_new_ext(const AVCodecContext *avctx,
|
|
|
|
AVFrameSideData ***sd, int *nb_sd,
|
|
|
|
struct AVMasteringDisplayMetadata **mdm)
|
|
|
|
{
|
|
|
|
AVBufferRef *buf;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
if (side_data_pref(avctx, sd, nb_sd, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA)) {
|
|
|
|
*mdm = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*mdm = av_mastering_display_metadata_alloc_size(&size);
|
|
|
|
if (!*mdm)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
buf = av_buffer_create((uint8_t *)*mdm, size, NULL, NULL, 0);
|
|
|
|
if (!buf) {
|
|
|
|
av_freep(mdm);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!av_frame_side_data_add(sd, nb_sd, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA,
|
|
|
|
&buf, 0)) {
|
|
|
|
*mdm = NULL;
|
|
|
|
av_buffer_unref(&buf);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_mastering_display_new(const AVCodecContext *avctx, AVFrame *frame,
|
|
|
|
AVMasteringDisplayMetadata **mdm)
|
|
|
|
{
|
|
|
|
if (side_data_pref(avctx, &frame->side_data, &frame->nb_side_data,
|
|
|
|
AV_FRAME_DATA_MASTERING_DISPLAY_METADATA)) {
|
|
|
|
*mdm = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*mdm = av_mastering_display_metadata_create_side_data(frame);
|
|
|
|
return *mdm ? 0 : AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_content_light_new_ext(const AVCodecContext *avctx,
|
|
|
|
AVFrameSideData ***sd, int *nb_sd,
|
|
|
|
AVContentLightMetadata **clm)
|
|
|
|
{
|
|
|
|
AVBufferRef *buf;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
if (side_data_pref(avctx, sd, nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL)) {
|
|
|
|
*clm = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*clm = av_content_light_metadata_alloc(&size);
|
|
|
|
if (!*clm)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
buf = av_buffer_create((uint8_t *)*clm, size, NULL, NULL, 0);
|
|
|
|
if (!buf) {
|
|
|
|
av_freep(clm);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!av_frame_side_data_add(sd, nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL,
|
|
|
|
&buf, 0)) {
|
|
|
|
*clm = NULL;
|
|
|
|
av_buffer_unref(&buf);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_decode_content_light_new(const AVCodecContext *avctx, AVFrame *frame,
|
|
|
|
AVContentLightMetadata **clm)
|
|
|
|
{
|
|
|
|
if (side_data_pref(avctx, &frame->side_data, &frame->nb_side_data,
|
|
|
|
AV_FRAME_DATA_CONTENT_LIGHT_LEVEL)) {
|
|
|
|
*clm = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*clm = av_content_light_metadata_create_side_data(frame);
|
|
|
|
return *clm ? 0 : AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_copy_palette(void *dst, const AVPacket *src, void *logctx)
|
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
const void *pal = av_packet_get_side_data(src, AV_PKT_DATA_PALETTE, &size);
|
|
|
|
|
|
|
|
if (pal && size == AVPALETTE_SIZE) {
|
|
|
|
memcpy(dst, pal, AVPALETTE_SIZE);
|
|
|
|
return 1;
|
|
|
|
} else if (pal) {
|
|
|
|
av_log(logctx, AV_LOG_ERROR,
|
|
|
|
"Palette size %"SIZE_SPECIFIER" is wrong\n", size);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void **hwaccel_picture_private)
|
|
|
|
{
|
|
|
|
const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
|
|
|
|
|
|
|
|
if (!hwaccel || !hwaccel->frame_priv_data_size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
av_assert0(!*hwaccel_picture_private);
|
|
|
|
|
|
|
|
if (hwaccel->free_frame_priv) {
|
|
|
|
AVHWFramesContext *frames_ctx;
|
|
|
|
|
|
|
|
if (!avctx->hw_frames_ctx)
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
|
|
|
|
frames_ctx = (AVHWFramesContext *) avctx->hw_frames_ctx->data;
|
|
|
|
*hwaccel_picture_private = ff_refstruct_alloc_ext(hwaccel->frame_priv_data_size, 0,
|
|
|
|
frames_ctx->device_ctx,
|
|
|
|
hwaccel->free_frame_priv);
|
|
|
|
} else {
|
|
|
|
*hwaccel_picture_private = ff_refstruct_allocz(hwaccel->frame_priv_data_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*hwaccel_picture_private)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ff_decode_flush_buffers(AVCodecContext *avctx)
|
|
|
|
{
|
|
|
|
AVCodecInternal *avci = avctx->internal;
|
|
|
|
DecodeContext *dc = decode_ctx(avci);
|
|
|
|
|
|
|
|
av_packet_unref(avci->last_pkt_props);
|
|
|
|
av_packet_unref(avci->in_pkt);
|
|
|
|
|
|
|
|
dc->pts_correction_last_pts =
|
|
|
|
dc->pts_correction_last_dts = INT64_MIN;
|
|
|
|
|
|
|
|
av_bsf_flush(avci->bsf);
|
|
|
|
|
|
|
|
dc->nb_draining_errors = 0;
|
|
|
|
dc->draining_started = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
AVCodecInternal *ff_decode_internal_alloc(void)
|
|
|
|
{
|
|
|
|
return av_mallocz(sizeof(DecodeContext));
|
|
|
|
}
|