From 0b0cb7cd6cf9c07f456b170dbca5728cb0af6350 Mon Sep 17 00:00:00 2001 From: Baptiste Coudurier Date: Tue, 3 Jun 2025 17:50:15 -0700 Subject: [PATCH] lavf/movenc: improve AVdh atom generation for DNxHD/DNxHR --- libavformat/movenc.c | 86 +++++++++++++------ tests/ref/vsynth/vsynth1-dnxhd-1080i | 2 +- tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit | 2 +- tests/ref/vsynth/vsynth1-dnxhd-1080i-colr | 2 +- tests/ref/vsynth/vsynth2-dnxhd-1080i | 2 +- tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit | 2 +- tests/ref/vsynth/vsynth2-dnxhd-1080i-colr | 2 +- tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit | 2 +- tests/ref/vsynth/vsynth3-dnxhd-1080i-colr | 2 +- tests/ref/vsynth/vsynth_lena-dnxhd-1080i | 2 +- .../ref/vsynth/vsynth_lena-dnxhd-1080i-10bit | 2 +- tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr | 2 +- 12 files changed, 73 insertions(+), 35 deletions(-) diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 218a285821..7d5d8f27e2 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -1679,17 +1679,18 @@ static int mov_write_apvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra } /* also used by all avid codecs (dv, imx, meridien) and their variants */ +/* https://community.avid.com/forums/t/136517.aspx */ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) { int interlaced; int cid; int display_width = track->par->width; + const uint8_t *extradata; if (track->extradata[track->last_stsd_index] && track->extradata_size[track->last_stsd_index] > 0x29) { if (ff_dnxhd_parse_header_prefix(track->extradata[track->last_stsd_index]) != 0) { /* looks like a DNxHD bit stream */ - interlaced = (track->extradata[track->last_stsd_index][5] & 2); - cid = AV_RB32(track->extradata[track->last_stsd_index] + 0x28); + extradata = track->extradata[track->last_stsd_index]; } else { av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n"); return 0; @@ -1699,60 +1700,97 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) return 0; } + cid = AV_RB32(extradata + 0x28); + avio_wb32(pb, 24); /* size */ ffio_wfourcc(pb, "ACLR"); ffio_wfourcc(pb, "ACLR"); ffio_wfourcc(pb, "0001"); + // 1: CCIR (supercolors will be dropped, 16 will be displayed as black) + // 2: FullRange (0 will be displayed as black, 16 will be displayed as dark grey) if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */ track->par->color_range == AVCOL_RANGE_UNSPECIFIED) { - avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */ - } else { /* Full range (0-255) */ - avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */ + avio_wb32(pb, 1); + } else { + avio_wb32(pb, 2); } - avio_wb32(pb, 0); /* unknown */ + avio_wb32(pb, 0); /* reserved */ if (track->tag == MKTAG('A','V','d','h')) { + int alp = extradata[0x07] & 1; + int pma = (extradata[0x07] >> 2) & 1; + int sbd = (extradata[0x21] >> 5) & 3; + int ssc = (extradata[0x2C] >> 5) & 3; + int clv = (extradata[0x2C] >> 1) & 3; + int clf = extradata[0x2C] & 1; + avio_wb32(pb, 32); ffio_wfourcc(pb, "ADHR"); ffio_wfourcc(pb, "0001"); - avio_wb32(pb, cid); - avio_wb32(pb, 0); /* unknown */ - avio_wb32(pb, 1); /* unknown */ - avio_wb32(pb, 0); /* unknown */ - avio_wb32(pb, 0); /* unknown */ + avio_wb32(pb, cid); // Compression ID + // 0: 4:2:2 Sub Sampling + // 1: 4:2:0 Sub Sampling + // 2: 4:4:4 Sub Sampling + avio_wb32(pb, ssc); // Sub Sampling Control + // 1: 8-bits per sample + // 2: 10-bits per sample + // 3: 12-bits per sample + avio_wb32(pb, sbd); // Sample Bit Depth + // 0: Bitstream is encoded using the YCBCR format rules and tables + // 1: Bitstream is encoded using the RGB format rules and tables – only Compression IDs 1256, 1270 + avio_wb16(pb, clf); // Color Format + // 0: ITU-R BT.709 + // 1: ITU-R BT.2020 + // 2: ITU-R BT.2020 C + // 3: Out-of-band + avio_wb16(pb, clv); // Color Volume + // 0: Alpha channel not present + // 1: Alpha channel present + avio_wb16(pb, alp); // Alpha Present + // 0: Alpha has not been applied to video channels + // 1: Alpha has been applied to the video channels prior to encoding + avio_wb16(pb, pma); // Pre-Multiplied Alpha return 0; } + interlaced = extradata[5] & 2; + avio_wb32(pb, 24); /* size */ ffio_wfourcc(pb, "APRG"); ffio_wfourcc(pb, "APRG"); ffio_wfourcc(pb, "0001"); - avio_wb32(pb, 1); /* unknown */ - avio_wb32(pb, 0); /* unknown */ + // 1 for progressive or 2 for interlaced + if (interlaced) + avio_wb32(pb, 2); + else + avio_wb32(pb, 1); + avio_wb32(pb, 0); /* reserved */ avio_wb32(pb, 120); /* size */ ffio_wfourcc(pb, "ARES"); ffio_wfourcc(pb, "ARES"); ffio_wfourcc(pb, "0001"); - avio_wb32(pb, cid); /* dnxhd cid, some id ? */ + avio_wb32(pb, cid); /* cid */ if ( track->par->sample_aspect_ratio.num > 0 && track->par->sample_aspect_ratio.den > 0) display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den; - avio_wb32(pb, display_width); - /* values below are based on samples created with quicktime and avid codecs */ + avio_wb32(pb, display_width); // field width if (interlaced) { - avio_wb32(pb, track->par->height / 2); - avio_wb32(pb, 2); /* unknown */ - avio_wb32(pb, 0); /* unknown */ - avio_wb32(pb, 4); /* unknown */ + avio_wb32(pb, track->par->height / 2); // field height + avio_wb32(pb, 2); // num fields + avio_wb32(pb, 0); // num black lines (must be 0) + // 4: HD1080i + // 5: HD1080P + // 6: HD720P + avio_wb32(pb, 4); // video format } else { avio_wb32(pb, track->par->height); - avio_wb32(pb, 1); /* unknown */ - avio_wb32(pb, 0); /* unknown */ + avio_wb32(pb, 1); // num fields + avio_wb32(pb, 0); if (track->par->height == 1080) - avio_wb32(pb, 5); /* unknown */ + avio_wb32(pb, 5); else - avio_wb32(pb, 6); /* unknown */ + avio_wb32(pb, 6); } /* padding */ ffio_fill(pb, 0, 10 * 8); diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i b/tests/ref/vsynth/vsynth1-dnxhd-1080i index 0e7844b0ee..ce08c85156 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-1080i +++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i @@ -1,4 +1,4 @@ -af5cbe239839f6282a68f1a106ed3a77 *tests/data/fate/vsynth1-dnxhd-1080i.mov +ac2ec2b1e8daef96715c7032db3447de *tests/data/fate/vsynth1-dnxhd-1080i.mov 3031911 tests/data/fate/vsynth1-dnxhd-1080i.mov fed9ed2a5179c9df0ef58772b025e303 *tests/data/fate/vsynth1-dnxhd-1080i.out.rawvideo stddev: 6.18 PSNR: 32.31 MAXDIFF: 64 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit index c3f3fda085..8dc3e50fd5 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -1a8261120bcc764a7bbdd198febff4c7 *tests/data/fate/vsynth1-dnxhd-1080i-10bit.mov +4b7ccdc290bd06cfcaf29baad55081fa *tests/data/fate/vsynth1-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth1-dnxhd-1080i-10bit.mov 31032fcb7e6af79daaac02288254c6d6 *tests/data/fate/vsynth1-dnxhd-1080i-10bit.out.rawvideo stddev: 5.69 PSNR: 33.02 MAXDIFF: 55 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr index 35cd719b63..a07f6b375c 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -5571f4ff9e29d352a7e373a14a9ed2ed *tests/data/fate/vsynth1-dnxhd-1080i-colr.mov +3bf2c5863bf8a46365e5ead657d01796 *tests/data/fate/vsynth1-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth1-dnxhd-1080i-colr.mov 6f2d5429ffc4529a76acfeb28b560542 *tests/data/fate/vsynth1-dnxhd-1080i-colr.out.rawvideo stddev: 5.65 PSNR: 33.09 MAXDIFF: 55 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i b/tests/ref/vsynth/vsynth2-dnxhd-1080i index 0668a44f9a..619d51a33e 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-1080i +++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i @@ -1,4 +1,4 @@ -0067903558c99e3abed402ed65297735 *tests/data/fate/vsynth2-dnxhd-1080i.mov +16784dcb2a944d681ee8125744598a00 *tests/data/fate/vsynth2-dnxhd-1080i.mov 3031911 tests/data/fate/vsynth2-dnxhd-1080i.mov e941d2587cfeccddc450da7f41f7f911 *tests/data/fate/vsynth2-dnxhd-1080i.out.rawvideo stddev: 1.50 PSNR: 44.56 MAXDIFF: 31 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit index 7689e2c22e..0ec33c68e8 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -16e86953a697e1e7f9d80903ff4fef0c *tests/data/fate/vsynth2-dnxhd-1080i-10bit.mov +f72fd4fb2f8969ae51809a049bacc036 *tests/data/fate/vsynth2-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth2-dnxhd-1080i-10bit.mov e4ca9be476869afb94962d945f90bdf6 *tests/data/fate/vsynth2-dnxhd-1080i-10bit.out.rawvideo stddev: 1.57 PSNR: 44.18 MAXDIFF: 33 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr index f5ac604716..3029a6f72a 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -eee674d012c850c1d2bb5e816b668cdf *tests/data/fate/vsynth2-dnxhd-1080i-colr.mov +64957f9ac88f32c175f22106fe60d291 *tests/data/fate/vsynth2-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth2-dnxhd-1080i-colr.mov ec40a8014b819d02951b2f06bee7b514 *tests/data/fate/vsynth2-dnxhd-1080i-colr.out.rawvideo stddev: 1.54 PSNR: 44.33 MAXDIFF: 33 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit index 2a040e12db..51e46f7450 100644 --- a/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -4e6185e273297061def8e0b7fabff71b *tests/data/fate/vsynth3-dnxhd-1080i-10bit.mov +ec15292ebe59baa20dea7a9c8fd64237 *tests/data/fate/vsynth3-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth3-dnxhd-1080i-10bit.mov c192f36ef8687e56c72a3dc416c7e191 *tests/data/fate/vsynth3-dnxhd-1080i-10bit.out.rawvideo stddev: 6.92 PSNR: 31.32 MAXDIFF: 50 bytes: 86700/ 8670 diff --git a/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr index 08aa30d8c4..920e86ccec 100644 --- a/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -92a2f67cf77abf3428fe2d4f53ba2027 *tests/data/fate/vsynth3-dnxhd-1080i-colr.mov +32cf64f3043053d3003388ab12f53cbe *tests/data/fate/vsynth3-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth3-dnxhd-1080i-colr.mov f907fd2d48bedbc5283fbfc3fb9f61a0 *tests/data/fate/vsynth3-dnxhd-1080i-colr.out.rawvideo stddev: 6.92 PSNR: 31.32 MAXDIFF: 50 bytes: 86700/ 8670 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i index ae5c515165..28b134e2b4 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i @@ -1,4 +1,4 @@ -1bb94b5a7917c1d81f3a92dd9b5b66ae *tests/data/fate/vsynth_lena-dnxhd-1080i.mov +ffd735676e998c9ad34757610e4078fa *tests/data/fate/vsynth_lena-dnxhd-1080i.mov 3031911 tests/data/fate/vsynth_lena-dnxhd-1080i.mov 7d0ca92f12711535d57eff3609462b31 *tests/data/fate/vsynth_lena-dnxhd-1080i.out.rawvideo stddev: 1.29 PSNR: 45.87 MAXDIFF: 22 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit index 5112f2a379..b8133e00a6 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -55e1097376ac44e916528eee5ee2266e *tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.mov +527c32a4f772ee94b85cf641053bf516 *tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.mov f2dc4375c58e0406d442e0cb28573e91 *tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.out.rawvideo stddev: 1.36 PSNR: 45.40 MAXDIFF: 22 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr index c21babba0f..878d7860ad 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -f80be8c3350ca8b22ae8aa8724b2ef20 *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov +6caa2aa3b496e591659d456eba0d9432 *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov ce4993a69ef55c8c4b18138716f17b6f *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.out.rawvideo stddev: 1.33 PSNR: 45.59 MAXDIFF: 22 bytes: 7603200/ 760320