@@ -1250,7 +1250,8 @@ const FFCodec ff_av1_decoder = {
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
FF_CODEC_CAP_INIT_CLEANUP |
- FF_CODEC_CAP_SETS_PKT_DTS,
+ FF_CODEC_CAP_SETS_PKT_DTS |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = av1_decode_flush,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles),
.p.priv_class = &av1_class,
@@ -73,6 +73,11 @@
* internal logic derive them from AVCodecInternal.last_pkt_props.
*/
#define FF_CODEC_CAP_SETS_FRAME_PROPS (1 << 8)
+/**
+ * This decoder might use FrameDecodeData. In particular, ff_get_buffer()
+ * shall allocate it.
+ */
+#define FF_CODEC_CAP_FRAME_DECODE_DATA (1 << 9)
/**
* FFCodec.codec_tags termination value
@@ -548,10 +548,10 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
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));
+ /* the only case where decode data may be set should be decoders
+ * with the FF_CODEC_CAP_FRAME_DECODE_DATA cap */
+ av_assert0(!frame->private_ref ||
+ codec->caps_internal & FF_CODEC_CAP_FRAME_DECODE_DATA);
if (frame->private_ref) {
FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
@@ -1460,9 +1460,11 @@ FF_ENABLE_DEPRECATION_WARNINGS
validate_avframe_allocation(avctx, frame);
- ret = ff_attach_decode_data(frame);
- if (ret < 0)
- goto fail;
+ if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_FRAME_DECODE_DATA) {
+ ret = ff_attach_decode_data(frame);
+ if (ret < 0)
+ goto fail;
+ }
end:
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
@@ -769,7 +769,8 @@ const FFCodec ff_h263_decoder = {
#endif
AV_CODEC_CAP_DELAY,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
- FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
+ FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = ff_mpeg_flush,
.p.max_lowres = 3,
.p.pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
@@ -791,7 +792,8 @@ const FFCodec ff_h263p_decoder = {
#endif
AV_CODEC_CAP_DELAY,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
- FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
+ FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = ff_mpeg_flush,
.p.max_lowres = 3,
.p.pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
@@ -1099,7 +1099,8 @@ const FFCodec ff_h264_decoder = {
NULL
},
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING |
- FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP,
+ FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = h264_decode_flush,
.update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context),
.update_thread_context_for_user = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context_for_user),
@@ -3890,7 +3890,8 @@ const FFCodec ff_hevc_decoder = {
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING |
- FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP,
+ FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles),
.hw_configs = (const AVCodecHWConfigInternal *const []) {
#if CONFIG_HEVC_DXVA2_HWACCEL
@@ -3027,7 +3027,8 @@ const FFCodec ff_mjpeg_decoder = {
.p.priv_class = &mjpegdec_class,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles),
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP |
- FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_SETS_PKT_DTS,
+ FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_SETS_PKT_DTS |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.hw_configs = (const AVCodecHWConfigInternal *const []) {
#if CONFIG_MJPEG_NVDEC_HWACCEL
HWACCEL_NVDEC(mjpeg),
@@ -2877,7 +2877,8 @@ const FFCodec ff_mpeg1video_decoder = {
#endif
AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
- FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
+ FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = flush,
.p.max_lowres = 3,
.update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context),
@@ -2910,7 +2911,8 @@ const FFCodec ff_mpeg2video_decoder = {
#endif
AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
- FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
+ FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = flush,
.p.max_lowres = 3,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg2_video_profiles),
@@ -3678,7 +3678,8 @@ const FFCodec ff_mpeg4_decoder = {
AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ FF_CODEC_CAP_ALLOCATE_PROGRESS |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = ff_mpeg_flush,
.p.max_lowres = 3,
.p.pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
@@ -882,7 +882,8 @@ const FFCodec ff_prores_decoder = {
.update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles),
- .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.hw_configs = (const AVCodecHWConfigInternal *const []) {
#if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL
HWACCEL_VIDEOTOOLBOX(prores),
@@ -20,6 +20,7 @@
#include "libavcodec/codec.h"
#include "libavcodec/codec_desc.h"
#include "libavcodec/codec_internal.h"
+#include "libavcodec/hwconfig.h"
#include "libavcodec/internal.h"
static const char *get_type_string(enum AVMediaType type)
@@ -146,7 +147,8 @@ int main(void){
FF_CODEC_CAP_SETS_PKT_DTS |
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
FF_CODEC_CAP_EXPORTS_CROPPING |
- FF_CODEC_CAP_SETS_FRAME_PROPS) ||
+ FF_CODEC_CAP_SETS_FRAME_PROPS |
+ FF_CODEC_CAP_FRAME_DECODE_DATA) ||
codec->capabilities & (AV_CODEC_CAP_AVOID_PROBING |
AV_CODEC_CAP_CHANNEL_CONF |
AV_CODEC_CAP_DRAW_HORIZ_BAND |
@@ -170,6 +172,17 @@ int main(void){
!(codec->capabilities & AV_CODEC_CAP_FRAME_THREADS))
ERR("Decoder %s wants allocated progress without supporting"
"frame threads\n");
+ if (!(codec2->caps_internal & FF_CODEC_CAP_FRAME_DECODE_DATA) &&
+ codec2->hw_configs) {
+ const AVCodecHWConfigInternal *const *hw_configs = codec2->hw_configs;
+ for (; *hw_configs; hw_configs++) {
+ if ((*hw_configs)->hwaccel &&
+ (strstr((*hw_configs)->hwaccel->name, "nvdec") ||
+ strstr((*hw_configs)->hwaccel->name, "videotoolbox")))
+ ERR("Decoder %s has videotoolbox or nvdec HWAccel, "
+ "yet these need FrameDecodeData.\n");
+ }
+ }
}
if (priv_data_size_wrong(codec2))
ERR_EXT("Private context of codec %s is impossibly-sized (size %d).",
@@ -1212,7 +1212,8 @@ const FFCodec ff_vc1_decoder = {
FF_CODEC_DECODE_CB(vc1_decode_frame),
.flush = ff_mpeg_flush,
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
- .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.p.pix_fmts = vc1_hwaccel_pixfmt_list_420,
.hw_configs = (const AVCodecHWConfigInternal *const []) {
#if CONFIG_VC1_DXVA2_HWACCEL
@@ -1250,7 +1251,8 @@ const FFCodec ff_wmv3_decoder = {
FF_CODEC_DECODE_CB(vc1_decode_frame),
.flush = ff_mpeg_flush,
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
- .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.p.pix_fmts = vc1_hwaccel_pixfmt_list_420,
.hw_configs = (const AVCodecHWConfigInternal *const []) {
#if CONFIG_WMV3_DXVA2_HWACCEL
@@ -2967,7 +2967,8 @@ const FFCodec ff_vp8_decoder = {
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
AV_CODEC_CAP_SLICE_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ FF_CODEC_CAP_ALLOCATE_PROGRESS |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = vp8_decode_flush,
.update_thread_context = ONLY_IF_THREADS_ENABLED(vp8_decode_update_thread_context),
.hw_configs = (const AVCodecHWConfigInternal *const []) {
@@ -1878,7 +1878,8 @@ const FFCodec ff_vp9_decoder = {
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP |
FF_CODEC_CAP_SLICE_THREAD_HAS_MF |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ FF_CODEC_CAP_ALLOCATE_PROGRESS |
+ FF_CODEC_CAP_FRAME_DECODE_DATA,
.flush = vp9_decode_flush,
.update_thread_context = ONLY_IF_THREADS_ENABLED(vp9_decode_update_thread_context),
.p.profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles),
Currently, every call to ff_get_buffer() allocates FrameDecodeData, although only very few decoders (those that might use nvdec or videotoolbox hardware acceleration) actually need it. This commit addresses this by adding an internal codec cap to ensure that FrameDecodeData is only allocated for codecs that might need it (i.e. for which there is a hardware acceleration that might actually need it). Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- 1. It seems that this has even been allocated for some encoders before c954cf1e1b766a0d1992d5be0a8be0055a8e1a6a. 2. Given that the videotoolbox hwaccels call ff_attach_decode_data() themselves, they actually don't need the generic part of ff_get_buffer() to allocate it for them; in particular, one could avoid adding the flag to the prores decoder. I can modify the patch in this way if desired (it would also necessitate modifying the assert in decode_receive_frame_internal()). 3. Unfortunately, I don't have hardware to actually test nvdec or videotoolbox, so only the "it works if allocating it is certainly unnecessary" has been tested. It would be nice if someone could also test the other part. 4. One could of course set these flags only if the relevant hwaccels are enabled at compile-time. 5. Unfortunately, it seems to be too late to call ff_attach_decode_data() from ff_nvdec_start_frame(), as it is called after ff_thread_finish_setup() might have been called, so modifying the frame would be a race. 6. Maybe the following would also work: Add a caps_internal to AVHWAccel and only allocate FrameDecodeData if the hardware acceleration currently in use needs it (as given by this new cap). It should work (hopefully) and would be cleaner. libavcodec/av1dec.c | 3 ++- libavcodec/codec_internal.h | 5 +++++ libavcodec/decode.c | 16 +++++++++------- libavcodec/h263dec.c | 6 ++++-- libavcodec/h264dec.c | 3 ++- libavcodec/hevcdec.c | 3 ++- libavcodec/mjpegdec.c | 3 ++- libavcodec/mpeg12dec.c | 6 ++++-- libavcodec/mpeg4videodec.c | 3 ++- libavcodec/proresdec2.c | 3 ++- libavcodec/tests/avcodec.c | 15 ++++++++++++++- libavcodec/vc1dec.c | 6 ++++-- libavcodec/vp8.c | 3 ++- libavcodec/vp9.c | 3 ++- 14 files changed, 56 insertions(+), 22 deletions(-)