* [FFmpeg-devel] [PATCH] Fix jpeg2k and dnxhr 444 MXF and MOV muxing (PR #20711)
@ 2025-10-16 0:21 Baptiste Coudurier via ffmpeg-devel
0 siblings, 0 replies; only message in thread
From: Baptiste Coudurier via ffmpeg-devel @ 2025-10-16 0:21 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Baptiste Coudurier
PR #20711 opened by Baptiste Coudurier (bcoudurier)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20711
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20711.patch
From 8bc654b2c0f79213195140f372c83095b0e2b123 Mon Sep 17 00:00:00 2001
From: Baptiste Coudurier <baptiste.coudurier@gmail.com>
Date: Tue, 3 Jun 2025 17:50:15 -0700
Subject: [PATCH 1/7] 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 +-
9 files changed, 70 insertions(+), 32 deletions(-)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 067d38b14b..f2aa141fb7 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
--
2.49.1
From d986e9525424104dbafb2c68702532b07b417a07 Mon Sep 17 00:00:00 2001
From: Baptiste Coudurier <baptiste.coudurier@gmail.com>
Date: Wed, 4 Jun 2025 10:43:04 -0700
Subject: [PATCH 2/7] lavf/mxfenc: require pixel format to be set for video
streams
---
libavformat/mxfenc.c | 56 +++++++++++++++++---------------------------
1 file changed, 21 insertions(+), 35 deletions(-)
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index b14a480ba3..ed315be140 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -1493,11 +1493,6 @@ static int mxf_write_jpeg2000_subdesc(AVFormatContext *s, AVStream *st)
int64_t pos;
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(st->codecpar->format);
- if (!pix_desc) {
- av_log(s, AV_LOG_ERROR, "Pixel format not set - not writing JPEG2000SubDescriptor\n");
- return AVERROR(EINVAL);
- }
-
/* JPEG2000 subdescriptor key */
avio_write(pb, mxf_jpeg2000_subdescriptor_key, 16);
klv_encode_ber4_length(pb, 0);
@@ -1610,7 +1605,6 @@ static int mxf_write_ffv1_desc(AVFormatContext *s, AVStream *st)
{
int is_rgb, pos;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(st->codecpar->format);
- av_assert0(desc);
is_rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
pos = mxf_write_cdci_common(s, st, is_rgb ? mxf_rgba_descriptor_key : mxf_cdci_descriptor_key);
@@ -2692,11 +2686,6 @@ static int mxf_parse_jpeg2000_frame(AVFormatContext *s, AVStream *st, AVPacket *
GetByteContext g;
uint32_t j2k_ncomponents;
- if (!pix_desc) {
- av_log(s, AV_LOG_ERROR, "Pixel format not set\n");
- return AVERROR(EINVAL);
- }
-
if (mxf->header_written)
return 1;
@@ -2898,20 +2887,18 @@ static enum AVChromaLocation choose_chroma_location(AVFormatContext *s, AVStream
if (par->chroma_location != AVCHROMA_LOC_UNSPECIFIED)
return par->chroma_location;
- if (pix_desc) {
- if (pix_desc->log2_chroma_h == 0) {
- return AVCHROMA_LOC_TOPLEFT;
- } else if (pix_desc->log2_chroma_w == 1 && pix_desc->log2_chroma_h == 1) {
- if (par->field_order == AV_FIELD_UNKNOWN || par->field_order == AV_FIELD_PROGRESSIVE) {
- switch (par->codec_id) {
- case AV_CODEC_ID_MJPEG:
- case AV_CODEC_ID_MPEG1VIDEO: return AVCHROMA_LOC_CENTER;
- }
+ if (pix_desc->log2_chroma_h == 0) {
+ return AVCHROMA_LOC_TOPLEFT;
+ } else if (pix_desc->log2_chroma_w == 1 && pix_desc->log2_chroma_h == 1) {
+ if (par->field_order == AV_FIELD_UNKNOWN || par->field_order == AV_FIELD_PROGRESSIVE) {
+ switch (par->codec_id) {
+ case AV_CODEC_ID_MJPEG:
+ case AV_CODEC_ID_MPEG1VIDEO: return AVCHROMA_LOC_CENTER;
}
- if (par->field_order == AV_FIELD_UNKNOWN || par->field_order != AV_FIELD_PROGRESSIVE) {
- switch (par->codec_id) {
- case AV_CODEC_ID_MPEG2VIDEO: return AVCHROMA_LOC_LEFT;
- }
+ }
+ if (par->field_order == AV_FIELD_UNKNOWN || par->field_order != AV_FIELD_PROGRESSIVE) {
+ switch (par->codec_id) {
+ case AV_CODEC_ID_MPEG2VIDEO: return AVCHROMA_LOC_LEFT;
}
}
}
@@ -2950,27 +2937,26 @@ static int mxf_init(AVFormatContext *s)
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(st->codecpar->format);
AVRational tbc = (AVRational){ 0, 0 };
+
+ if (!pix_desc) {
+ av_log(s, AV_LOG_ERROR, "video stream require the codec pixel format to be set\n");
+ return -1;
+ }
+
if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0)
tbc = av_inv_q(st->avg_frame_rate);
else if (st->r_frame_rate.num > 0 && st->r_frame_rate.den > 0)
tbc = av_inv_q(st->r_frame_rate);
- // Default component depth to 8
- sc->component_depth = 8;
- sc->h_chroma_sub_sample = 2;
- sc->v_chroma_sub_sample = 2;
- sc->color_siting = 0xFF;
-
if (st->codecpar->sample_aspect_ratio.num && st->codecpar->sample_aspect_ratio.den) {
sc->aspect_ratio = av_mul_q(st->codecpar->sample_aspect_ratio,
av_make_q(st->codecpar->width, st->codecpar->height));
}
- if (pix_desc) {
- sc->component_depth = pix_desc->comp[0].depth;
- sc->h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
- sc->v_chroma_sub_sample = 1 << pix_desc->log2_chroma_h;
- }
+ sc->component_depth = pix_desc->comp[0].depth;
+ sc->h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
+ sc->v_chroma_sub_sample = 1 << pix_desc->log2_chroma_h;
+
switch (choose_chroma_location(s, st)) {
case AVCHROMA_LOC_TOPLEFT: sc->color_siting = 0; break;
case AVCHROMA_LOC_LEFT: sc->color_siting = 6; break;
--
2.49.1
From 6a26192e536e5eb49b269ce4be496968b693342c Mon Sep 17 00:00:00 2001
From: Baptiste Coudurier <baptiste.coudurier@gmail.com>
Date: Tue, 3 Jun 2025 23:11:43 -0700
Subject: [PATCH 3/7] lavf/mxfenc: remove cdci pixel format specific values
from stream context
---
libavformat/mxfenc.c | 64 +++++++++++++++++++-------------------------
1 file changed, 28 insertions(+), 36 deletions(-)
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index ed315be140..30d8cc1c27 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -106,11 +106,7 @@ typedef struct MXFStreamContext {
int order; ///< interleaving order if dts are equal
int interlaced; ///< whether picture is interlaced
int field_dominance; ///< tff=1, bff=2
- int component_depth;
- int color_siting;
int signal_standard;
- int h_chroma_sub_sample;
- int v_chroma_sub_sample;
int temporal_reordering;
AVRational aspect_ratio; ///< display aspect ratio
int closed_gop; ///< gop is closed, used in mpeg-2 frame parsing
@@ -180,6 +176,8 @@ static int mxf_write_cdci_desc(AVFormatContext *s, AVStream *st);
static int mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st);
static int mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st);
+static enum AVChromaLocation choose_chroma_location(AVFormatContext *s, AVStream *st);
+
static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 },
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
@@ -1207,6 +1205,7 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
{
MXFStreamContext *sc = st->priv_data;
AVIOContext *pb = s->pb;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(st->codecpar->format);
int stored_width = st->codecpar->width;
int stored_height = st->codecpar->height;
int display_width;
@@ -1309,21 +1308,37 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
}
if (key != mxf_rgba_descriptor_key) {
+ int component_depth = pix_desc->comp[0].depth;
+ int h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
+ int v_chroma_sub_sample = 1 << pix_desc->log2_chroma_h;
+ int color_siting;
+
// component depth
mxf_write_local_tag(s, 4, 0x3301);
- avio_wb32(pb, sc->component_depth);
+ avio_wb32(pb, component_depth);
// horizontal subsampling
mxf_write_local_tag(s, 4, 0x3302);
- avio_wb32(pb, sc->h_chroma_sub_sample);
+ avio_wb32(pb, h_chroma_sub_sample);
// vertical subsampling
mxf_write_local_tag(s, 4, 0x3308);
- avio_wb32(pb, sc->v_chroma_sub_sample);
+ avio_wb32(pb, v_chroma_sub_sample);
+
+ switch (choose_chroma_location(s, st)) {
+ case AVCHROMA_LOC_TOPLEFT: color_siting = 0; break;
+ case AVCHROMA_LOC_LEFT: color_siting = 6; break;
+ case AVCHROMA_LOC_TOP: color_siting = 1; break;
+ case AVCHROMA_LOC_CENTER: color_siting = 3; break;
+ default: color_siting = 0xff;
+ }
+
+ if (IS_D10(s))
+ color_siting = 0; // color siting is specified to be 0 in d-10 specs
// color siting
mxf_write_local_tag(s, 1, 0x3303);
- avio_w8(pb, sc->color_siting);
+ avio_w8(pb, color_siting);
// Padding Bits
mxf_write_local_tag(s, 2, 0x3307);
@@ -1331,12 +1346,12 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
if (st->codecpar->color_range != AVCOL_RANGE_UNSPECIFIED) {
int black = 0,
- white = (1<<sc->component_depth) - 1,
- color = (1<<sc->component_depth);
+ white = (1<<component_depth) - 1,
+ color = (1<<component_depth);
if (st->codecpar->color_range == AVCOL_RANGE_MPEG) {
- black = 1 << (sc->component_depth - 4);
- white = 235 << (sc->component_depth - 8);
- color = (14 << (sc->component_depth - 4)) + 1;
+ black = 1 << (component_depth - 4);
+ white = 235 << (component_depth - 8);
+ color = (14 << (component_depth - 4)) + 1;
}
mxf_write_local_tag(s, 4, 0x3304);
avio_wb32(pb, black);
@@ -2354,15 +2369,6 @@ static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt
if (i == FF_ARRAY_ELEMS(mxf_dnxhd_codec_uls))
return 0;
- sc->component_depth = 0;
- switch (pkt->data[0x21] >> 5) {
- case 1: sc->component_depth = 8; break;
- case 2: sc->component_depth = 10; break;
- case 3: sc->component_depth = 12; break;
- }
- if (!sc->component_depth)
- return 0;
-
if (cid >= 1270) { // RI raster
av_reduce(&sc->aspect_ratio.num, &sc->aspect_ratio.den,
st->codecpar->width, st->codecpar->height,
@@ -2536,7 +2542,6 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
sc->aspect_ratio.num, sc->aspect_ratio.den, 1024*1024);
intra_only = (sps->constraint_set_flags >> 3) & 1;
sc->interlaced = !sps->frame_mbs_only_flag;
- sc->component_depth = sps->bit_depth_luma;
buf = nal_end;
break;
@@ -2581,7 +2586,6 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
for (i = 0; i < FF_ARRAY_ELEMS(mxf_h264_codec_uls); i++) {
if (frame_size == mxf_h264_codec_uls[i].frame_size && sc->interlaced == mxf_h264_codec_uls[i].interlaced) {
codec_ul = &mxf_h264_codec_uls[i].uid;
- sc->component_depth = 10; // AVC Intra is always 10 Bit
sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for broadcast HD
st->codecpar->profile = mxf_h264_codec_uls[i].profile;
sc->avc_intra = 1;
@@ -2953,17 +2957,6 @@ static int mxf_init(AVFormatContext *s)
av_make_q(st->codecpar->width, st->codecpar->height));
}
- sc->component_depth = pix_desc->comp[0].depth;
- sc->h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
- sc->v_chroma_sub_sample = 1 << pix_desc->log2_chroma_h;
-
- switch (choose_chroma_location(s, st)) {
- case AVCHROMA_LOC_TOPLEFT: sc->color_siting = 0; break;
- case AVCHROMA_LOC_LEFT: sc->color_siting = 6; break;
- case AVCHROMA_LOC_TOP: sc->color_siting = 1; break;
- case AVCHROMA_LOC_CENTER: sc->color_siting = 3; break;
- }
-
mxf->content_package_rate = ff_mxf_get_content_package_rate(tbc);
mxf->time_base = tbc;
avpriv_set_pts_info(st, 64, mxf->time_base.num, mxf->time_base.den);
@@ -3006,7 +2999,6 @@ static int mxf_init(AVFormatContext *s)
sc->container_ul = &mxf_d10_container_uls[ul_index];
sc->index = INDEX_D10_VIDEO;
sc->signal_standard = 1;
- sc->color_siting = 0;
sc->frame_size = (int64_t)sc->video_bit_rate *
mxf->time_base.num / (8*mxf->time_base.den);
}
--
2.49.1
From 792e479ec258fe027faa4b61a15b0fa7dc5aea2f Mon Sep 17 00:00:00 2001
From: Baptiste Coudurier <baptiste.coudurier@gmail.com>
Date: Wed, 4 Jun 2025 11:24:41 -0700
Subject: [PATCH 4/7] lavf/mxfenc: correctly add jpeg2000 subdescriptor
reference in cdci, factorize
---
libavformat/mxfenc.c | 50 +++++++++++++++++++++++---------------------
1 file changed, 26 insertions(+), 24 deletions(-)
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 30d8cc1c27..b935361599 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -117,9 +117,9 @@ typedef struct MXFStreamContext {
int max_gop; ///< maximum gop size, used by mpeg-2 descriptor
int b_picture_count; ///< maximum number of consecutive b pictures, used in mpeg-2 descriptor
int low_delay; ///< low delay, used in mpeg-2 descriptor
- int avc_intra;
int micro_version; ///< format micro_version, used in ffv1 descriptor
j2k_info_t j2k_info;
+ enum MXFMetadataSetType sub_descriptor;
} MXFStreamContext;
typedef struct MXFContainerEssenceEntry {
@@ -417,8 +417,9 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x4406, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x0C,0x00,0x00,0x00}}, /* User Comments */
{ 0x5001, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x09,0x01,0x00,0x00}}, /* Name */
{ 0x5003, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x0A,0x01,0x00,0x00}}, /* Value */
- // mxf_avc_subdescriptor_local_tags
+ // sub descriptor used AVC, JPEG2000 and FFV1
{ 0x8100, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00}}, /* SubDescriptors */
+ // mxf_avc_subdescriptor_local_tags
{ 0x8200, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0E,0x00,0x00}}, /* AVC Decoding Delay */
{ 0x8201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0A,0x00,0x00}}, /* AVC Profile */
{ 0x8202, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0D,0x00,0x00}}, /* AVC Level */
@@ -432,7 +433,6 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0xDFDA, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x0C,0x05,0x00,0x00,0x00}}, /* FFV1 Version */
{ 0xDFDB, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x0C,0x01,0x00,0x00,0x00}}, /* FFV1 Initialization Metadata */
// ff_mxf_jpeg2000_local_tags
- { 0x8400, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00}}, /* Sub Descriptors / Opt Ordered array of strong references to sub descriptor sets */
{ 0x8401, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x01,0x00,0x00,0x00}}, /* Rsiz: An enumerated value that defines the decoder capabilities */
{ 0x8402, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x02,0x00,0x00,0x00}}, /* Xsiz: Width of the reference grid */
{ 0x8403, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x03,0x00,0x00,0x00}}, /* Ysiz: Height of the reference grid */
@@ -582,10 +582,11 @@ static void mxf_write_primer_pack(AVFormatContext *s)
AVIOContext *pb = s->pb;
int local_tag_number = MXF_NUM_TAGS, i;
int will_have_avc_tags = 0, will_have_mastering_tags = 0, will_have_ffv1_tags = 0, will_have_jpeg2000_tags = 0;
+ int will_have_sub_descriptor = 0;
for (i = 0; i < s->nb_streams; i++) {
MXFStreamContext *sc = s->streams[i]->priv_data;
- if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) {
+ if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 && sc->sub_descriptor) {
will_have_avc_tags = 1;
}
if (av_packet_side_data_get(s->streams[i]->codecpar->coded_side_data,
@@ -599,6 +600,9 @@ static void mxf_write_primer_pack(AVFormatContext *s)
if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_JPEG2000){
will_have_jpeg2000_tags = 1;
}
+ if (sc->sub_descriptor) {
+ will_have_sub_descriptor = 1;
+ }
}
if (!mxf->store_user_comments) {
@@ -607,7 +611,7 @@ static void mxf_write_primer_pack(AVFormatContext *s)
mxf_mark_tag_unused(mxf, 0x5003);
}
- if (!will_have_avc_tags && !will_have_ffv1_tags) {
+ if (!will_have_sub_descriptor) {
mxf_mark_tag_unused(mxf, 0x8100);
}
@@ -631,7 +635,6 @@ static void mxf_write_primer_pack(AVFormatContext *s)
}
if (!will_have_jpeg2000_tags) {
- mxf_mark_tag_unused(mxf, 0x8400);
mxf_mark_tag_unused(mxf, 0x8401);
mxf_mark_tag_unused(mxf, 0x8402);
mxf_mark_tag_unused(mxf, 0x8403);
@@ -1451,18 +1454,10 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
avio_w8(pb, sc->field_dominance);
}
- if (st->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) {
- // write avc sub descriptor ref
+ if (sc->sub_descriptor) {
mxf_write_local_tag(s, 8 + 16, 0x8100);
mxf_write_refs_count(pb, 1);
- mxf_write_uuid(pb, AVCSubDescriptor, 0);
- }
-
- if (st->codecpar->codec_id == AV_CODEC_ID_FFV1) {
- // write ffv1 sub descriptor ref
- mxf_write_local_tag(s, 8 + 16, 0x8100);
- mxf_write_refs_count(pb, 1);
- mxf_write_uuid(pb, FFV1SubDescriptor, 0);
+ mxf_write_uuid(pb, sc->sub_descriptor, 0);
}
return pos;
@@ -1561,22 +1556,22 @@ static int mxf_write_jpeg2000_subdesc(AVFormatContext *s, AVStream *st)
static int mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
{
+ MXFStreamContext *sc = st->priv_data;
int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
mxf_update_klv_size(s->pb, pos);
- if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
- mxf_write_avc_subdesc(s, st);
- }
- if (st->codecpar->codec_id == AV_CODEC_ID_JPEG2000) {
- return mxf_write_jpeg2000_subdesc(s, st);
+ switch (sc->sub_descriptor) {
+ case AVCSubDescriptor: mxf_write_avc_subdesc(s, st); break;
+ case JPEG2000SubDescriptor: mxf_write_jpeg2000_subdesc(s, st); break;
}
+
return 0;
}
static int mxf_write_h264_desc(AVFormatContext *s, AVStream *st)
{
MXFStreamContext *sc = st->priv_data;
- if (sc->avc_intra) {
+ if (!sc->sub_descriptor) {
mxf_write_mpegvideo_desc(s, st);
} else {
int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
@@ -2514,7 +2509,7 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
const UID *codec_ul = NULL;
uint32_t state = -1;
int extra_size = 512; // support AVC Intra files without SPS/PPS header
- int i, frame_size, slice_type, has_sps = 0, intra_only = 0, ret;
+ int i, frame_size, slice_type, has_sps = 0, intra_only = 0, avc_intra = 0, ret;
for (;;) {
buf = avpriv_find_start_code(buf, buf_end, &state);
@@ -2588,7 +2583,7 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
codec_ul = &mxf_h264_codec_uls[i].uid;
sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for broadcast HD
st->codecpar->profile = mxf_h264_codec_uls[i].profile;
- sc->avc_intra = 1;
+ avc_intra = 1;
mxf->cbr_index = 1;
sc->frame_size = pkt->size;
if (sc->interlaced)
@@ -2609,8 +2604,13 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
av_log(s, AV_LOG_ERROR, "h264 profile not supported\n");
return 0;
}
+
sc->codec_ul = codec_ul;
+ if (!avc_intra) {
+ sc->sub_descriptor = AVCSubDescriptor;
+ }
+
return 1;
}
@@ -2669,6 +2669,7 @@ static int mxf_parse_ffv1_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
av_assert0(v < 2);
}
sc->codec_ul = &mxf_ffv1_codec_uls[v];
+ sc->sub_descriptor = FFV1SubDescriptor;
if (st->codecpar->field_order > AV_FIELD_PROGRESSIVE) {
sc->interlaced = 1;
@@ -2726,6 +2727,7 @@ static int mxf_parse_jpeg2000_frame(AVFormatContext *s, AVStream *st, AVPacket *
bytestream2_get_bufferu(&g, sc->j2k_info.j2k_comp_desc, 3 * j2k_ncomponents);
sc->frame_size = pkt->size;
+ sc->sub_descriptor = JPEG2000SubDescriptor;
return 1;
}
--
2.49.1
From 0332f44c438d858760b510b2faaadcbe09c22d6d Mon Sep 17 00:00:00 2001
From: Baptiste Coudurier <baptiste.coudurier@gmail.com>
Date: Wed, 4 Jun 2025 11:35:31 -0700
Subject: [PATCH 5/7] lavf/mxfenc: fix return value to int64_t
---
libavformat/mxfenc.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index b935361599..2b37675938 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -1613,11 +1613,10 @@ static int mxf_write_ffv1_subdesc(AVFormatContext *s, AVStream *st)
static int mxf_write_ffv1_desc(AVFormatContext *s, AVStream *st)
{
- int is_rgb, pos;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(st->codecpar->format);
- is_rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
+ int is_rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
- pos = mxf_write_cdci_common(s, st, is_rgb ? mxf_rgba_descriptor_key : mxf_cdci_descriptor_key);
+ int64_t pos = mxf_write_cdci_common(s, st, is_rgb ? mxf_rgba_descriptor_key : mxf_cdci_descriptor_key);
mxf_update_klv_size(s->pb, pos);
return mxf_write_ffv1_subdesc(s, st);
}
--
2.49.1
From 09cc306bf4de0a90febd800574a0377d489e3ccc Mon Sep 17 00:00:00 2001
From: Baptiste Coudurier <baptiste.coudurier@gmail.com>
Date: Wed, 4 Jun 2025 14:09:50 -0700
Subject: [PATCH 6/7] lavf/mxfenc: factorize cdci descriptor functions
---
libavformat/mxfenc.c | 110 +++++++++++++++++++------------------------
1 file changed, 48 insertions(+), 62 deletions(-)
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 2b37675938..8cd92b980c 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -120,6 +120,7 @@ typedef struct MXFStreamContext {
int micro_version; ///< format micro_version, used in ffv1 descriptor
j2k_info_t j2k_info;
enum MXFMetadataSetType sub_descriptor;
+ const UID *picture_descriptor_key;
} MXFStreamContext;
typedef struct MXFContainerEssenceEntry {
@@ -169,20 +170,22 @@ static const struct {
static int mxf_write_wav_desc(AVFormatContext *s, AVStream *st);
static int mxf_write_aes3_desc(AVFormatContext *s, AVStream *st);
-static int mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st);
-static int mxf_write_h264_desc(AVFormatContext *s, AVStream *st);
-static int mxf_write_ffv1_desc(AVFormatContext *s, AVStream *st);
static int mxf_write_cdci_desc(AVFormatContext *s, AVStream *st);
static int mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st);
static int mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st);
+static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st);
+static void mxf_write_ffv1_subdesc(AVFormatContext *s, AVStream *st);
+
+static int mxf_write_mpegvideo_local_tags(AVFormatContext *s, AVStream *st);
+
static enum AVChromaLocation choose_chroma_location(AVFormatContext *s, AVStream *st);
static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 },
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 },
- mxf_write_mpegvideo_desc },
+ mxf_write_cdci_desc },
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x03,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x16,0x01,0x03,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 },
@@ -220,7 +223,7 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x0D,0x01,0x03,0x01,0x02,0x10,0x60,0x01 },
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 },
- mxf_write_h264_desc },
+ mxf_write_cdci_desc },
// S436M ANC
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x0D,0x01,0x03,0x01,0x02,0x0e,0x00,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x17,0x01,0x02,0x00 },
@@ -235,7 +238,7 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x0d,0x01,0x03,0x01,0x02,0x23,0x01,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x1d,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x09,0x00,0x00 },
- mxf_write_ffv1_desc },
+ mxf_write_cdci_desc },
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
@@ -1204,7 +1207,7 @@ static inline uint32_t rescale_mastering_luma(AVRational q)
return av_rescale(q.num, FF_MXF_MASTERING_LUMA_DEN, q.den);
}
-static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key)
+static int64_t mxf_write_generic_picture_desc(AVFormatContext *s, AVStream *st)
{
MXFStreamContext *sc = st->priv_data;
AVIOContext *pb = s->pb;
@@ -1217,7 +1220,7 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
const MXFCodecUL *color_primaries_ul;
const MXFCodecUL *color_trc_ul;
const MXFCodecUL *color_space_ul;
- int64_t pos = mxf_write_generic_desc(s, st, key);
+ int64_t pos = mxf_write_generic_desc(s, st, *sc->picture_descriptor_key);
const AVPacketSideData *side_data;
color_primaries_ul = mxf_get_codec_ul_by_id(ff_mxf_color_primaries_uls, st->codecpar->color_primaries);
@@ -1310,7 +1313,7 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
avio_wb32(pb, -((st->codecpar->height - display_height)&1));
}
- if (key != mxf_rgba_descriptor_key) {
+ if (sc->picture_descriptor_key != &mxf_rgba_descriptor_key) {
int component_depth = pix_desc->comp[0].depth;
int h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
int v_chroma_sub_sample = 1 << pix_desc->log2_chroma_h;
@@ -1460,6 +1463,9 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
mxf_write_uuid(pb, sc->sub_descriptor, 0);
}
+ if (sc->picture_descriptor_key == &mxf_mpegvideo_descriptor_key)
+ mxf_write_mpegvideo_local_tags(s, st);
+
return pos;
}
@@ -1557,31 +1563,19 @@ static int mxf_write_jpeg2000_subdesc(AVFormatContext *s, AVStream *st)
static int mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
{
MXFStreamContext *sc = st->priv_data;
- int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
+ int64_t pos = mxf_write_generic_picture_desc(s, st);
mxf_update_klv_size(s->pb, pos);
switch (sc->sub_descriptor) {
case AVCSubDescriptor: mxf_write_avc_subdesc(s, st); break;
case JPEG2000SubDescriptor: mxf_write_jpeg2000_subdesc(s, st); break;
+ case FFV1SubDescriptor: mxf_write_ffv1_subdesc(s, st); break;
}
return 0;
}
-static int mxf_write_h264_desc(AVFormatContext *s, AVStream *st)
-{
- MXFStreamContext *sc = st->priv_data;
- if (!sc->sub_descriptor) {
- mxf_write_mpegvideo_desc(s, st);
- } else {
- int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
- mxf_update_klv_size(s->pb, pos);
- mxf_write_avc_subdesc(s, st);
- }
- return 0;
-}
-
-static int mxf_write_ffv1_subdesc(AVFormatContext *s, AVStream *st)
+static void mxf_write_ffv1_subdesc(AVFormatContext *s, AVStream *st)
{
AVIOContext *pb = s->pb;
MXFStreamContext *sc = st->priv_data;
@@ -1608,17 +1602,6 @@ static int mxf_write_ffv1_subdesc(AVFormatContext *s, AVStream *st)
}
mxf_update_klv_size(s->pb, pos);
- return 0;
-}
-
-static int mxf_write_ffv1_desc(AVFormatContext *s, AVStream *st)
-{
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(st->codecpar->format);
- int is_rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
-
- int64_t pos = mxf_write_cdci_common(s, st, is_rgb ? mxf_rgba_descriptor_key : mxf_cdci_descriptor_key);
- mxf_update_klv_size(s->pb, pos);
- return mxf_write_ffv1_subdesc(s, st);
}
static int mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st)
@@ -1628,42 +1611,38 @@ static int mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st)
return 0;
}
-static int mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st)
+static int mxf_write_mpegvideo_local_tags(AVFormatContext *s, AVStream *st)
{
AVIOContext *pb = s->pb;
MXFStreamContext *sc = st->priv_data;
int profile_and_level = (st->codecpar->profile<<4) | st->codecpar->level;
- int64_t pos = mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key);
- if (st->codecpar->codec_id != AV_CODEC_ID_H264) {
- // bit rate
- mxf_write_local_tag(s, 4, 0x8000);
- avio_wb32(pb, sc->video_bit_rate);
+ // bit rate
+ mxf_write_local_tag(s, 4, 0x8000);
+ avio_wb32(pb, sc->video_bit_rate);
- // profile and level
- mxf_write_local_tag(s, 1, 0x8007);
- if (!st->codecpar->profile)
- profile_and_level |= 0x80; // escape bit
- avio_w8(pb, profile_and_level);
+ // profile and level
+ mxf_write_local_tag(s, 1, 0x8007);
+ if (!st->codecpar->profile)
+ profile_and_level |= 0x80; // escape bit
+ avio_w8(pb, profile_and_level);
- // low delay
- mxf_write_local_tag(s, 1, 0x8003);
- avio_w8(pb, sc->low_delay);
+ // low delay
+ mxf_write_local_tag(s, 1, 0x8003);
+ avio_w8(pb, sc->low_delay);
- // closed gop
- mxf_write_local_tag(s, 1, 0x8004);
- avio_w8(pb, sc->seq_closed_gop);
+ // closed gop
+ mxf_write_local_tag(s, 1, 0x8004);
+ avio_w8(pb, sc->seq_closed_gop);
- // max gop
- mxf_write_local_tag(s, 2, 0x8006);
- avio_wb16(pb, sc->max_gop);
+ // max gop
+ mxf_write_local_tag(s, 2, 0x8006);
+ avio_wb16(pb, sc->max_gop);
- // b picture count
- mxf_write_local_tag(s, 2, 0x8008);
- avio_wb16(pb, sc->b_picture_count);
- }
+ // b picture count
+ mxf_write_local_tag(s, 2, 0x8008);
+ avio_wb16(pb, sc->b_picture_count);
- mxf_update_klv_size(pb, pos);
return 0;
}
@@ -2606,9 +2585,10 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
sc->codec_ul = codec_ul;
- if (!avc_intra) {
+ if (avc_intra)
+ sc->picture_descriptor_key = &mxf_mpegvideo_descriptor_key;
+ else
sc->sub_descriptor = AVCSubDescriptor;
- }
return 1;
}
@@ -2639,6 +2619,7 @@ static int mxf_parse_ffv1_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
{
MXFContext *mxf = s->priv_data;
MXFStreamContext *sc = st->priv_data;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(st->codecpar->format);
uint8_t state[FFV1_CONTEXT_SIZE];
RangeCoder c;
unsigned v;
@@ -2679,6 +2660,9 @@ static int mxf_parse_ffv1_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
av_reduce(&sc->aspect_ratio.num, &sc->aspect_ratio.den,
sc->aspect_ratio.num, sc->aspect_ratio.den, INT_MAX);
+ if (pix_desc->flags & AV_PIX_FMT_FLAG_RGB)
+ sc->picture_descriptor_key = &mxf_rgba_descriptor_key;
+
return 1;
}
@@ -2828,6 +2812,7 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st,
if (!codec_ul)
return 0;
sc->codec_ul = codec_ul;
+ sc->picture_descriptor_key = &mxf_mpegvideo_descriptor_key;
}
return 1;
}
@@ -2968,6 +2953,7 @@ static int mxf_init(AVFormatContext *s)
sc->seq_closed_gop = -1; // unknown yet
}
+ sc->picture_descriptor_key = &mxf_cdci_descriptor_key;
sc->video_bit_rate = st->codecpar->bit_rate;
if (IS_D10(s) ||
--
2.49.1
From 2401bddbf00829a51a7964fc856cf52f7b70f1a8 Mon Sep 17 00:00:00 2001
From: Baptiste Coudurier <baptiste.coudurier@gmail.com>
Date: Wed, 4 Jun 2025 00:01:44 -0700
Subject: [PATCH 7/7] lavf/mxfenc: fix muxing for DNxHD/DNxHR 444
---
libavformat/mxfenc.c | 70 ++++++++++++++++++++++++++++++++++----------
1 file changed, 55 insertions(+), 15 deletions(-)
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 8cd92b980c..12ef521779 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -121,6 +121,7 @@ typedef struct MXFStreamContext {
j2k_info_t j2k_info;
enum MXFMetadataSetType sub_descriptor;
const UID *picture_descriptor_key;
+ int cid; ///< compression id, used by dnxhd
} MXFStreamContext;
typedef struct MXFContainerEssenceEntry {
@@ -289,6 +290,8 @@ static const uint8_t header_closed_partition_key[] = { 0x06,0x0E,0x2B,0x34,0x02,
static const uint8_t klv_fill_key[] = { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x01,0x02,0x10,0x01,0x00,0x00,0x00 };
static const uint8_t body_partition_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x03,0x04,0x00 }; // ClosedComplete
+static const UID mxf_rgba_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x29,0x00 };
+
/**
* partial key for header metadata
*/
@@ -390,6 +393,10 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x3304, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x03,0x03,0x00,0x00,0x00}}, /* Black Ref level */
{ 0x3305, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x03,0x04,0x00,0x00,0x00}}, /* White Ref level */
{ 0x3306, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x05,0x03,0x05,0x00,0x00,0x00}}, /* Color Range */
+ // RGBA Picture Essence Descriptor
+ { 0x3401, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x05,0x03,0x06,0x00,0x00,0x00}}, /* Pixel Layout */
+ { 0x3406, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x05,0x03,0x0B,0x00,0x00,0x00}}, /* Component Max Ref */
+ { 0x3407, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x05,0x03,0x0C,0x00,0x00,0x00}}, /* Component Min Ref */
// Generic Sound Essence Descriptor
{ 0x3D02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x04,0x02,0x03,0x01,0x04,0x00,0x00,0x00}}, /* Locked/Unlocked */
{ 0x3D03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x01,0x01,0x01,0x00,0x00}}, /* Audio sampling rate */
@@ -585,27 +592,31 @@ static void mxf_write_primer_pack(AVFormatContext *s)
AVIOContext *pb = s->pb;
int local_tag_number = MXF_NUM_TAGS, i;
int will_have_avc_tags = 0, will_have_mastering_tags = 0, will_have_ffv1_tags = 0, will_have_jpeg2000_tags = 0;
- int will_have_sub_descriptor = 0;
+ int will_have_sub_descriptor = 0, will_have_rgba_descriptor = 0;
for (i = 0; i < s->nb_streams; i++) {
- MXFStreamContext *sc = s->streams[i]->priv_data;
- if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 && sc->sub_descriptor) {
+ AVStream *st = s->streams[i];
+ MXFStreamContext *sc = st->priv_data;
+ if (st->codecpar->codec_id == AV_CODEC_ID_H264 && sc->sub_descriptor) {
will_have_avc_tags = 1;
}
- if (av_packet_side_data_get(s->streams[i]->codecpar->coded_side_data,
- s->streams[i]->codecpar->nb_coded_side_data,
+ if (av_packet_side_data_get(st->codecpar->coded_side_data,
+ st->codecpar->nb_coded_side_data,
AV_PKT_DATA_MASTERING_DISPLAY_METADATA)) {
will_have_mastering_tags = 1;
}
- if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_FFV1) {
+ if (st->codecpar->codec_id == AV_CODEC_ID_FFV1) {
will_have_ffv1_tags = 1;
}
- if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_JPEG2000){
+ if (st->codecpar->codec_id == AV_CODEC_ID_JPEG2000) {
will_have_jpeg2000_tags = 1;
}
if (sc->sub_descriptor) {
will_have_sub_descriptor = 1;
}
+ if (sc->picture_descriptor_key == &mxf_rgba_descriptor_key) {
+ will_have_rgba_descriptor = 1;
+ }
}
if (!mxf->store_user_comments) {
@@ -618,6 +629,12 @@ static void mxf_write_primer_pack(AVFormatContext *s)
mxf_mark_tag_unused(mxf, 0x8100);
}
+ if (!will_have_rgba_descriptor) {
+ mxf_mark_tag_unused(mxf, 0x3401);
+ mxf_mark_tag_unused(mxf, 0x3406);
+ mxf_mark_tag_unused(mxf, 0x3407);
+ }
+
if (!will_have_avc_tags) {
mxf_mark_tag_unused(mxf, 0x8200);
mxf_mark_tag_unused(mxf, 0x8201);
@@ -1190,7 +1207,6 @@ static const UID mxf_mpegvideo_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,
static const UID mxf_wav_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 };
static const UID mxf_aes3_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 };
static const UID mxf_cdci_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x28,0x00 };
-static const UID mxf_rgba_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x29,0x00 };
static const UID mxf_generic_sound_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x42,0x00 };
static const UID mxf_avc_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6E,0x00 };
@@ -1222,6 +1238,7 @@ static int64_t mxf_write_generic_picture_desc(AVFormatContext *s, AVStream *st)
const MXFCodecUL *color_space_ul;
int64_t pos = mxf_write_generic_desc(s, st, *sc->picture_descriptor_key);
const AVPacketSideData *side_data;
+ int component_depth = pix_desc->comp[0].depth;
color_primaries_ul = mxf_get_codec_ul_by_id(ff_mxf_color_primaries_uls, st->codecpar->color_primaries);
color_trc_ul = mxf_get_codec_ul_by_id(ff_mxf_color_trc_uls, st->codecpar->color_trc);
@@ -1236,6 +1253,10 @@ static int64_t mxf_write_generic_picture_desc(AVFormatContext *s, AVStream *st)
display_width = stored_width;
switch (st->codecpar->codec_id) {
+ case AV_CODEC_ID_DNXHD:
+ if (sc->cid < 1270) // DNxHD
+ break;
+ // fall for DNxHR RI rasters
case AV_CODEC_ID_MPEG2VIDEO:
case AV_CODEC_ID_H264:
//Based on 16x16 macroblocks
@@ -1313,8 +1334,25 @@ static int64_t mxf_write_generic_picture_desc(AVFormatContext *s, AVStream *st)
avio_wb32(pb, -((st->codecpar->height - display_height)&1));
}
- if (sc->picture_descriptor_key != &mxf_rgba_descriptor_key) {
- int component_depth = pix_desc->comp[0].depth;
+ if (sc->picture_descriptor_key == &mxf_rgba_descriptor_key) {
+ uint8_t rgb_layout[16] = {
+ 'R', component_depth,
+ 'G', component_depth,
+ 'B', component_depth,
+ };
+
+ // pixel layout
+ mxf_write_local_tag(s, 16, 0x3401);
+ avio_write(pb, rgb_layout, 16);
+
+ // component max ref
+ mxf_write_local_tag(s, 4, 0x3406);
+ avio_wb32(pb, (1<<component_depth) - 1);
+
+ // component min ref
+ mxf_write_local_tag(s, 4, 0x3407);
+ avio_wb32(pb, 0);
+ } else {
int h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
int v_chroma_sub_sample = 1 << pix_desc->log2_chroma_h;
int color_siting;
@@ -1393,7 +1431,6 @@ static int64_t mxf_write_generic_picture_desc(AVFormatContext *s, AVStream *st)
f1 *= 2;
}
-
mxf_write_local_tag(s, 16, 0x320D);
avio_wb32(pb, 2);
avio_wb32(pb, 4);
@@ -2323,7 +2360,7 @@ static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt
{
MXFContext *mxf = s->priv_data;
MXFStreamContext *sc = st->priv_data;
- int i, cid;
+ int i;
if (mxf->header_written)
return 1;
@@ -2331,9 +2368,9 @@ static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt
if (pkt->size < 43)
return 0;
- cid = AV_RB32(pkt->data + 0x28);
+ sc->cid = AV_RB32(pkt->data + 0x28);
for (i = 0; i < FF_ARRAY_ELEMS(mxf_dnxhd_codec_uls); i++) {
- if (cid == mxf_dnxhd_codec_uls[i].cid) {
+ if (sc->cid == mxf_dnxhd_codec_uls[i].cid) {
sc->codec_ul = &mxf_dnxhd_codec_uls[i].codec_ul;
sc->interlaced = mxf_dnxhd_codec_uls[i].interlaced;
break;
@@ -2342,7 +2379,7 @@ static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt
if (i == FF_ARRAY_ELEMS(mxf_dnxhd_codec_uls))
return 0;
- if (cid >= 1270) { // RI raster
+ if (sc->cid >= 1270) { // RI raster
av_reduce(&sc->aspect_ratio.num, &sc->aspect_ratio.den,
st->codecpar->width, st->codecpar->height,
INT_MAX);
@@ -2352,6 +2389,9 @@ static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt
sc->frame_size = pkt->size;
+ if (sc->cid == 1270 || sc->cid == 1256)
+ sc->picture_descriptor_key = &mxf_rgba_descriptor_key;
+
return 1;
}
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-10-16 0:22 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-16 0:21 [FFmpeg-devel] [PATCH] Fix jpeg2k and dnxhr 444 MXF and MOV muxing (PR #20711) Baptiste Coudurier via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git