From 68a8eca752396b5b574014e5b48842ced45af47c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 11 Jan 2024 19:24:58 +0100 Subject: [PATCH] lavc: add a decoder option for configuring side data preference This and the following commits fix #10857 --- doc/APIchanges | 3 +++ libavcodec/avcodec.h | 34 ++++++++++++++++++++++++++++++++++ libavcodec/decode.c | 35 +++++++++++++++++++++++++++++++++++ libavcodec/options_table.h | 12 ++++++++++++ libavcodec/version.h | 2 +- 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index 650c135b38..cf58c8c5f0 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07 API changes, most recent first: +2024-03-08 - xxxxxxxxxx - lavc 61.1.100 - avcodec.h + Add AVCodecContext.[nb_]side_data_prefer_packet. + 2024-03-08 - xxxxxxxxxx - lavu 59.1.100 - opt.h Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef. diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index fb0612ed26..21fc74707f 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -2028,6 +2028,40 @@ typedef struct AVCodecContext { * an error. */ int64_t frame_num; + + /** + * Decoding only. May be set by the caller before avcodec_open2() to an + * av_malloc()'ed array (or via AVOptions). Owned and freed by the decoder + * afterwards. + * + * Side data attached to decoded frames may come from several sources: + * 1. coded_side_data, which the decoder will for certain types translate + * from packet-type to frame-type and attach to frames; + * 2. side data attached to an AVPacket sent for decoding (same + * considerations as above); + * 3. extracted from the coded bytestream. + * The first two cases are supplied by the caller and typically come from a + * container. + * + * This array configures decoder behaviour in cases when side data of the + * same type is present both in the coded bytestream and in the + * user-supplied side data (items 1. and 2. above). In all cases, at most + * one instance of each side data type will be attached to output frames. By + * default it will be the bytestream side data. Adding an + * AVPacketSideDataType value to this array will flip the preference for + * this type, thus making the decoder prefer user-supplied side data over + * bytestream. In case side data of the same type is present both in + * coded_data and attacked to a packet, the packet instance always has + * priority. + * + * The array may also contain a single -1, in which case the preference is + * switched for all side data types. + */ + int *side_data_prefer_packet; + /** + * Number of entries in side_data_prefer_packet. + */ + unsigned nb_side_data_prefer_packet; } AVCodecContext; /** diff --git a/libavcodec/decode.c b/libavcodec/decode.c index f0260cfa07..0f3eb79b89 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -65,6 +65,12 @@ typedef struct DecodeContext { 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) @@ -1739,6 +1745,35 @@ int ff_decode_preinit(AVCodecContext *avctx) 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; j < FF_ARRAY_ELEMS(sd_global_map); j++) { + if (sd_global_map[j].packet == val) { + val = 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) diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 7155a335c1..7a2ef3474e 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -42,6 +42,8 @@ #define D AV_OPT_FLAG_DECODING_PARAM #define CC AV_OPT_FLAG_CHILD_CONSTS +#define AR AV_OPT_TYPE_FLAG_ARRAY + #define AV_CODEC_DEFAULT_BITRATE 200*1000 static const AVOption avcodec_options[] = { @@ -395,6 +397,16 @@ static const AVOption avcodec_options[] = { {"unsafe_output", "allow potentially unsafe hwaccel frame output that might require special care to process successfully", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_UNSAFE_OUTPUT }, INT_MIN, INT_MAX, V | D, .unit = "hwaccel_flags"}, {"extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, V|D }, {"discard_damaged_percentage", "Percentage of damaged samples to discard a frame", OFFSET(discard_damaged_percentage), AV_OPT_TYPE_INT, {.i64 = 95 }, 0, 100, V|D }, +{"side_data_prefer_packet", "Comma-separated list of side data types for which user-supplied (container) data is preferred over coded bytestream", + OFFSET(side_data_prefer_packet), AV_OPT_TYPE_INT | AR, .min = -1, .max = INT_MAX, .flags = V|A|S|D, .unit = "side_data_pkt" }, + {"replaygain", .default_val.i64 = AV_PKT_DATA_REPLAYGAIN, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"displaymatrix", .default_val.i64 = AV_PKT_DATA_DISPLAYMATRIX, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"spherical", .default_val.i64 = AV_PKT_DATA_SPHERICAL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"stereo3d", .default_val.i64 = AV_PKT_DATA_STEREO3D, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"audio_service_type", .default_val.i64 = AV_PKT_DATA_AUDIO_SERVICE_TYPE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"mastering_display_metadata", .default_val.i64 = AV_PKT_DATA_MASTERING_DISPLAY_METADATA, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"content_light_level", .default_val.i64 = AV_PKT_DATA_CONTENT_LIGHT_LEVEL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, + {"icc_profile", .default_val.i64 = AV_PKT_DATA_ICC_PROFILE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" }, {NULL}, }; diff --git a/libavcodec/version.h b/libavcodec/version.h index 8c3d476003..5957009457 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 0 +#define LIBAVCODEC_VERSION_MINOR 1 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \