[FFmpeg-devel] [PATCH] libavformat/mxfenc.c: added mxf opatom muxer

Mark Reid mindmark at gmail.com
Thu Jan 29 04:44:21 CET 2015


---
 libavformat/allformats.c |   1 +
 libavformat/mxfenc.c     | 139 ++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 127 insertions(+), 13 deletions(-)

diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index bc033ef..ad2e649 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -206,6 +206,7 @@ void av_register_all(void)
     REGISTER_DEMUXER (MVI,              mvi);
     REGISTER_MUXDEMUX(MXF,              mxf);
     REGISTER_MUXER   (MXF_D10,          mxf_d10);
+    REGISTER_MUXER   (MXF_OPATOM,       mxf_opatom);
     REGISTER_DEMUXER (MXG,              mxg);
     REGISTER_DEMUXER (NC,               nc);
     REGISTER_DEMUXER (NISTSPHERE,       nistsphere);
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index a850239..541c2b2 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -52,6 +52,7 @@
 #include "config.h"
 
 extern AVOutputFormat ff_mxf_d10_muxer;
+extern AVOutputFormat ff_mxf_opatom_muxer;
 
 #define EDIT_UNITS_PER_BODY 250
 #define KAG_SIZE 512
@@ -320,6 +321,7 @@ static const uint8_t umid_ul[]              = { 0x06,0x0A,0x2B,0x34,0x01,0x01,0x
  * complete key for operation pattern, partitions, and primer pack
  */
 static const uint8_t op1a_ul[]                     = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x01,0x09,0x00 };
+static const uint8_t opatom_ul[]                   = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x02,0x01,0x10,0x03,0x00,0x00 };
 static const uint8_t footer_partition_key[]        = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x04,0x04,0x00 }; // ClosedComplete
 static const uint8_t primer_pack_key[]             = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x05,0x01,0x00 };
 static const uint8_t index_table_segment_key[]     = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 };
@@ -483,6 +485,12 @@ static void klv_encode_ber4_length(AVIOContext *pb, int len)
     avio_wb24(pb, len);
 }
 
+static void klv_encode_ber9_length(AVIOContext *pb, uint64_t len)
+{
+    avio_w8(pb, 0x80 + 8);
+    avio_wb64(pb, len);
+}
+
 /*
  * Get essence container ul index
  */
@@ -601,7 +609,10 @@ static void mxf_write_preface(AVFormatContext *s)
 
     // operational pattern
     mxf_write_local_tag(pb, 16, 0x3B09);
-    avio_write(pb, op1a_ul, 16);
+    if (s->oformat == &ff_mxf_opatom_muxer)
+        avio_write(pb, opatom_ul, 16);
+    else
+        avio_write(pb, op1a_ul, 16);
 
     // write essence_container_refs
     mxf_write_local_tag(pb, 8 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count), 0x3B0A);
@@ -1362,7 +1373,7 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
         index_byte_count += klv_fill_size(index_byte_count);
     }
 
-    if (!memcmp(key, body_partition_key, 16)) {
+    if (key && !memcmp(key, body_partition_key, 16)) {
         if ((err = av_reallocp_array(&mxf->body_partition_offset, mxf->body_partitions_count + 1,
                                      sizeof(*mxf->body_partition_offset))) < 0) {
             mxf->body_partitions_count = 0;
@@ -1372,7 +1383,11 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
     }
 
     // write klv
-    avio_write(pb, key, 16);
+    if (key)
+        avio_write(pb, key, 16);
+    else
+        avio_write(pb, body_partition_key, 16);
+
     klv_encode_ber_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
 
     // write partition value
@@ -1382,9 +1397,9 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
 
     avio_wb64(pb, partition_offset); // ThisPartition
 
-    if (!memcmp(key, body_partition_key, 16) && mxf->body_partitions_count > 1)
+    if (key && !memcmp(key, body_partition_key, 16) && mxf->body_partitions_count > 1)
         avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-2]); // PreviousPartition
-    else if (!memcmp(key, footer_partition_key, 16) && mxf->body_partitions_count)
+    else if (key && !memcmp(key, footer_partition_key, 16) && mxf->body_partitions_count)
         avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-1]); // PreviousPartition
     else
         avio_wb64(pb, 0);
@@ -1400,15 +1415,18 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
     avio_wb32(pb, index_byte_count ? indexsid : 0); // indexSID
 
     // BodyOffset
-    if (bodysid && mxf->edit_units_count && mxf->body_partitions_count) {
+    if (bodysid && mxf->edit_units_count && mxf->body_partitions_count && s->oformat != &ff_mxf_opatom_muxer)
         avio_wb64(pb, mxf->body_offset);
-    } else
+    else
         avio_wb64(pb, 0);
 
     avio_wb32(pb, bodysid); // bodySID
 
     // operational pattern
-    avio_write(pb, op1a_ul, 16);
+    if (s->oformat == &ff_mxf_opatom_muxer)
+        avio_write(pb, opatom_ul, 16);
+    else
+        avio_write(pb, op1a_ul, 16);
 
     // essence container
     mxf_write_essence_container_refs(s);
@@ -1431,7 +1449,8 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
         avio_seek(pb, pos, SEEK_SET);
     }
 
-    avio_flush(pb);
+    if(key)
+        avio_flush(pb);
 
     return 0;
 }
@@ -1498,6 +1517,11 @@ AVPacket *pkt)
     sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
     sc->aspect_ratio = (AVRational){ 16, 9 };
 
+    if(s->oformat == &ff_mxf_opatom_muxer){
+        mxf->edit_unit_byte_count = frame_size;
+        return 1;
+    }
+
     mxf->edit_unit_byte_count = KAG_SIZE;
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
@@ -1568,6 +1592,11 @@ static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
     sc->index = ul_index + 16;
     sc->codec_ul =  &mxf_essence_container_uls[sc->index].codec_ul;
 
+    if(s->oformat == &ff_mxf_opatom_muxer) {
+        mxf->edit_unit_byte_count = frame_size;
+        return 1;
+    }
+
     mxf->edit_unit_byte_count = KAG_SIZE;
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
@@ -1803,6 +1832,11 @@ static int mxf_write_header(AVFormatContext *s)
     if (!s->nb_streams)
         return -1;
 
+    if (s->oformat == &ff_mxf_opatom_muxer && s->nb_streams !=1){
+        av_log(s, AV_LOG_ERROR, "there must be exactly one stream for mxf opatom\n");
+        return -1;
+    }
+
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
         MXFStreamContext *sc = av_mallocz(sizeof(*sc));
@@ -1901,7 +1935,7 @@ static int mxf_write_header(AVFormatContext *s)
         present[sc->index]++;
     }
 
-    if (s->oformat == &ff_mxf_d10_muxer) {
+    if (s->oformat == &ff_mxf_d10_muxer || s->oformat == &ff_mxf_opatom_muxer) {
         mxf->essence_container_count = 1;
     }
 
@@ -2046,6 +2080,60 @@ static void mxf_write_d10_audio_packet(AVFormatContext *s, AVStream *st, AVPacke
     }
 }
 
+static int mxf_write_opatom_body_partition(AVFormatContext *s)
+{
+    MXFContext *mxf = s->priv_data;
+    AVIOContext *pb = s->pb;
+    AVStream *st = s->streams[0];
+    MXFStreamContext *sc = st->priv_data;
+    const uint8_t *key = NULL;
+
+    int err;
+
+    if (!mxf->header_written)
+        key = body_partition_key;
+
+    if ((err = mxf_write_partition(s, 1, 0, key, 0)) < 0)
+        return err;
+    mxf_write_klv_fill(s);
+    avio_write(pb, sc->track_essence_element_key, 16);
+    klv_encode_ber9_length(pb, mxf->body_offset);
+    return 0;
+}
+
+static int mxf_write_opatom_packet(AVFormatContext *s, AVPacket *pkt, MXFIndexEntry *ie)
+{
+    MXFContext *mxf = s->priv_data;
+    AVIOContext *pb = s->pb;
+    AVStream *st = s->streams[pkt->stream_index];
+    MXFStreamContext *sc = st->priv_data;
+
+    int err;
+
+    if (!mxf->header_written) {
+        if ((err = mxf_write_partition(s, 0, 0, header_open_partition_key, 1)) < 0)
+            return err;
+        mxf_write_klv_fill(s);
+
+        if ((err = mxf_write_opatom_body_partition(s)) < 0)
+            return err;
+        mxf->header_written = 1;
+    }
+
+    if (!mxf->edit_unit_byte_count) {
+        mxf->index_entries[mxf->edit_units_count].offset = mxf->body_offset;
+        mxf->index_entries[mxf->edit_units_count].flags = ie->flags;
+        mxf->index_entries[mxf->edit_units_count].temporal_ref = ie->temporal_ref;
+    }
+    mxf->edit_units_count++;
+    avio_write(pb, pkt->data, pkt->size);
+    mxf->body_offset += pkt->size;
+
+    avio_flush(pb);
+
+    return 0;
+}
+
 static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MXFContext *mxf = s->priv_data;
@@ -2086,6 +2174,9 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
         }
     }
 
+    if (s->oformat == &ff_mxf_opatom_muxer)
+        return mxf_write_opatom_packet(s, pkt, &ie);
+
     if (!mxf->header_written) {
         if (mxf->edit_unit_byte_count) {
             if ((err = mxf_write_partition(s, 1, 2, header_open_partition_key, 1)) < 0)
@@ -2153,7 +2244,7 @@ static void mxf_write_random_index_pack(AVFormatContext *s)
     avio_write(pb, random_index_pack_key, 16);
     klv_encode_ber_length(pb, 28 + 12LL*mxf->body_partitions_count);
 
-    if (mxf->edit_unit_byte_count)
+    if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer)
         avio_wb32(pb, 1); // BodySID of header partition
     else
         avio_wb32(pb, 0);
@@ -2180,7 +2271,7 @@ 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) { // no need to repeat index
+    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)
             return err;
     } else {
@@ -2194,8 +2285,15 @@ static int mxf_write_footer(AVFormatContext *s)
     mxf_write_random_index_pack(s);
 
     if (s->pb->seekable) {
+        if (s->oformat == &ff_mxf_opatom_muxer){
+            /* rewrite body partition to update lengths */
+            avio_seek(pb, mxf->body_partition_offset[0], SEEK_SET);
+            if ((err = mxf_write_opatom_body_partition(s)) < 0)
+                return err;
+        }
+
         avio_seek(pb, 0, SEEK_SET);
-        if (mxf->edit_unit_byte_count) {
+        if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer) {
             if ((err = mxf_write_partition(s, 1, 2, header_closed_partition_key, 1)) < 0)
                 return err;
             mxf_write_klv_fill(s);
@@ -2330,3 +2428,18 @@ AVOutputFormat ff_mxf_d10_muxer = {
     .interleave_packet = mxf_interleave,
     .priv_class        = &mxf_d10_muxer_class,
 };
+
+AVOutputFormat ff_mxf_opatom_muxer = {
+    .name              = "mxf_opatom",
+    .long_name         = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format) Operational Pattern Atom"),
+    .mime_type         = "application/mxf",
+    .extensions        = "mxf",
+    .priv_data_size    = sizeof(MXFContext),
+    .audio_codec       = AV_CODEC_ID_PCM_S16LE,
+    .video_codec       = AV_CODEC_ID_DNXHD,
+    .write_header      = mxf_write_header,
+    .write_packet      = mxf_write_packet,
+    .write_trailer     = mxf_write_footer,
+    .flags             = AVFMT_NOTIMESTAMPS,
+    .interleave_packet = mxf_interleave,
+};
-- 
2.2.1



More information about the ffmpeg-devel mailing list