[FFmpeg-devel] [PATCH] mfxenc add jpeg2000 frame field interlacing support. SPONSORED BY INA (Institut National de l'Audiovisuel) * the use of a jpeg2000 frame/field input is signaled by the option flag mxf_j2kinterlace * according to smpte 0400-2012, the codec descriptor JPEG2000UndefinedDigitalCinemaProfile is used For comptability with tierce solution used in Digital Cinema industry : * the klv Keys 'TrackName' and those of mxf jpeg2000 picture sub descriptor defined in smpte 422-2014 have been added * option flags 'mxf_nobody' and 'mxf_footer_with_hmd' have been added to rearrange the klv description order according to exploitation constraints
Erwann Renan
erenan at ektacom.com
Thu Oct 28 17:23:43 EEST 2021
---
libavformat/mxf.h | 1 +
libavformat/mxfenc.c | 371 +++++++++++++++++++++++++++++++++++++++++--
2 files changed, 361 insertions(+), 11 deletions(-)
diff --git a/libavformat/mxf.h b/libavformat/mxf.h
index fe9c52732c..2ce637d4a8 100644
--- a/libavformat/mxf.h
+++ b/libavformat/mxf.h
@@ -50,6 +50,7 @@ enum MXFMetadataSetType {
TaggedValue,
TapeDescriptor,
AVCSubDescriptor,
+ JPEG2000SubDescriptor,
};
enum MXFFrameLayout {
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index c36ebef932..5b8ec60358 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -99,6 +99,7 @@ typedef struct MXFStreamContext {
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;
+ char * pcTrackName;
} MXFStreamContext;
typedef struct MXFContainerEssenceEntry {
@@ -151,6 +152,7 @@ static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st);
+static void mxf_write_jpeg2000_desc(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 },
@@ -190,6 +192,10 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x08,0x00 },
{ 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 },
mxf_write_cdci_desc },
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0c,0x01,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x08,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x7F },
+ mxf_write_jpeg2000_desc },
// H.264
{ { 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 },
@@ -295,6 +301,8 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x4B01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x30,0x04,0x05,0x00,0x00,0x00,0x00}}, /* Edit Rate */
{ 0x4B02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x03,0x01,0x03,0x00,0x00}}, /* Origin */
{ 0x4803, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x02,0x04,0x00,0x00}}, /* Sequence reference */
+ // Track name
+ { 0x4802, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x01,0x07,0x01,0x02,0x01,0x00,0x00,0x00}}, /* TrackName */
// Sequence
{ 0x0201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x07,0x01,0x00,0x00,0x00,0x00,0x00}}, /* Data Definition UL */
{ 0x0202, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x02,0x01,0x01,0x03,0x00,0x00}}, /* Duration */
@@ -386,6 +394,20 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x8302, FF_MXF_MasteringDisplayWhitePointChromaticity },
{ 0x8303, FF_MXF_MasteringDisplayMaximumLuminance },
{ 0x8304, FF_MXF_MasteringDisplayMinimumLuminance },
+ // 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}}, /* 2 bytes : 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}}, /* 4 bytes : Width of the reference grid */
+ { 0x8403, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x03,0x00,0x00,0x00}}, /* 4 bytes : Height of the reference grid */
+ { 0x8404, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x04,0x00,0x00,0x00}}, /* 4 bytes : Horizontal offset from the origin of the reference grid to the left side of the image area */
+ { 0x8405, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x05,0x00,0x00,0x00}}, /* 4 bytes : Vertical offset from the origin of the reference grid to the left side of the image area */
+ { 0x8406, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x06,0x00,0x00,0x00}}, /* 4 bytes : Width of one reference tile with respect to the reference grid, */
+ { 0x8407, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x07,0x00,0x00,0x00}}, /* 4 bytes : Height of one reference tile with respect to the reference grid, */
+ { 0x8408, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x08,0x00,0x00,0x00}}, /* 4 bytes : Horizontal offset from the origin of the reference grid to the left side of the first tile */
+ { 0x8409, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x09,0x00,0x00,0x00}}, /* 4 bytes : Vertical offset from the origin of the reference grid to the left side of the first tile */
+ { 0x840A, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x0A,0x00,0x00,0x00}}, /* 2 bytes : The number of components in the picture */
+ { 0x840B, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x0B,0x00,0x00,0x00}}, /* 8+3n bytes : Array of picture components where each component comprises 3 bytes named Ssizi, XRSizi, YRSizi The array of 3-byte groups is preceded by the array header comprising a 4-byte value of the number of components followed by a 4-byte value of �3�. */
+ { 0x840C, {0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0a,0x04,0x01,0x06,0x03,0x0E,0x00,0x00,0x00}}, /* The nature and order of the image components in the compressed domain as carried in the J2C codestream.. */
};
#define MXF_NUM_TAGS FF_ARRAY_ELEMS(mxf_local_tag_batch)
@@ -421,6 +443,9 @@ typedef struct MXFContext {
int track_instance_count; // used to generate MXFTrack uuids
int cbr_index; ///< use a constant bitrate index
uint8_t unused_tags[MXF_NUM_TAGS]; ///< local tags that we know will not be used
+ int mxf_nobody;
+ int mxf_j2kinterlace;
+ int footer_with_hmd;
} MXFContext;
static void mxf_write_uuid(AVIOContext *pb, enum MXFMetadataSetType type, int value)
@@ -521,7 +546,7 @@ static void mxf_write_primer_pack(AVFormatContext *s)
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
int local_tag_number = MXF_NUM_TAGS, i;
- int will_have_avc_tags = 0, will_have_mastering_tags = 0;
+ int will_have_avc_tags = 0, will_have_mastering_tags = 0, will_have_jpeg2000_tags = 0;
for (i = 0; i < s->nb_streams; i++) {
MXFStreamContext *sc = s->streams[i]->priv_data;
@@ -531,6 +556,9 @@ static void mxf_write_primer_pack(AVFormatContext *s)
if (av_stream_get_side_data(s->streams[i], AV_PKT_DATA_MASTERING_DISPLAY_METADATA, NULL)) {
will_have_mastering_tags = 1;
}
+ if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_JPEG2000){
+ will_have_jpeg2000_tags = 1;
+ }
}
if (!mxf->store_user_comments) {
@@ -553,6 +581,21 @@ static void mxf_write_primer_pack(AVFormatContext *s)
mxf_mark_tag_unused(mxf, 0x8304);
}
+ if (!will_have_jpeg2000_tags) {
+ mxf_mark_tag_unused(mxf, 0x8401);
+ mxf_mark_tag_unused(mxf, 0x8402);
+ mxf_mark_tag_unused(mxf, 0x8403);
+ mxf_mark_tag_unused(mxf, 0x8404);
+ mxf_mark_tag_unused(mxf, 0x8405);
+ mxf_mark_tag_unused(mxf, 0x8406);
+ mxf_mark_tag_unused(mxf, 0x8407);
+ mxf_mark_tag_unused(mxf, 0x8408);
+ mxf_mark_tag_unused(mxf, 0x8409);
+ mxf_mark_tag_unused(mxf, 0x840A);
+ mxf_mark_tag_unused(mxf, 0x840B);
+ mxf_mark_tag_unused(mxf, 0x840C);
+ }
+
for (i = 0; i < MXF_NUM_TAGS; i++) {
if (mxf->unused_tags[i]) {
local_tag_number--;
@@ -843,7 +886,28 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, MXFPackage *packag
mxf_write_metadata_key(pb, 0x013b00);
PRINT_KEY(s, "track key", pb->buf_ptr - 16);
- klv_encode_ber_length(pb, 80);
+
+ if (st->codecpar) {
+ static const char * pcTrackName_Video = "Picture" ;
+ static const char * pcTrackName_Audio = "Sound" ;
+ static const char * pcTrackName_Anc = "Ancillary" ;
+ if ( st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO )
+ {
+ //TrackName Video
+ klv_encode_ber_length(pb, 80 + mxf_utf16_local_tag_length(pcTrackName_Video));
+ mxf_write_local_tag_utf16(s, 0x4802 , pcTrackName_Video);
+ } else if ( st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ) {
+ //TrackName Audio
+ klv_encode_ber_length(pb, 80 + mxf_utf16_local_tag_length(pcTrackName_Audio));
+ mxf_write_local_tag_utf16(s, 0x4802, pcTrackName_Audio);
+ } else {
+ //TrackName Ancillary
+ klv_encode_ber_length(pb, 80 + mxf_utf16_local_tag_length(pcTrackName_Anc));
+ mxf_write_local_tag_utf16(s, 0x4802, pcTrackName_Anc);
+ }
+ } else {
+ klv_encode_ber_length(pb, 80);
+ }
// write track uid
mxf_write_local_tag(s, 16, 0x3C0A);
@@ -1092,6 +1156,35 @@ static const UID mxf_cdci_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,
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 };
+static const UID mxf_jpeg2000_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x5A,00 };
+
+static int get_trc(UID ul, enum AVColorTransferCharacteristic trc)
+{
+ switch (trc) {
+ case AVCOL_TRC_GAMMA28 :
+ case AVCOL_TRC_GAMMA22 :
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x01,0x00,0x00}), 16);
+ return 0;
+ case AVCOL_TRC_BT709 :
+ case AVCOL_TRC_SMPTE170M :
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00}), 16);
+ return 0;
+ case AVCOL_TRC_SMPTE240M :
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x03,0x00,0x00}), 16);
+ return 0;
+ case AVCOL_TRC_BT1361_ECG:
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x05,0x00,0x00}), 16);
+ return 0;
+ case AVCOL_TRC_LINEAR :
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x06,0x00,0x00}), 16);
+ return 0;
+ case AVCOL_TRC_SMPTE428 :
+ memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x08,0x04,0x01,0x01,0x01,0x01,0x07,0x00,0x00}), 16);
+ return 0;
+ default:
+ return -1;
+ }
+}
static inline uint16_t rescale_mastering_chroma(AVRational q)
{
@@ -1327,6 +1420,182 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
return pos;
}
+static int64_t mxf_write_jpeg2000_common(AVFormatContext *s, AVStream *st, const UID key)
+{
+ MXFStreamContext *sc = st->priv_data;
+ MXFContext *mxf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int stored_width = st->codecpar->width;
+ int stored_height = st->codecpar->height;
+ int display_height;
+ int f1, f2;
+ UID transfer_ul = {0};
+ int64_t pos = mxf_write_generic_desc(s, st, key);
+ get_trc(transfer_ul, st->codecpar->color_trc);
+
+ mxf_write_local_tag(s, 4, 0x3203);
+ avio_wb32(pb, stored_width);
+ mxf_write_local_tag(s, 4, 0x3202);
+ avio_wb32(pb, stored_height);
+
+ //Sampled width
+ mxf_write_local_tag(s, 4, 0x3205);
+ avio_wb32(pb, st->codecpar->width);
+
+ //Samples height
+ mxf_write_local_tag(s, 4, 0x3204);
+ avio_wb32(pb, st->codecpar->height);
+
+ //Sampled X Offset
+ mxf_write_local_tag(s, 4, 0x3206);
+ avio_wb32(pb, 0);
+
+ //Sampled Y Offset
+ mxf_write_local_tag(s, 4, 0x3207);
+ avio_wb32(pb, 0);
+
+ mxf_write_local_tag(s, 4, 0x3209);
+ avio_wb32(pb, st->codecpar->width);
+
+ if (st->codecpar->height == 608) // PAL + VBI
+ display_height = 576;
+ else if (st->codecpar->height == 512) // NTSC + VBI
+ display_height = 486;
+ else
+ display_height = st->codecpar->height;
+
+ mxf_write_local_tag(s, 4, 0x3208);
+ avio_wb32(pb, display_height);
+
+ // display X offset
+ mxf_write_local_tag(s, 4, 0x320A);
+ avio_wb32(pb, 0);
+
+ //display Y offset
+ mxf_write_local_tag(s, 4, 0x320B);
+ avio_wb32(pb, (st->codecpar->height - display_height));
+
+ if (sc->interlaced) {
+ //Display F2 Offset
+ mxf_write_local_tag(s, 4, 0x3217);
+ avio_wb32(pb, -((st->codecpar->height - display_height)&1));
+ }
+
+ // component depth
+ mxf_write_local_tag(s, 4, 0x3301);
+ avio_wb32(pb, sc->component_depth);
+
+ // horizontal subsampling
+ mxf_write_local_tag(s, 4, 0x3302);
+ avio_wb32(pb, sc->h_chroma_sub_sample);
+
+ // vertical subsampling
+ mxf_write_local_tag(s, 4, 0x3308);
+ avio_wb32(pb, sc->v_chroma_sub_sample);
+
+ // color siting
+ mxf_write_local_tag(s, 1, 0x3303);
+ avio_w8(pb, sc->color_siting);
+
+ // // Padding Bits
+ // mxf_write_local_tag(s, 2, 0x3307);
+ // avio_wb16(pb, 0);
+
+ if (st->codecpar->color_range != AVCOL_RANGE_UNSPECIFIED) {
+ int black = 0,
+ white = (1<<sc->component_depth) - 1,
+ color = (1<<sc->component_depth) - 1;
+ 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;
+ }
+ mxf_write_local_tag(s, 4, 0x3304);
+ avio_wb32(pb, black);
+ mxf_write_local_tag(s, 4, 0x3305);
+ avio_wb32(pb, white);
+ mxf_write_local_tag(s, 4, 0x3306);
+ avio_wb32(pb, color);
+ }
+
+ if (sc->signal_standard) {
+ mxf_write_local_tag(s, 1, 0x3215);
+ avio_w8(pb, sc->signal_standard);
+ }
+
+ // frame layout
+ mxf_write_local_tag(s, 1, 0x320C);
+ avio_w8(pb, sc->interlaced);
+
+ // video line map
+ {
+ int _field_height = (mxf->mxf_j2kinterlace) ? (2*st->codecpar->height) : st->codecpar->height;
+
+ if (st->codecpar->sample_aspect_ratio.num && st->codecpar->sample_aspect_ratio.den) {
+ AVRational _ratio = av_mul_q(st->codecpar->sample_aspect_ratio,
+ av_make_q(st->codecpar->width, st->codecpar->height));
+ sc->aspect_ratio = _ratio;
+
+ switch (_field_height) {
+ case 576: f1 = 23; f2 = st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO ? 335 : 336; break;
+ case 608: f1 = 7; f2 = 320; break;
+ case 480: f1 = 20; f2 = st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO ? 285 : 283; break;
+ case 512: f1 = 7; f2 = 270; break;
+ case 720: f1 = 26; f2 = 0; break; // progressive
+ case 1080: f1 = 21; f2 = 584; break;
+ default: f1 = 0; f2 = 0; break;
+ }
+ } else {
+ switch (_field_height) {
+ case 576: sc->aspect_ratio = (AVRational){ 4, 3}; f1 = 23; f2 = st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO ? 335 : 336; break;
+ case 608: sc->aspect_ratio = (AVRational){ 4, 3}; f1 = 7; f2 = 320; break;
+ case 480: sc->aspect_ratio = (AVRational){ 4, 3}; f1 = 20; f2 = st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO ? 285 : 283; break;
+ case 512: sc->aspect_ratio = (AVRational){ 4, 3}; f1 = 7; f2 = 270; break;
+ case 720: sc->aspect_ratio = (AVRational){ 16, 9}; f1 = 26; f2 = 0; break; // progressive
+ case 1080: sc->aspect_ratio = (AVRational){ 16, 9}; f1 = 21; f2 = 584; break;
+ default: f1 = 0; f2 = 0; break;
+ }
+ }
+ }
+
+ if (!sc->interlaced && f2) {
+ f2 = 0;
+ f1 *= 2;
+ }
+
+ mxf_write_local_tag(s, 16, 0x320D);
+ avio_wb32(pb, 2);
+ avio_wb32(pb, 4);
+ avio_wb32(pb, f1);
+ avio_wb32(pb, f2);
+ mxf_write_local_tag(s, 8, 0x320E);
+ avio_wb32(pb, sc->aspect_ratio.num);
+ avio_wb32(pb, sc->aspect_ratio.den);
+
+ //Transfer characteristic
+ if (transfer_ul[0]) {
+ mxf_write_local_tag(s, 16, 0x3210);
+ avio_write(pb, transfer_ul, 16);
+ }
+
+ mxf_write_local_tag(s, 16, 0x3201);
+ avio_write(pb, *sc->codec_ul, 16);
+
+ mxf_write_local_tag(s, 1, 0x3212);
+ avio_w8(pb, sc->field_dominance);
+
+/* The JPEG 2000 picture sub-descriptor includes only those properties from the main header of the codestream
+that are required in ISO/IEC 15444-1, Annex A, Table A.2. */
+ {
+ // write avc sub descriptor ref
+ mxf_write_local_tag(s, 8 + 16, 0x8400);
+ mxf_write_refs_count(pb, 1);
+ mxf_write_uuid(pb, JPEG2000SubDescriptor, 0);
+ }
+
+ return pos;
+}
+
static void mxf_update_klv_size(AVIOContext *pb, int64_t pos)
{
int64_t cur_pos = avio_tell(pb);
@@ -1360,6 +1629,60 @@ static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st)
mxf_update_klv_size(s->pb, pos);
}
+static void mxf_write_jpeg2000_subdesc(AVFormatContext *s, AVStream *st)
+{
+ AVIOContext *pb = s->pb;
+ int64_t pos;
+
+ int component_count = av_pix_fmt_count_planes(st->codecpar->format);
+
+ avio_write(pb, mxf_jpeg2000_subdescriptor_key, 16);
+ klv_encode_ber4_length(pb, 0);
+ pos = avio_tell(pb);
+
+ mxf_write_local_tag(s, 16, 0x3C0A);
+ mxf_write_uuid(pb, JPEG2000SubDescriptor, 0);
+
+ mxf_write_local_tag(s, 2, 0x8401);
+ avio_wb16(pb, 0x0000);
+ mxf_write_local_tag(s, 4, 0x8402);
+ avio_wb32(pb, st->codecpar->width);
+ mxf_write_local_tag(s, 4, 0x8403);
+ avio_wb32(pb, st->codecpar->height);
+ mxf_write_local_tag(s, 4, 0x8404);
+ avio_wb32(pb, 0);
+ mxf_write_local_tag(s, 4, 0x8405);
+ avio_wb32(pb, 0);
+ mxf_write_local_tag(s, 4, 0x8406);
+ avio_wb32(pb, st->codecpar->width);
+ mxf_write_local_tag(s, 4, 0x8407);
+ avio_wb32(pb, st->codecpar->height);
+ mxf_write_local_tag(s, 4, 0x8408);
+ avio_wb32(pb, 0);
+ mxf_write_local_tag(s, 4, 0x8409);
+ avio_wb32(pb, 0);
+ mxf_write_local_tag(s, 2, 0x840A);
+ avio_wb16(pb, component_count);
+
+ mxf_write_local_tag(s, 8 + 3*component_count, 0x840B);
+ avio_wb32(pb, component_count);
+ avio_wb32(pb, 3);
+ {
+ char _desc [3][3]= { {0x09,0x01,0x01} , {0x09,0x02,0x01} , {0x09,0x02,0x01} };
+ int comp = 0;
+ for ( comp = 0; comp< component_count ;comp++ ) {
+ avio_write(pb, _desc[comp%3] , 3);
+ }
+ }
+ mxf_write_local_tag(s, 16, 0x840C);
+ {
+ char _layout[16] = { 'Y' , '\n', 'U' , '\n', 'V' , '\n', 'F' , 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ avio_write(pb, _layout , 16);
+ }
+ mxf_update_klv_size(pb, pos);
+}
+
static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
{
int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
@@ -1370,6 +1693,12 @@ static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
}
}
+static void mxf_write_jpeg2000_desc(AVFormatContext *s, AVStream *st)
+{
+ int64_t pos = mxf_write_jpeg2000_common(s, st, mxf_cdci_descriptor_key);
+ mxf_update_klv_size(s->pb, pos);
+ mxf_write_jpeg2000_subdesc(s, st);
+}
static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st)
{
MXFStreamContext *sc = st->priv_data;
@@ -1729,7 +2058,7 @@ static int mxf_write_header_metadata_sets(AVFormatContext *s)
static unsigned klv_fill_size(uint64_t size)
{
unsigned pad = KAG_SIZE - (size & (KAG_SIZE-1));
- if (pad < 20) // smallest fill item possible
+ if (pad <= 20) // smallest fill item possible
return pad + KAG_SIZE;
else
return pad & (KAG_SIZE-1);
@@ -2762,7 +3091,13 @@ static void mxf_write_system_item(AVFormatContext *s)
avio_wb64(pb, 0); // creation date/time stamp
avio_w8(pb, 0x81); // SMPTE 12M time code
- time_code = av_timecode_get_smpte_from_framenum(&mxf->tc, frame);
+ if ( 0 == mxf->mxf_j2kinterlace ) {
+ time_code = av_timecode_get_smpte_from_framenum(&mxf->tc, frame);
+ } else {
+ unsigned int _myframenum = frame>>1;
+ time_code = av_timecode_get_smpte_from_framenum(&mxf->tc, _myframenum);
+ }
+
avio_wb32(pb, time_code);
avio_wb32(pb, 0); // binary group data
avio_wb64(pb, 0);
@@ -2928,6 +3263,12 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_ERROR, "could not get h264 profile\n");
return -1;
}
+ } else if (st->codecpar->codec_id == AV_CODEC_ID_JPEG2000) {
+ if (mxf->mxf_j2kinterlace) {
+ st->codecpar->field_order = AV_FIELD_TT;
+ sc->interlaced = 1;
+ sc->field_dominance = 1;
+ }
}
if (mxf->cbr_index) {
@@ -2960,11 +3301,13 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
if (!mxf->edit_unit_byte_count &&
(!mxf->edit_units_count || mxf->edit_units_count > EDIT_UNITS_PER_BODY) &&
!(ie.flags & 0x33)) { // I-frame, GOP start
- mxf_write_klv_fill(s);
- if ((err = mxf_write_partition(s, 1, 2, body_partition_key, 0)) < 0)
- return err;
- mxf_write_klv_fill(s);
- mxf_write_index_table_segment(s);
+ if (!mxf->mxf_nobody) {
+ mxf_write_klv_fill(s);
+ if ((err = mxf_write_partition(s, 1, 2, body_partition_key, 0)) < 0)
+ return err;
+ mxf_write_klv_fill(s);
+ mxf_write_index_table_segment(s);
+ }
}
mxf_write_klv_fill(s);
@@ -3044,10 +3387,10 @@ static int mxf_write_footer(AVFormatContext *s)
mxf_write_klv_fill(s);
mxf->footer_partition_offset = avio_tell(pb);
if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer) { // no need to repeat index
- if ((err = mxf_write_partition(s, 0, 0, footer_partition_key, 0)) < 0)
+ if ((err = mxf_write_partition(s, 0, 0, footer_partition_key, mxf->footer_with_hmd)) < 0)
return err;
} else {
- if ((err = mxf_write_partition(s, 0, 2, footer_partition_key, 0)) < 0)
+ if ((err = mxf_write_partition(s, 0, 2, footer_partition_key, mxf->footer_with_hmd)) < 0)
return err;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
@@ -3198,6 +3541,12 @@ static const AVOption mxf_options[] = {
MXF_COMMON_OPTIONS
{ "store_user_comments", "",
offsetof(MXFContext, store_user_comments), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
+ { "mxf_nobody", "",
+ offsetof(MXFContext, mxf_nobody), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
+ { "mxf_j2kinterlace", "",
+ offsetof(MXFContext, mxf_j2kinterlace), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
+ { "mxf_footer_with_hmd", "",
+ offsetof(MXFContext, footer_with_hmd), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ NULL },
};
--
2.25.1
More information about the ffmpeg-devel
mailing list