From 8e5841cd7994b1b925c677d906cd4e8130651115 Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 21 Oct 2024 11:01:00 +0800 Subject: [PATCH 1/6] avformat: validate dovi config in muxers --- ...ovi-sidedata-to-hlsenc-and-mpegtsenc.patch | 57 ++++- ...0078-validate-dovi-config-for-muxers.patch | 204 ++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 debian/patches/0078-validate-dovi-config-for-muxers.patch diff --git a/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch b/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch index d4b7795260c..66caf41f7dc 100644 --- a/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch +++ b/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch @@ -36,7 +36,7 @@ Index: FFmpeg/libavformat/movenc.c =================================================================== --- FFmpeg.orig/libavformat/movenc.c +++ FFmpeg/libavformat/movenc.c -@@ -8124,6 +8124,7 @@ static const AVCodecTag codec_mp4_tags[] +@@ -8128,6 +8128,7 @@ static const AVCodecTag codec_mp4_tags[] { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') }, @@ -44,7 +44,7 @@ Index: FFmpeg/libavformat/movenc.c { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') }, { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') }, { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') }, -@@ -8137,6 +8138,7 @@ static const AVCodecTag codec_mp4_tags[] +@@ -8141,6 +8142,7 @@ static const AVCodecTag codec_mp4_tags[] { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') }, { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') }, { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') }, @@ -117,7 +117,7 @@ Index: FFmpeg/libavformat/mpegtsenc.c static int get_dvb_stream_type(AVFormatContext *s, AVStream *st) { MpegTSWrite *ts = s->priv_data; -@@ -803,7 +850,16 @@ static int mpegts_write_pmt(AVFormatCont +@@ -803,7 +850,65 @@ static int mpegts_write_pmt(AVFormatCont } else if (stream_type == STREAM_TYPE_VIDEO_VC1) { put_registration_descriptor(&q, MKTAG('V', 'C', '-', '1')); } else if (stream_type == STREAM_TYPE_VIDEO_HEVC && s->strict_std_compliance <= FF_COMPLIANCE_NORMAL) { @@ -125,8 +125,57 @@ Index: FFmpeg/libavformat/mpegtsenc.c + const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data, + st->codecpar->nb_coded_side_data, AV_PKT_DATA_DOVI_CONF); + const AVDOVIDecoderConfigurationRecord *dovi = sd ? (const AVDOVIDecoderConfigurationRecord *)sd->data : NULL; ++ int is_dovi_config_valid = dovi != NULL; + -+ if (dovi && dovi->bl_present_flag && s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { ++ if (dovi) { ++ switch (dovi->dv_level) { ++ case 4: ++ case 5: ++ case 7: ++ case 8: ++ if (st->codecpar->codec_id != AV_CODEC_ID_HEVC) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ default: ++ is_dovi_config_valid = 0; ++ break; ++ } ++ ++ switch (dovi->dv_bl_signal_compatibility_id) { ++ case 1: ++ case 6: ++ if (st->codecpar->color_trc != AVCOL_TRC_SMPTE2084 || ++ st->codecpar->color_primaries != AVCOL_PRI_BT2020 || ++ st->codecpar->color_space != AVCOL_SPC_BT2020_NCL || ++ st->codecpar->color_range != AVCOL_RANGE_MPEG || ++ st->codecpar->format != AV_PIX_FMT_YUV420P10) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 2: ++ // Don't check range or color info for SDR base layer as a lot of them will set to unspecified ++ // And a lot of players assumes unspecified as BT709 in tv range ++ if (st->codecpar->format != AV_PIX_FMT_YUV420P) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 4: ++ if (st->codecpar->color_trc != AVCOL_TRC_ARIB_STD_B67 || ++ st->codecpar->color_primaries != AVCOL_PRI_BT2020 || ++ st->codecpar->color_space != AVCOL_SPC_BT2020_NCL || ++ st->codecpar->color_range != AVCOL_RANGE_MPEG || ++ st->codecpar->format != AV_PIX_FMT_YUV420P10) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ default: ++ // others are reserved value, don't check ++ break; ++ } ++ } ++ ++ if (dovi && is_dovi_config_valid && dovi->bl_present_flag && s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { + if (put_dovi_descriptor(s, &q, dovi) < 0) + break; + } else { diff --git a/debian/patches/0078-validate-dovi-config-for-muxers.patch b/debian/patches/0078-validate-dovi-config-for-muxers.patch new file mode 100644 index 00000000000..e136ede3863 --- /dev/null +++ b/debian/patches/0078-validate-dovi-config-for-muxers.patch @@ -0,0 +1,204 @@ +Index: FFmpeg/libavformat/movenc.c +=================================================================== +--- FFmpeg.orig/libavformat/movenc.c ++++ FFmpeg/libavformat/movenc.c +@@ -2538,8 +2538,79 @@ static int mov_write_video_tag(AVFormatC + mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); + if (spherical_mapping) + mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); +- if (dovi) +- mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data); ++ if (dovi) { ++ AVDOVIDecoderConfigurationRecord* dovi_config = (AVDOVIDecoderConfigurationRecord *) dovi->data; ++ int is_dovi_config_valid = 1; ++ switch (dovi_config->dv_level) { ++ case 4: ++ case 5: ++ case 7: ++ case 8: ++ case 20: ++ if (track->par->codec_id != AV_CODEC_ID_HEVC) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 9: ++ if (track->par->codec_id != AV_CODEC_ID_H264) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 10: ++ if (track->par->codec_id != AV_CODEC_ID_AV1) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ default: ++ is_dovi_config_valid = 0; ++ break; ++ } ++ ++ switch (dovi_config->dv_bl_signal_compatibility_id) { ++ case 0: ++ if (track->par->color_range != AVCOL_RANGE_JPEG || ++ track->par->format != AV_PIX_FMT_YUV420P10 || ++ !(track->tag == MKTAG('d', 'v', 'h', '1') || ++ track->tag == MKTAG('d', 'v', 'h', 'e') || ++ track->tag == MKTAG('d', 'a', 'v', '1'))) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 1: ++ case 6: ++ if (track->par->color_trc != AVCOL_TRC_SMPTE2084 || ++ track->par->color_primaries != AVCOL_PRI_BT2020 || ++ track->par->color_space != AVCOL_SPC_BT2020_NCL || ++ track->par->color_range != AVCOL_RANGE_MPEG || ++ track->par->format != AV_PIX_FMT_YUV420P10) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 2: ++ // Don't check range or color info for SDR base layer as a lot of them will set to unspecified ++ // And a lot of players assumes unspecified as BT709 in tv range ++ if (track->par->format != AV_PIX_FMT_YUV420P) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 4: ++ if (track->par->color_trc != AVCOL_TRC_ARIB_STD_B67 || ++ track->par->color_primaries != AVCOL_PRI_BT2020 || ++ track->par->color_space != AVCOL_SPC_BT2020_NCL || ++ track->par->color_range != AVCOL_RANGE_MPEG || ++ track->par->format != AV_PIX_FMT_YUV420P10) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ default: ++ // others are reserved value, don't check ++ break; ++ } ++ ++ if (is_dovi_config_valid) { ++ mov_write_dvcc_dvvc_tag(s, pb, dovi_config); ++ } ++ } + } + + if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) { +Index: FFmpeg/libavformat/matroskaenc.c +=================================================================== +--- FFmpeg.orig/libavformat/matroskaenc.c ++++ FFmpeg/libavformat/matroskaenc.c +@@ -1719,28 +1719,96 @@ static void mkv_write_blockadditionmappi + + dovi = (const AVDOVIDecoderConfigurationRecord *)sd->data; + if (dovi->dv_profile <= 10) { +- ebml_master mapping; +- uint8_t buf[ISOM_DVCC_DVVC_SIZE]; +- uint32_t type; +- +- uint64_t expected_size = (2 + 1 + (sizeof(DVCC_DVVC_BLOCK_TYPE_NAME) - 1)) +- + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); +- +- if (dovi->dv_profile > 7) { +- type = MATROSKA_BLOCK_ADD_ID_TYPE_DVVC; +- } else { +- type = MATROSKA_BLOCK_ADD_ID_TYPE_DVCC; ++ int is_dovi_config_valid = 1; ++ switch (dovi->dv_level) { ++ case 4: ++ case 5: ++ case 7: ++ case 8: ++ case 20: ++ if (par->codec_id != AV_CODEC_ID_HEVC) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 9: ++ if (par->codec_id != AV_CODEC_ID_H264) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 10: ++ if (par->codec_id != AV_CODEC_ID_AV1) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ default: ++ is_dovi_config_valid = 0; ++ break; + } + +- ff_isom_put_dvcc_dvvc(s, buf, dovi); ++ switch (dovi->dv_bl_signal_compatibility_id) { ++ case 0: ++ if (par->color_range != AVCOL_RANGE_JPEG || ++ par->format != AV_PIX_FMT_YUV420P10 || ++ !(par->codec_tag == MKTAG('d', 'v', 'h', '1') || ++ par->codec_tag == MKTAG('d', 'v', 'h', 'e') || ++ par->codec_tag == MKTAG('d', 'a', 'v', '1'))) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 1: ++ case 6: ++ if (par->color_trc != AVCOL_TRC_SMPTE2084 || ++ par->color_primaries != AVCOL_PRI_BT2020 || ++ par->color_space != AVCOL_SPC_BT2020_NCL || ++ par->color_range != AVCOL_RANGE_MPEG || ++ par->format != AV_PIX_FMT_YUV420P10) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 2: ++ // Don't check range or color info for SDR base layer as a lot of them will set to unspecified ++ // And a lot of players assumes unspecified as BT709 in tv range ++ if (par->format != AV_PIX_FMT_YUV420P) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ case 4: ++ if (par->color_trc != AVCOL_TRC_ARIB_STD_B67 || ++ par->color_primaries != AVCOL_PRI_BT2020 || ++ par->color_space != AVCOL_SPC_BT2020_NCL || ++ par->color_range != AVCOL_RANGE_MPEG || ++ par->format != AV_PIX_FMT_YUV420P10) { ++ is_dovi_config_valid = 0; ++ } ++ break; ++ default: ++ // others are reserved value, don't check ++ break; ++ } ++ if (is_dovi_config_valid) { ++ ebml_master mapping; ++ uint8_t buf[ISOM_DVCC_DVVC_SIZE]; ++ uint32_t type; ++ ++ uint64_t expected_size = (2 + 1 + (sizeof(DVCC_DVVC_BLOCK_TYPE_NAME) - 1)) ++ + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); ++ ++ if (dovi->dv_profile > 7) { ++ type = MATROSKA_BLOCK_ADD_ID_TYPE_DVVC; ++ } else { ++ type = MATROSKA_BLOCK_ADD_ID_TYPE_DVCC; ++ } + +- mapping = start_ebml_master(pb, MATROSKA_ID_TRACKBLKADDMAPPING, expected_size); ++ ff_isom_put_dvcc_dvvc(s, buf, dovi); + +- put_ebml_string(pb, MATROSKA_ID_BLKADDIDNAME, DVCC_DVVC_BLOCK_TYPE_NAME); +- put_ebml_uint(pb, MATROSKA_ID_BLKADDIDTYPE, type); +- put_ebml_binary(pb, MATROSKA_ID_BLKADDIDEXTRADATA, buf, sizeof(buf)); ++ mapping = start_ebml_master(pb, MATROSKA_ID_TRACKBLKADDMAPPING, expected_size); + +- end_ebml_master(pb, mapping); ++ put_ebml_string(pb, MATROSKA_ID_BLKADDIDNAME, DVCC_DVVC_BLOCK_TYPE_NAME); ++ put_ebml_uint(pb, MATROSKA_ID_BLKADDIDTYPE, type); ++ put_ebml_binary(pb, MATROSKA_ID_BLKADDIDEXTRADATA, buf, sizeof(buf)); ++ ++ end_ebml_master(pb, mapping); ++ } + } + #endif + } diff --git a/debian/patches/series b/debian/patches/series index 8a9bb4501a4..3feb7ac5054 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -75,3 +75,4 @@ 0075-allow-vpl-qsv-to-init-with-the-legacy-msdk-path.patch 0076-alway-set-videotoolboxenc-pixel-buffer-info.patch 0077-add-remove-dovi-hdr10plus-bsf.patch +0078-validate-dovi-config-for-muxers.patch From 1920af5630747b198c69e77e427ddaf05482b2e5 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 22 Oct 2024 18:20:37 +0800 Subject: [PATCH 2/6] avformat: make dovi config check public --- ...ovi-sidedata-to-hlsenc-and-mpegtsenc.patch | 205 +++++++++++++----- ...0078-validate-dovi-config-for-muxers.patch | 204 ----------------- debian/patches/series | 1 - 3 files changed, 149 insertions(+), 261 deletions(-) delete mode 100644 debian/patches/0078-validate-dovi-config-for-muxers.patch diff --git a/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch b/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch index 66caf41f7dc..2bcad44d165 100644 --- a/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch +++ b/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch @@ -8,13 +8,13 @@ Index: FFmpeg/libavformat/hlsenc.c int remaining_options; - int i, ret; + int i, j, ret; - + ret = avformat_alloc_output_context2(&vs->avf, vs->oformat, NULL, NULL); if (ret < 0) @@ -896,6 +896,20 @@ static int hls_mux_init(AVFormatContext st->codecpar->codec_tag = 0; } - + + // copy side data + for (j = 0; j < vs->streams[i]->codecpar->nb_coded_side_data; j++) { + const AVPacketSideData *sd_src = &vs->streams[i]->codecpar->coded_side_data[j]; @@ -64,10 +64,18 @@ Index: FFmpeg/libavformat/mpegtsenc.c #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" -@@ -350,6 +351,52 @@ static void put_registration_descriptor( +@@ -40,6 +41,7 @@ + #include "internal.h" + #include "mpegts.h" + #include "mux.h" ++#include "dovi_isom.h" + + #define PCR_TIME_BASE 27000000 + +@@ -350,6 +352,52 @@ static void put_registration_descriptor( *q_ptr = q; } - + +static int put_dovi_descriptor(AVFormatContext *s, uint8_t **q_ptr, + const AVDOVIDecoderConfigurationRecord *dovi) +{ @@ -117,7 +125,7 @@ Index: FFmpeg/libavformat/mpegtsenc.c static int get_dvb_stream_type(AVFormatContext *s, AVStream *st) { MpegTSWrite *ts = s->priv_data; -@@ -803,7 +850,65 @@ static int mpegts_write_pmt(AVFormatCont +@@ -803,7 +851,18 @@ static int mpegts_write_pmt(AVFormatCont } else if (stream_type == STREAM_TYPE_VIDEO_VC1) { put_registration_descriptor(&q, MKTAG('V', 'C', '-', '1')); } else if (stream_type == STREAM_TYPE_VIDEO_HEVC && s->strict_std_compliance <= FF_COMPLIANCE_NORMAL) { @@ -125,57 +133,10 @@ Index: FFmpeg/libavformat/mpegtsenc.c + const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data, + st->codecpar->nb_coded_side_data, AV_PKT_DATA_DOVI_CONF); + const AVDOVIDecoderConfigurationRecord *dovi = sd ? (const AVDOVIDecoderConfigurationRecord *)sd->data : NULL; -+ int is_dovi_config_valid = dovi != NULL; -+ -+ if (dovi) { -+ switch (dovi->dv_level) { -+ case 4: -+ case 5: -+ case 7: -+ case 8: -+ if (st->codecpar->codec_id != AV_CODEC_ID_HEVC) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ default: -+ is_dovi_config_valid = 0; -+ break; -+ } -+ -+ switch (dovi->dv_bl_signal_compatibility_id) { -+ case 1: -+ case 6: -+ if (st->codecpar->color_trc != AVCOL_TRC_SMPTE2084 || -+ st->codecpar->color_primaries != AVCOL_PRI_BT2020 || -+ st->codecpar->color_space != AVCOL_SPC_BT2020_NCL || -+ st->codecpar->color_range != AVCOL_RANGE_MPEG || -+ st->codecpar->format != AV_PIX_FMT_YUV420P10) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 2: -+ // Don't check range or color info for SDR base layer as a lot of them will set to unspecified -+ // And a lot of players assumes unspecified as BT709 in tv range -+ if (st->codecpar->format != AV_PIX_FMT_YUV420P) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 4: -+ if (st->codecpar->color_trc != AVCOL_TRC_ARIB_STD_B67 || -+ st->codecpar->color_primaries != AVCOL_PRI_BT2020 || -+ st->codecpar->color_space != AVCOL_SPC_BT2020_NCL || -+ st->codecpar->color_range != AVCOL_RANGE_MPEG || -+ st->codecpar->format != AV_PIX_FMT_YUV420P10) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ default: -+ // others are reserved value, don't check -+ break; -+ } -+ } -+ -+ if (dovi && is_dovi_config_valid && dovi->bl_present_flag && s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { ++ if (dovi && ++ !ff_isom_validate_dovi_config(dovi, st->codecpar, MKTAG('d', 'v', 'h', '1')) && // always assume tag is valid ++ dovi->bl_present_flag && ++ s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { + if (put_dovi_descriptor(s, &q, dovi) < 0) + break; + } else { @@ -184,3 +145,135 @@ Index: FFmpeg/libavformat/mpegtsenc.c } else if (stream_type == STREAM_TYPE_VIDEO_CAVS || stream_type == STREAM_TYPE_VIDEO_AVS2 || stream_type == STREAM_TYPE_VIDEO_AVS3) { put_registration_descriptor(&q, MKTAG('A', 'V', 'S', 'V')); +Index: FFmpeg/libavformat/dovi_isom.c +=================================================================== +--- FFmpeg.orig/libavformat/dovi_isom.c ++++ FFmpeg/libavformat/dovi_isom.c +@@ -116,3 +116,74 @@ void ff_isom_put_dvcc_dvvc(void *logctx, + dovi->bl_present_flag, + dovi->dv_bl_signal_compatibility_id); + } ++ ++int ff_isom_validate_dovi_config(const AVDOVIDecoderConfigurationRecord *dovi, ++ const AVCodecParameters *codec_par, int codec_tag) ++{ ++ if (!dovi || !codec_par) ++ return AVERROR(ENOMEM); ++ ++ switch (dovi->dv_profile) { ++ case 4: ++ case 5: ++ case 7: ++ case 8: ++ case 20: ++ if (codec_par->codec_id != AV_CODEC_ID_HEVC) ++ return AVERROR(EINVAL); ++ break; ++ case 9: ++ if (codec_par->codec_id != AV_CODEC_ID_H264) ++ return AVERROR(EINVAL); ++ break; ++ case 10: ++ if (codec_par->codec_id != AV_CODEC_ID_AV1) ++ return AVERROR(EINVAL); ++ break; ++ default: ++ return AVERROR(EINVAL); ++ } ++ ++ switch (dovi->dv_bl_signal_compatibility_id) { ++ case 0: ++ // Although the IPT-PQ-C2 Dolby Vision uses is always full range, some videos tag that wrong in the container ++ // To allow stream copy for such videos, don't check for the color range ++ if (codec_par->format != AV_PIX_FMT_YUV420P10 || ++ (codec_tag && !(codec_tag == MKTAG('d', 'v', 'h', '1') || ++ codec_tag == MKTAG('d', 'v', 'h', 'e') || ++ codec_tag == MKTAG('d', 'a', 'v', '1')))) { ++ return AVERROR(EINVAL); ++ } ++ break; ++ case 1: // HDR10 ++ case 6: ++ if (codec_par->color_trc != AVCOL_TRC_SMPTE2084 || ++ codec_par->color_primaries != AVCOL_PRI_BT2020 || ++ codec_par->color_space != AVCOL_SPC_BT2020_NCL || ++ codec_par->color_range != AVCOL_RANGE_MPEG || ++ codec_par->format != AV_PIX_FMT_YUV420P10) { ++ return AVERROR(EINVAL); ++ } ++ break; ++ case 2: // SDR ++ // Don't check range or color info for SDR base layer as a lot of them will set to unspecified ++ // And a lot of players assumes unspecified as BT709 in tv range ++ if (codec_par->format != AV_PIX_FMT_YUV420P) ++ return AVERROR(EINVAL); ++ break; ++ case 4: // HLG ++ if (codec_par->color_trc != AVCOL_TRC_ARIB_STD_B67 || ++ codec_par->color_primaries != AVCOL_PRI_BT2020 || ++ codec_par->color_space != AVCOL_SPC_BT2020_NCL || ++ codec_par->color_range != AVCOL_RANGE_MPEG || ++ codec_par->format != AV_PIX_FMT_YUV420P10) { ++ return AVERROR(EINVAL); ++ } ++ break; ++ default: ++ // others are reserved value, don't check ++ break; ++ } ++ ++ return 0; ++} +Index: FFmpeg/libavformat/dovi_isom.h +=================================================================== +--- FFmpeg.orig/libavformat/dovi_isom.h ++++ FFmpeg/libavformat/dovi_isom.h +@@ -33,4 +33,12 @@ int ff_isom_parse_dvcc_dvvc(void *logctx + void ff_isom_put_dvcc_dvvc(void *logctx, uint8_t out[ISOM_DVCC_DVVC_SIZE], + const AVDOVIDecoderConfigurationRecord *dovi); + ++/* ++ * Check if the AVDOVIDecoderConfigurationRecord is spec-compliant for current codec parameters ++ * Used by muxers to determine if the configuration record should be copied into the container ++ * Returns 0 when the AVDOVIDecoderConfigurationRecord is safe to copy, otherwise return an AVERROR ++ */ ++int ff_isom_validate_dovi_config(const AVDOVIDecoderConfigurationRecord *dovi, ++ const AVCodecParameters *codec_par, int codec_tag); ++ + #endif /* AVFORMAT_DOVI_ISOM_H */ + Index: FFmpeg/libavformat/movenc.c +=================================================================== +--- FFmpeg.orig/libavformat/movenc.c ++++ FFmpeg/libavformat/movenc.c +@@ -2538,8 +2538,9 @@ static int mov_write_video_tag(AVFormatC + mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); + if (spherical_mapping) + mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); +- if (dovi) ++ if (dovi && !ff_isom_validate_dovi_config((AVDOVIDecoderConfigurationRecord *)dovi->data, track->par, track->tag)) { + mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data); ++ } + } + + if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) { +Index: FFmpeg/libavformat/matroskaenc.c +=================================================================== +--- FFmpeg.orig/libavformat/matroskaenc.c ++++ FFmpeg/libavformat/matroskaenc.c +@@ -1718,13 +1718,14 @@ static void mkv_write_blockadditionmappi + return; + + dovi = (const AVDOVIDecoderConfigurationRecord *)sd->data; +- if (dovi->dv_profile <= 10) { ++ if (dovi->dv_profile <= 10 && ++ !ff_isom_validate_dovi_config(dovi, par, (int)par->codec_tag)) { + ebml_master mapping; + uint8_t buf[ISOM_DVCC_DVVC_SIZE]; + uint32_t type; + + uint64_t expected_size = (2 + 1 + (sizeof(DVCC_DVVC_BLOCK_TYPE_NAME) - 1)) +- + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); ++ + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); + + if (dovi->dv_profile > 7) { + type = MATROSKA_BLOCK_ADD_ID_TYPE_DVVC; diff --git a/debian/patches/0078-validate-dovi-config-for-muxers.patch b/debian/patches/0078-validate-dovi-config-for-muxers.patch deleted file mode 100644 index e136ede3863..00000000000 --- a/debian/patches/0078-validate-dovi-config-for-muxers.patch +++ /dev/null @@ -1,204 +0,0 @@ -Index: FFmpeg/libavformat/movenc.c -=================================================================== ---- FFmpeg.orig/libavformat/movenc.c -+++ FFmpeg/libavformat/movenc.c -@@ -2538,8 +2538,79 @@ static int mov_write_video_tag(AVFormatC - mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); - if (spherical_mapping) - mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); -- if (dovi) -- mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data); -+ if (dovi) { -+ AVDOVIDecoderConfigurationRecord* dovi_config = (AVDOVIDecoderConfigurationRecord *) dovi->data; -+ int is_dovi_config_valid = 1; -+ switch (dovi_config->dv_level) { -+ case 4: -+ case 5: -+ case 7: -+ case 8: -+ case 20: -+ if (track->par->codec_id != AV_CODEC_ID_HEVC) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 9: -+ if (track->par->codec_id != AV_CODEC_ID_H264) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 10: -+ if (track->par->codec_id != AV_CODEC_ID_AV1) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ default: -+ is_dovi_config_valid = 0; -+ break; -+ } -+ -+ switch (dovi_config->dv_bl_signal_compatibility_id) { -+ case 0: -+ if (track->par->color_range != AVCOL_RANGE_JPEG || -+ track->par->format != AV_PIX_FMT_YUV420P10 || -+ !(track->tag == MKTAG('d', 'v', 'h', '1') || -+ track->tag == MKTAG('d', 'v', 'h', 'e') || -+ track->tag == MKTAG('d', 'a', 'v', '1'))) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 1: -+ case 6: -+ if (track->par->color_trc != AVCOL_TRC_SMPTE2084 || -+ track->par->color_primaries != AVCOL_PRI_BT2020 || -+ track->par->color_space != AVCOL_SPC_BT2020_NCL || -+ track->par->color_range != AVCOL_RANGE_MPEG || -+ track->par->format != AV_PIX_FMT_YUV420P10) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 2: -+ // Don't check range or color info for SDR base layer as a lot of them will set to unspecified -+ // And a lot of players assumes unspecified as BT709 in tv range -+ if (track->par->format != AV_PIX_FMT_YUV420P) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 4: -+ if (track->par->color_trc != AVCOL_TRC_ARIB_STD_B67 || -+ track->par->color_primaries != AVCOL_PRI_BT2020 || -+ track->par->color_space != AVCOL_SPC_BT2020_NCL || -+ track->par->color_range != AVCOL_RANGE_MPEG || -+ track->par->format != AV_PIX_FMT_YUV420P10) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ default: -+ // others are reserved value, don't check -+ break; -+ } -+ -+ if (is_dovi_config_valid) { -+ mov_write_dvcc_dvvc_tag(s, pb, dovi_config); -+ } -+ } - } - - if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) { -Index: FFmpeg/libavformat/matroskaenc.c -=================================================================== ---- FFmpeg.orig/libavformat/matroskaenc.c -+++ FFmpeg/libavformat/matroskaenc.c -@@ -1719,28 +1719,96 @@ static void mkv_write_blockadditionmappi - - dovi = (const AVDOVIDecoderConfigurationRecord *)sd->data; - if (dovi->dv_profile <= 10) { -- ebml_master mapping; -- uint8_t buf[ISOM_DVCC_DVVC_SIZE]; -- uint32_t type; -- -- uint64_t expected_size = (2 + 1 + (sizeof(DVCC_DVVC_BLOCK_TYPE_NAME) - 1)) -- + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); -- -- if (dovi->dv_profile > 7) { -- type = MATROSKA_BLOCK_ADD_ID_TYPE_DVVC; -- } else { -- type = MATROSKA_BLOCK_ADD_ID_TYPE_DVCC; -+ int is_dovi_config_valid = 1; -+ switch (dovi->dv_level) { -+ case 4: -+ case 5: -+ case 7: -+ case 8: -+ case 20: -+ if (par->codec_id != AV_CODEC_ID_HEVC) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 9: -+ if (par->codec_id != AV_CODEC_ID_H264) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 10: -+ if (par->codec_id != AV_CODEC_ID_AV1) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ default: -+ is_dovi_config_valid = 0; -+ break; - } - -- ff_isom_put_dvcc_dvvc(s, buf, dovi); -+ switch (dovi->dv_bl_signal_compatibility_id) { -+ case 0: -+ if (par->color_range != AVCOL_RANGE_JPEG || -+ par->format != AV_PIX_FMT_YUV420P10 || -+ !(par->codec_tag == MKTAG('d', 'v', 'h', '1') || -+ par->codec_tag == MKTAG('d', 'v', 'h', 'e') || -+ par->codec_tag == MKTAG('d', 'a', 'v', '1'))) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 1: -+ case 6: -+ if (par->color_trc != AVCOL_TRC_SMPTE2084 || -+ par->color_primaries != AVCOL_PRI_BT2020 || -+ par->color_space != AVCOL_SPC_BT2020_NCL || -+ par->color_range != AVCOL_RANGE_MPEG || -+ par->format != AV_PIX_FMT_YUV420P10) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 2: -+ // Don't check range or color info for SDR base layer as a lot of them will set to unspecified -+ // And a lot of players assumes unspecified as BT709 in tv range -+ if (par->format != AV_PIX_FMT_YUV420P) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ case 4: -+ if (par->color_trc != AVCOL_TRC_ARIB_STD_B67 || -+ par->color_primaries != AVCOL_PRI_BT2020 || -+ par->color_space != AVCOL_SPC_BT2020_NCL || -+ par->color_range != AVCOL_RANGE_MPEG || -+ par->format != AV_PIX_FMT_YUV420P10) { -+ is_dovi_config_valid = 0; -+ } -+ break; -+ default: -+ // others are reserved value, don't check -+ break; -+ } -+ if (is_dovi_config_valid) { -+ ebml_master mapping; -+ uint8_t buf[ISOM_DVCC_DVVC_SIZE]; -+ uint32_t type; -+ -+ uint64_t expected_size = (2 + 1 + (sizeof(DVCC_DVVC_BLOCK_TYPE_NAME) - 1)) -+ + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); -+ -+ if (dovi->dv_profile > 7) { -+ type = MATROSKA_BLOCK_ADD_ID_TYPE_DVVC; -+ } else { -+ type = MATROSKA_BLOCK_ADD_ID_TYPE_DVCC; -+ } - -- mapping = start_ebml_master(pb, MATROSKA_ID_TRACKBLKADDMAPPING, expected_size); -+ ff_isom_put_dvcc_dvvc(s, buf, dovi); - -- put_ebml_string(pb, MATROSKA_ID_BLKADDIDNAME, DVCC_DVVC_BLOCK_TYPE_NAME); -- put_ebml_uint(pb, MATROSKA_ID_BLKADDIDTYPE, type); -- put_ebml_binary(pb, MATROSKA_ID_BLKADDIDEXTRADATA, buf, sizeof(buf)); -+ mapping = start_ebml_master(pb, MATROSKA_ID_TRACKBLKADDMAPPING, expected_size); - -- end_ebml_master(pb, mapping); -+ put_ebml_string(pb, MATROSKA_ID_BLKADDIDNAME, DVCC_DVVC_BLOCK_TYPE_NAME); -+ put_ebml_uint(pb, MATROSKA_ID_BLKADDIDTYPE, type); -+ put_ebml_binary(pb, MATROSKA_ID_BLKADDIDEXTRADATA, buf, sizeof(buf)); -+ -+ end_ebml_master(pb, mapping); -+ } - } - #endif - } diff --git a/debian/patches/series b/debian/patches/series index 3feb7ac5054..8a9bb4501a4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -75,4 +75,3 @@ 0075-allow-vpl-qsv-to-init-with-the-legacy-msdk-path.patch 0076-alway-set-videotoolboxenc-pixel-buffer-info.patch 0077-add-remove-dovi-hdr10plus-bsf.patch -0078-validate-dovi-config-for-muxers.patch From e4152b2631710830bbdc0c0d33736638dd790b8f Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 22 Oct 2024 23:03:05 +0800 Subject: [PATCH 3/6] avcodec/mpegtsenc: optimize check order --- ...ovi-sidedata-to-hlsenc-and-mpegtsenc.patch | 43 +++++++------------ 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch b/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch index 2bcad44d165..6617cd190f1 100644 --- a/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch +++ b/debian/patches/0031-pass-dovi-sidedata-to-hlsenc-and-mpegtsenc.patch @@ -36,7 +36,18 @@ Index: FFmpeg/libavformat/movenc.c =================================================================== --- FFmpeg.orig/libavformat/movenc.c +++ FFmpeg/libavformat/movenc.c -@@ -8128,6 +8128,7 @@ static const AVCodecTag codec_mp4_tags[] +@@ -2538,8 +2538,9 @@ static int mov_write_video_tag(AVFormatC + mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); + if (spherical_mapping) + mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); +- if (dovi) ++ if (dovi && !ff_isom_validate_dovi_config((AVDOVIDecoderConfigurationRecord *)dovi->data, track->par, track->tag)) { + mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data); ++ } + } + + if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) { +@@ -8128,6 +8129,7 @@ static const AVCodecTag codec_mp4_tags[] { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') }, @@ -44,7 +55,7 @@ Index: FFmpeg/libavformat/movenc.c { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') }, { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') }, { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') }, -@@ -8141,6 +8142,7 @@ static const AVCodecTag codec_mp4_tags[] +@@ -8141,6 +8143,7 @@ static const AVCodecTag codec_mp4_tags[] { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') }, { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') }, { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') }, @@ -134,9 +145,9 @@ Index: FFmpeg/libavformat/mpegtsenc.c + st->codecpar->nb_coded_side_data, AV_PKT_DATA_DOVI_CONF); + const AVDOVIDecoderConfigurationRecord *dovi = sd ? (const AVDOVIDecoderConfigurationRecord *)sd->data : NULL; + if (dovi && -+ !ff_isom_validate_dovi_config(dovi, st->codecpar, MKTAG('d', 'v', 'h', '1')) && // always assume tag is valid + dovi->bl_present_flag && -+ s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { ++ s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL && ++ !ff_isom_validate_dovi_config(dovi, st->codecpar, MKTAG('d', 'v', 'h', '1'))) { // always assume tag is valid + if (put_dovi_descriptor(s, &q, dovi) < 0) + break; + } else { @@ -241,26 +252,11 @@ Index: FFmpeg/libavformat/dovi_isom.h + const AVCodecParameters *codec_par, int codec_tag); + #endif /* AVFORMAT_DOVI_ISOM_H */ - Index: FFmpeg/libavformat/movenc.c -=================================================================== ---- FFmpeg.orig/libavformat/movenc.c -+++ FFmpeg/libavformat/movenc.c -@@ -2538,8 +2538,9 @@ static int mov_write_video_tag(AVFormatC - mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); - if (spherical_mapping) - mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); -- if (dovi) -+ if (dovi && !ff_isom_validate_dovi_config((AVDOVIDecoderConfigurationRecord *)dovi->data, track->par, track->tag)) { - mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data); -+ } - } - - if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) { Index: FFmpeg/libavformat/matroskaenc.c =================================================================== --- FFmpeg.orig/libavformat/matroskaenc.c +++ FFmpeg/libavformat/matroskaenc.c -@@ -1718,13 +1718,14 @@ static void mkv_write_blockadditionmappi +@@ -1718,7 +1718,8 @@ static void mkv_write_blockadditionmappi return; dovi = (const AVDOVIDecoderConfigurationRecord *)sd->data; @@ -270,10 +266,3 @@ Index: FFmpeg/libavformat/matroskaenc.c ebml_master mapping; uint8_t buf[ISOM_DVCC_DVVC_SIZE]; uint32_t type; - - uint64_t expected_size = (2 + 1 + (sizeof(DVCC_DVVC_BLOCK_TYPE_NAME) - 1)) -- + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); -+ + (2 + 1 + 4) + (2 + 1 + ISOM_DVCC_DVVC_SIZE); - - if (dovi->dv_profile > 7) { - type = MATROSKA_BLOCK_ADD_ID_TYPE_DVVC; From 7107cc2e4fccc57985eabe2c85b1dd3b91880703 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 22 Oct 2024 23:44:02 +0800 Subject: [PATCH 4/6] builder: don't use cargo-c 0.10.5 --- builder/images/base/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/images/base/Dockerfile b/builder/images/base/Dockerfile index 001088d0a1a..c41bd557876 100644 --- a/builder/images/base/Dockerfile +++ b/builder/images/base/Dockerfile @@ -19,7 +19,7 @@ RUN \ ENV CARGO_HOME="/opt/cargo" RUSTUP_HOME="/opt/rustup" PATH="/opt/cargo/bin:${PATH}" RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --no-modify-path && \ - cargo install cargo-c && rm -rf "${CARGO_HOME}"/registry "${CARGO_HOME}"/git + cargo install cargo-c@0.10.4 && rm -rf "${CARGO_HOME}"/registry "${CARGO_HOME}"/git RUN --mount=src=.,dst=/input \ for s in /input/*.sh; do cp $s /usr/bin/$(echo $s | sed -e 's|.*/||' -e 's/\.sh$//'); done From ef477e9ded3916f502ab15d809b7d4f0aa7484e9 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 22 Oct 2024 23:52:20 +0800 Subject: [PATCH 5/6] builder: use rust 1.81 --- builder/images/base/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/builder/images/base/Dockerfile b/builder/images/base/Dockerfile index c41bd557876..d19f6df219e 100644 --- a/builder/images/base/Dockerfile +++ b/builder/images/base/Dockerfile @@ -18,8 +18,9 @@ RUN \ git config --global advice.detachedHead false ENV CARGO_HOME="/opt/cargo" RUSTUP_HOME="/opt/rustup" PATH="/opt/cargo/bin:${PATH}" -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --no-modify-path && \ - cargo install cargo-c@0.10.4 && rm -rf "${CARGO_HOME}"/registry "${CARGO_HOME}"/git +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --no-modify-path +RUN rustup install 1.81.0 +RUN cargo +1.81.0 install cargo-c && rm -rf "${CARGO_HOME}"/registry "${CARGO_HOME}"/git RUN --mount=src=.,dst=/input \ for s in /input/*.sh; do cp $s /usr/bin/$(echo $s | sed -e 's|.*/||' -e 's/\.sh$//'); done From 1733fb8802771b72558b283f552104dc4ffb723e Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 23 Oct 2024 00:16:04 +0800 Subject: [PATCH 6/6] builder: use locked version for rust --- builder/images/base/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builder/images/base/Dockerfile b/builder/images/base/Dockerfile index d19f6df219e..9ecb0cd788a 100644 --- a/builder/images/base/Dockerfile +++ b/builder/images/base/Dockerfile @@ -19,8 +19,7 @@ RUN \ ENV CARGO_HOME="/opt/cargo" RUSTUP_HOME="/opt/rustup" PATH="/opt/cargo/bin:${PATH}" RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --no-modify-path -RUN rustup install 1.81.0 -RUN cargo +1.81.0 install cargo-c && rm -rf "${CARGO_HOME}"/registry "${CARGO_HOME}"/git +RUN cargo install --locked cargo-c && rm -rf "${CARGO_HOME}"/registry "${CARGO_HOME}"/git RUN --mount=src=.,dst=/input \ for s in /input/*.sh; do cp $s /usr/bin/$(echo $s | sed -e 's|.*/||' -e 's/\.sh$//'); done