[FFmpeg-soc] [soc]: r2802 - mxf/mxfenc.c
spyfeng
subversion at mplayerhq.hu
Wed Jul 16 18:39:42 CEST 2008
Author: spyfeng
Date: Wed Jul 16 18:39:42 2008
New Revision: 2802
Log:
add file mxfenc.c for maintaince, debug, as base
Added:
mxf/mxfenc.c
Added: mxf/mxfenc.c
==============================================================================
--- (empty file)
+++ mxf/mxfenc.c Wed Jul 16 18:39:42 2008
@@ -0,0 +1,930 @@
+/*
+ * MXF muxer.
+ * Copyright (c) 2008 GUCAS, Zhentan Feng<spyfeng at gmail dot com>.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * References
+ * SMPTE 336M KLV Data Encoding Protocol Using Key-Length-Value
+ * SMPTE 377M MXF File Format Specifications
+ * SMPTE 379M MXF Generic Container
+ * SMPTE 381M Mapping MPEG Streams into the MXF Generic Container
+ * SMPTE RP210: SMPTE Metadata Dictionary
+ * SMPTE RP224: Registry of SMPTE Universal Labels
+ */
+
+#define DEBUG
+
+#include "libavutil/random.h"
+#include "avformat.h"
+#include "libavcodec/bytestream.h"
+
+typedef uint8_t UID[16];
+typedef uint8_t UMID[32];
+
+enum MXFMetadataSetType {
+ MaterialPackage,
+ SourcePackage,
+};
+
+typedef struct {
+ UID key;
+ offset_t offset;
+ uint64_t length;
+} KLVPacket;
+
+typedef struct {
+ UID uid;
+ unsigned matching_len;
+ enum CodecID id;
+} MXFCodecUL;
+
+typedef struct {
+ int local_tag;
+ UID uid;
+} MXFLocalTagPair;
+
+typedef struct {
+ UID uid;
+ enum CodecType type;
+} MXFDataDefinitionUL;
+
+typedef struct {
+ UID uid;
+ enum CodecID type;
+} MXFEssenceElementKey;
+
+typedef struct {
+ UID *identification;
+ UID *content_storage;
+ UID *essence_container;
+ UID *package;
+ UID *track;
+ UID **sequence;
+ UID **structural_component;
+} MXFReferenceContext;
+
+static const uint8_t umid_base[] = {0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x13, 0x00, 0x00, 0x00};//16 bytes
+
+/* complete key */
+static const uint8_t op1a_ul[] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00 };
+static const uint8_t header_partition_key[] = { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00 };//ClosedComplete
+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 MXFEssenceElementKey mxf_essence_element_key[] = {
+ { { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00}, CODEC_ID_MPEG2VIDEO},
+ { { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x16,0x01,0x01,0x00}, CODEC_ID_PCM_S16LE},
+ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, CODEC_ID_NONE},
+};
+
+/* partial key for header metadata */
+static const uint8_t header_metadata_key[] = {0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01};//13 bytes
+
+/* SMPTE RP224 http://www.smpte-ra.org/mdd/index.html */
+static const MXFDataDefinitionUL mxf_data_definition_uls[] = {
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x02,0x01,0x00,0x00,0x00 }, CODEC_TYPE_VIDEO },
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x02,0x02,0x00,0x00,0x00 }, CODEC_TYPE_AUDIO },
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x05,0x01,0x03,0x02,0x02,0x02,0x02,0x00,0x00 }, CODEC_TYPE_AUDIO },
+ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, CODEC_TYPE_DATA },
+};
+
+
+static const MXFCodecUL mxf_picture_essence_container_uls[] = {
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */
+// { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, CODEC_ID_DVVIDEO }, /* DV 625 25mbps */
+// { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE },
+};
+
+/* SMPTE RP210 http://www.smpte-ra.org/mdd/index.html */
+static const MXFLocalTagPair mxf_local_tag_batch[] = {
+ //preface set
+ { 0x3C0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x01,0x01,0x15,0x02,0x00,0x00,0x00,0x00}},/* Instance UID */
+ { 0x3B02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x02,0x04,0x00,0x00}},/* Last Modified Date */
+ { 0x3B05, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x01,0x02,0x01,0x05,0x00,0x00,0x00}},/* Version */
+ { 0x3B06, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x06,0x04,0x00,0x00}},/* Identifications reference */
+ { 0x3B03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x02,0x01,0x00,0x00}},/* Content Storage reference */
+ { 0x3B09, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x01,0x02,0x02,0x03,0x00,0x00,0x00,0x00}},/* Operational Pattern UL */
+ { 0x3B0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x01,0x02,0x02,0x10,0x02,0x01,0x00,0x00}},/* Essence Containers UL batch */
+ { 0x3B0B, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x01,0x02,0x02,0x10,0x02,0x02,0x00,0x00}},/* DM Schemes UL batch */
+ //Identification
+ {0x3C09, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x01,0x00,0x00,0x00}},/* This Generation UID */
+ {0x3C01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x02,0x01,0x00,0x00}},/* Company Name */
+ {0x3C02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x03,0x01,0x00,0x00}},/* Product Name */
+ {0x3C04, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x04,0x00,0x00,0x00}},/* Version String */
+ {0x3C05, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x07,0x00,0x00,0x00}},/* Product ID */
+ {0x3C06, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x02,0x03,0x00,0x00}},/* Modification Date */
+ //Content Storage
+ {0x1901, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x05,0x01,0x00,0x00}},/* Package strong reference batch */
+ //Essence Container Data
+ {0x2701, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x06,0x01,0x00,0x00,0x00}},/* Linked Package UID */
+ {0x3F07, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x01,0x03,0x04,0x04,0x00,0x00,0x00,0x00}},/* BodySID */
+ //Package
+ {0x4401, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x01,0x01,0x15,0x10,0x00,0x00,0x00,0x00}},/* Package UID */
+ {0x4405, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x01,0x03,0x00,0x00}},/* Package Creation Date */
+ {0x4404, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x02,0x05,0x00,0x00}},/* Package Modified Date */
+ {0x4403, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x06,0x05,0x00,0x00}},/* Tracks Strong reference array */
+ //Track
+ {0x4801, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x01,0x07,0x01,0x01,0x00,0x00,0x00,0x00}},/* Track ID */
+ {0x4804, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x01,0x03,0x00,0x00}},/* Track Numberr */
+ {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 */
+ //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 */
+ {0x1001, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x06,0x09,0x00,0x00}},/* Structural Components reference array */
+ //Source Clip
+ {0x1201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x07,0x02,0x01,0x03,0x01,0x0A,0x00,0x00}},/* Start position */
+ {0x1101, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x03,0x01,0x00,0x00,0x00}},/* SourcePackageID */
+ {0x1102, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x03,0x02,0x00,0x00,0x00}},/* SourceTrackID */
+};
+
+typedef struct MXFContext {
+ UMID top_sour_package_uid;
+ int64_t header_byte_count;
+ int64_t header_start;
+ int64_t header_byte_count_offset;
+ int64_t header_footer_partition_offset;
+ AVRandomState random_state;
+ MXFReferenceContext *reference;
+ char track_number_sign[sizeof(mxf_essence_element_key)];
+ UID *track_essence_element_key;
+} MXFContext;
+
+#define PRINT_KEY(pc, s, x) dprintf(pc, "%s %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", s, \
+ (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5], (x)[6], (x)[7], (x)[8], (x)[9], (x)[10], (x)[11], (x)[12], (x)[13], (x)[14], (x)[15])
+static void mxf_generate_uuid(AVFormatContext *s, UID uuid)
+{
+ MXFContext *mxf = s->priv_data;
+ int rand_num, i;
+
+ for (i = 0; i < 16; i++) {
+ rand_num = av_random(&mxf->random_state);
+ rand_num = rand_num%256 + 1;
+
+ //the 7th byte is version according to ISO 11578
+ if (i == 6) {
+ rand_num &= 0x0f;
+ rand_num |= 0x40;
+ }
+
+ //the 8th byte is variant for current use according to ISO 11578
+ if (i == 8) {
+ rand_num &= 0x3f;
+ rand_num |= 0x80;
+ }
+ bytestream_put_byte(&uuid, rand_num);
+ }
+}
+
+static void mxf_generate_umid(AVFormatContext *s, UMID umid)
+{
+ memcpy(umid, umid_base, 16);
+ mxf_generate_uuid(s, umid + 16);
+}
+
+static int mxf_generate_reference(AVFormatContext *s, UID *refs, int ref_count)
+{
+ int i;
+ UID *p;
+ refs = av_mallocz(ref_count * sizeof(UID));
+ if (!refs)
+ return -1;
+ p = refs;
+ for (i = 0; i < ref_count; i++) {
+ mxf_generate_uuid(s, *p);
+ p ++;
+ }
+ p = 0;
+ return 0;
+}
+
+static int klv_encode_ber_length(ByteIOContext *pb, uint64_t len)
+{
+ // Determine the best BER size
+ int size = 0, i;
+ if (len < 128) {
+ //short form
+ size = 1;
+ put_byte(pb, len);
+ return size;
+ }
+
+ while (len /= 256)
+ size ++;
+
+ //long form
+ put_byte(pb, 0x80 + (size - 1));
+ i = size - 1;
+ while(i) {
+ put_byte(pb, len & 0xff);
+ len >>= 8;
+ i--;
+ }
+ return size;
+}
+
+static int mxf_write_primer_pack(AVFormatContext *s)
+{
+ ByteIOContext *pb = s->pb;
+ const MXFLocalTagPair *local_tag_batch;
+ int i,local_tag_number = 0;
+
+ local_tag_number = sizeof(mxf_local_tag_batch) / 20;
+
+ //write key and length
+ put_buffer(pb, primer_pack_key, 16);
+ klv_encode_ber_length(pb, local_tag_number * 18 + 8);
+
+ //write value
+ put_be32(pb, local_tag_number);//local_tag num
+ put_be32(pb, 18);//item size, always 18 according to the specs
+
+ for (local_tag_batch = mxf_local_tag_batch; i < local_tag_number; local_tag_batch++, i++) {
+ put_be16(pb, local_tag_batch->local_tag);
+ put_buffer(pb, local_tag_batch->uid, 16);
+ }
+ return 0;
+}
+
+static int mxf_write_local_tag(ByteIOContext *pb, int value_size, int tag)
+{
+ put_be16(pb, tag);
+ put_be16(pb, value_size);
+ return 0;
+}
+
+static int mxf_write_reference(ByteIOContext *pb, int ref_count, UID *value)
+{
+ put_be32(pb, ref_count);
+ put_be32(pb, 16);
+ put_buffer(pb, *value, 16 * ref_count);
+ return 0;
+}
+
+static int utf8len(const uint8_t *b){
+ int len=0;
+ int val;
+ while(*b){
+ GET_UTF8(val, *b++, return -1;)
+ len++;
+ }
+ return len;
+}
+
+static void mxf_free_refs(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ int i;
+
+ av_freep(&mxf->reference->identification);
+ av_freep(&mxf->reference->content_storage);
+ av_freep(&mxf->reference->package);
+ av_freep(&mxf->reference->track);
+ for (i = 0; i < s->nb_streams; i++) {
+ av_freep(&mxf->reference->sequence[i]);
+ av_freep(&mxf->reference->structural_component[i]);
+ }
+ av_freep(&mxf->reference->sequence);
+ av_freep(&mxf->reference->structural_component);
+}
+
+static const MXFDataDefinitionUL *mxf_get_data_definition_ul(const MXFDataDefinitionUL *uls, enum CodecType type)
+{
+ while (uls->type != CODEC_TYPE_DATA) {
+ if (type == uls->type)
+ break;
+ uls ++;
+ }
+ return uls;
+}
+
+static int mxf_write_preface(AVFormatContext *s, KLVPacket *klv)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFReferenceContext *set_ref = mxf->reference;
+ UID uid;
+ ByteIOContext *pb = s->pb;
+ ByteIOContext *dyn_bc;
+ uint8_t *dyn_buf=NULL;
+ int dyn_size;
+
+ int ret = url_open_dyn_buf(&dyn_bc);
+ if(ret < 0)
+ return ret;
+
+ //write preface set uid
+ mxf_generate_uuid(s, uid);
+ mxf_write_local_tag(dyn_bc, 16, 0x3C0A);
+ put_buffer(dyn_bc, uid, 16);
+
+#ifdef DEBUG
+ PRINT_KEY(s, "preface uid", uid);
+#endif
+
+ //write create date as unknown
+ mxf_write_local_tag(dyn_bc, 8, 0x3B02);
+ put_buffer(dyn_bc, 0, 8);
+
+ //write version
+ mxf_write_local_tag(dyn_bc, 2, 0x3B05);
+ put_be16(dyn_bc, 1);
+
+ //write identification_refs
+ if (mxf_generate_reference(s, set_ref->identification, 1) < 0)
+ return -1;
+ mxf_write_local_tag(dyn_bc, 16 + 8, 0x3B06);
+ mxf_write_reference(dyn_bc, 1, set_ref->identification);
+
+ //write content_storage_refs
+ if (mxf_generate_reference(s, set_ref->content_storage, 1) < 0)
+ return -1;
+ mxf_write_local_tag(dyn_bc, 16, 0x3B03);
+ put_buffer(dyn_bc, *set_ref->content_storage, 16);
+
+ mxf_write_local_tag(dyn_bc, 16, 0x3B09);
+ put_buffer(dyn_bc, op1a_ul, 16);
+
+ //write essence_container_refs
+ if (mxf_generate_reference(s, set_ref->essence_container, 1) < 0)
+ return -1;
+ mxf_write_local_tag(dyn_bc, 16 + 8, 0x3B0A);
+ mxf_write_reference(dyn_bc, 1, set_ref->essence_container);
+
+ //write dm_scheme_refs
+ mxf_write_local_tag(dyn_bc, 8, 0x3B0B);
+ put_be64(dyn_bc, 0);
+
+ dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf);
+
+ //write KLV
+ klv->key[13] = 0x01;
+ klv->key[14] = 0x2f;
+ klv->key[15] = 0x00;
+
+ put_buffer(pb, klv->key, 16);
+ klv_encode_ber_length(pb, dyn_size);
+ put_buffer(pb, dyn_buf, dyn_size);
+
+ av_free(dyn_buf);
+ return 0;
+}
+
+static int mxf_write_identification(AVFormatContext *s, KLVPacket *klv)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFReferenceContext *set_ref = mxf->reference;
+ ByteIOContext *pb = s->pb;
+ UID uid;
+ ByteIOContext *dyn_bc;
+ uint8_t *dyn_buf=NULL;
+ int dyn_size, company_name_len, product_name_len, version_string_len;
+
+ int ret = url_open_dyn_buf(&dyn_bc);
+ if(ret < 0)
+ return ret;
+
+ company_name_len = utf8len("FFmpeg") + 1;
+ product_name_len = utf8len("OP1a Muxer") + 1;
+ version_string_len = utf8len("version 0.0.1") + 1;
+
+ //write uid
+ mxf_write_local_tag(dyn_bc, 16, 0x3C0A);
+ put_buffer(dyn_bc, *set_ref->identification, 16);
+
+ //write generation uid
+ mxf_generate_uuid(s, uid);
+ mxf_write_local_tag(dyn_bc, 16, 0x3C09);
+ put_buffer(dyn_bc, uid, 16);
+
+ mxf_write_local_tag(dyn_bc, company_name_len, 0x3C01);
+ put_buffer(dyn_bc, "FFmpeg", company_name_len);
+
+ mxf_write_local_tag(dyn_bc, product_name_len, 0x3C02);
+ put_buffer(dyn_bc, "OP1a Muxer", product_name_len);
+
+ mxf_write_local_tag(dyn_bc, version_string_len, 0x3C04);
+ put_buffer(dyn_bc, "version 0.0.1", version_string_len);
+
+ //write product uid
+ mxf_generate_uuid(s, uid);
+ mxf_write_local_tag(dyn_bc, 16, 0x3C05);
+ put_buffer(dyn_bc, uid, 16);
+
+ //write modified date
+ mxf_write_local_tag(dyn_bc, 8, 0x3C06);
+ put_buffer(dyn_bc, 0, 8);
+
+ dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf);
+
+ klv->key[13] = 0x01;
+ klv->key[14] = 0x30;
+ klv->key[15] = 0x00;
+
+ put_buffer(pb, klv->key, 16);
+ klv_encode_ber_length(pb, dyn_size);
+ put_buffer(pb, dyn_buf, dyn_size);
+
+ av_free(dyn_buf);
+ return 0;
+}
+
+static int mxf_write_content_storage(AVFormatContext *s, KLVPacket *klv)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFReferenceContext *set_ref = mxf->reference;
+ ByteIOContext *pb = s->pb;
+ ByteIOContext *dyn_bc;
+ uint8_t *dyn_buf=NULL;
+ int dyn_size;
+
+ int ret = url_open_dyn_buf(&dyn_bc);
+ if(ret < 0)
+ return ret;
+
+ //write uid
+ mxf_write_local_tag(dyn_bc, 16, 0x3C0A);
+ put_buffer(dyn_bc, *set_ref->content_storage, 16);
+
+ //write package reference
+ if (mxf_generate_reference(s, set_ref->package, 2) < 0)
+ return -1;
+ mxf_write_local_tag(dyn_bc, 16 * 2 + 8, 0x1901);
+ mxf_write_reference(dyn_bc, 2, set_ref->package);
+
+ klv->key[13] = 0x01;
+ klv->key[14] = 0x18;
+ klv->key[15] = 0x00;
+
+ put_buffer(pb, klv->key, 16);
+ klv_encode_ber_length(pb, dyn_size);
+ put_buffer(pb, dyn_buf, dyn_size);
+
+ av_free(dyn_buf);
+ return 0;
+}
+
+static int mxf_write_package(AVFormatContext *s, KLVPacket *klv, enum MXFMetadataSetType type)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFReferenceContext *set_ref = mxf->reference;
+ ByteIOContext *pb = s->pb;
+ UMID umid;
+ UID *ref;
+ ByteIOContext *dyn_bc;
+ uint8_t *dyn_buf=NULL;
+ int dyn_size;
+
+ int ret = url_open_dyn_buf(&dyn_bc);
+ if(ret < 0)
+ return ret;
+
+ //write uid
+ ref = type == MaterialPackage ? set_ref->package : & set_ref->package[1];
+ mxf_write_local_tag(dyn_bc, 16, 0x3C0A);
+ put_buffer(dyn_bc, *ref, 16);
+
+ //write package umid
+ mxf_write_local_tag(dyn_bc, 32, 0x4401);
+ if (type == MaterialPackage) {
+ mxf_generate_umid(s, umid);
+ put_buffer(dyn_bc, umid, 32);
+ } else {
+ put_buffer(dyn_bc, mxf->top_sour_package_uid, 32);
+ }
+
+ //write create date
+ mxf_write_local_tag(dyn_bc, 8, 0x4405);
+ put_buffer(dyn_bc, 0, 8);
+
+ //write modified date
+ mxf_write_local_tag(dyn_bc, 8, 0x4404);
+ put_buffer(dyn_bc, 0, 8);
+
+ //write track refs
+ if (mxf_generate_reference(s, set_ref->track, s->nb_streams) < 0)
+ return -1;
+ mxf_write_local_tag(dyn_bc, s->nb_streams * 16 + 8, 0x4403);
+ mxf_write_reference(dyn_bc, s->nb_streams, set_ref->track);
+
+ //every track have 1 sequence and 1 structural componet, malloc memory for the refs pointer
+ set_ref->sequence = av_mallocz(s->nb_streams * sizeof(*set_ref->sequence));
+ if (!set_ref->sequence)
+ return -1;
+ set_ref->structural_component = av_mallocz(s->nb_streams * sizeof(*set_ref->structural_component));
+ if (set_ref->structural_component)
+ return -1;
+
+ //malloc memory for essence element key of each track
+ mxf->track_essence_element_key = av_mallocz(s->nb_streams * sizeof(UID));
+ if (!mxf->track_essence_element_key)
+ return -1;
+
+ klv->key[13] = 0x01;
+ klv->key[14] = type == MaterialPackage ? 0x36 : 0x37;
+ klv->key[15] = 0x00;
+
+ put_buffer(pb, klv->key, 16);
+ klv_encode_ber_length(pb, dyn_size);
+ put_buffer(pb, dyn_buf, dyn_size);
+
+ av_free(dyn_buf);
+ return 0;
+}
+
+static int mxf_write_track(AVFormatContext *s, KLVPacket *klv, int stream_index, enum MXFMetadataSetType type)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFReferenceContext *set_ref = mxf->reference;
+ ByteIOContext *pb = s->pb;
+ AVStream *st;
+ const MXFEssenceElementKey *element;
+ int i = 0;
+ ByteIOContext *dyn_bc;
+ uint8_t *dyn_buf=NULL;
+ int dyn_size;
+
+ int ret = url_open_dyn_buf(&dyn_bc);
+ if(ret < 0)
+ return ret;
+
+ st = s->streams[stream_index];
+
+ //set pts information
+ if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
+ av_set_pts_info(st, 64, 1, st->codec->time_base.den);
+ } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
+ av_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ }
+
+ //write track uid
+ mxf_write_local_tag(dyn_bc, 16, 0x3C0A);
+ put_buffer(dyn_bc, set_ref->track[stream_index], 16);
+
+ //write track id
+ mxf_write_local_tag(dyn_bc, 4, 0x4801);
+ put_be32(dyn_bc, stream_index + 1);
+
+ if (type != MaterialPackage) {
+ for (element = mxf_essence_element_key; element->type != CODEC_ID_NONE; element++) {
+ if (st->codec->codec_id== element->type) {
+ //write track number
+ mxf_write_local_tag(dyn_bc, 4, 0x4804);
+ put_buffer(dyn_bc, element->uid + 12, 3);
+ put_byte(dyn_bc, element->uid[15] + mxf->track_number_sign[i]);
+ mxf->track_number_sign[i] ++;
+
+ //set essence_element key
+ memcpy(mxf->track_essence_element_key[stream_index], element->uid, 16);
+ break;
+ }
+ i++;
+ }
+ } else {
+ put_buffer(dyn_bc, 0, 4);//track number of material package is 0
+ }
+
+ mxf_write_local_tag(dyn_bc, 8, 0x4B01);
+ put_be32(dyn_bc, st->time_base.num);
+ put_be32(dyn_bc, st->time_base.den);
+
+ //write origin
+ mxf_write_local_tag(dyn_bc, 8, 0x4B02);
+ put_be64(dyn_bc, 0);
+
+ //write sequence refs
+ if (mxf_generate_reference(s, set_ref->sequence[stream_index], 1) < 0)
+ return -1;
+ mxf_write_local_tag(dyn_bc, 16, 0x4803);
+ put_buffer(dyn_bc, *set_ref->sequence[stream_index], 16);
+
+ //write KLV
+ klv->key[13] = 0x01;
+ klv->key[14] = 0x3b;
+ klv->key[15] = 0x00;
+
+ put_buffer(pb, klv->key, 16);
+ klv_encode_ber_length(pb, dyn_size);
+ put_buffer(pb, dyn_buf, dyn_size);
+
+ av_free(dyn_buf);
+ return 0;
+}
+
+static int mxf_write_sequence(AVFormatContext *s, KLVPacket *klv, int stream_index)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFReferenceContext *set_ref = mxf->reference;
+ ByteIOContext *pb = s->pb;
+ AVStream *st;
+ const MXFDataDefinitionUL * data_def_ul;
+ ByteIOContext *dyn_bc;
+ uint8_t *dyn_buf=NULL;
+ int dyn_size;
+
+ int ret = url_open_dyn_buf(&dyn_bc);
+ if(ret < 0)
+ return ret;
+
+ st = s->streams[stream_index];
+
+ mxf_write_local_tag(dyn_bc, 16, 0x3C0A);
+ put_buffer(dyn_bc, *set_ref->sequence[stream_index], 16);
+
+ //find data define uls
+ data_def_ul = mxf_get_data_definition_ul(mxf_data_definition_uls, st->codec->codec_type);
+ mxf_write_local_tag(dyn_bc, 16, 0x0201);
+ put_buffer(dyn_bc, data_def_ul->uid, 16);
+
+ mxf_write_local_tag(dyn_bc, 8, 0x0202);
+ put_be32(dyn_bc, st->duration);
+
+ //write structural component
+ if (mxf_generate_reference(s, set_ref->structural_component[stream_index], 1) < 0)
+ return -1;
+ mxf_write_local_tag(dyn_bc, 16 + 8, 0x1001);
+ mxf_write_reference(dyn_bc, 1, set_ref->structural_component[stream_index]);
+
+ klv->key[13] = 0x01;
+ klv->key[14] = 0x0f;
+ klv->key[15] = 0x00;
+
+ put_buffer(pb, klv->key, 16);
+ klv_encode_ber_length(pb, dyn_size);
+ put_buffer(pb, dyn_buf, dyn_size);
+
+ av_free(dyn_buf);
+ return 0;
+}
+
+static int mxf_write_structural_component(AVFormatContext *s, KLVPacket *klv, int stream_index, enum MXFMetadataSetType type)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFReferenceContext *set_ref = mxf->reference;
+ ByteIOContext *pb = s->pb;
+ AVStream *st;
+ const MXFDataDefinitionUL * data_def_ul;
+ ByteIOContext *dyn_bc;
+ uint8_t *dyn_buf=NULL;
+ int dyn_size;
+
+ int ret = url_open_dyn_buf(&dyn_bc);
+ if(ret < 0)
+ return ret;
+
+ st = s->streams[stream_index];
+
+ //write uid
+ mxf_write_local_tag(dyn_bc, 16, 0x3C0A);
+ put_buffer(dyn_bc, *set_ref->structural_component[stream_index], 16);
+
+ data_def_ul = mxf_get_data_definition_ul(mxf_data_definition_uls, st->codec->codec_type);
+ mxf_write_local_tag(dyn_bc, 16, 0x0201);
+ put_buffer(dyn_bc, data_def_ul->uid, 16);
+
+ //write start_position
+ mxf_write_local_tag(dyn_bc, 8, 0x1201);
+ put_be64(dyn_bc, 0);
+
+ //write duration
+ mxf_write_local_tag(dyn_bc, 8, 0x0202);
+ put_be64(dyn_bc, st->duration);
+
+ if (type == SourcePackage) {
+ //write source package uid, end of the reference
+ mxf_write_local_tag(pb, 32, 0x1101);
+ put_buffer(dyn_bc, 0, 32);
+
+ //write source track id
+ mxf_write_local_tag(dyn_bc, 4, 0x1102);
+ put_be64(dyn_bc, 0);
+ } else {
+ mxf_write_local_tag(dyn_bc, 32, 0x1101);
+ put_buffer(dyn_bc, mxf->top_sour_package_uid, 32);
+
+ mxf_write_local_tag(dyn_bc, 4, 0x1102);
+ put_be64(dyn_bc, stream_index + 1);
+ }
+
+ klv->key[13] = 0x01;
+ klv->key[14] = 0x11;
+ klv->key[15] = 0x00;
+ put_buffer(pb, klv->key, 16);
+ klv_encode_ber_length(pb, dyn_size);
+ put_buffer(pb, dyn_buf, dyn_size);
+
+ av_free(dyn_buf);
+ return 0;
+}
+
+static int mxf_build_strctural_metadata(AVFormatContext *s, KLVPacket* klv, enum MXFMetadataSetType type)
+{
+ int i;
+
+ if (mxf_write_package(s, klv, type) < 0)
+ return -1;
+
+ for (i = 0;i < s->nb_streams; i++) {
+ if (mxf_write_track(s, klv, i, type) < 0)
+ return -1;
+
+ if (mxf_write_sequence(s, klv, i) < 0)
+ return -1;
+
+ if (mxf_write_structural_component(s, klv, i, type) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static int mxf_write_header_metadata_sets(AVFormatContext *s)
+{
+ KLVPacket klv;
+ memcpy(klv.key, header_metadata_key, 13);
+ if (mxf_write_preface(s, &klv) < 0)
+ return -1;
+
+ if (mxf_write_identification(s,&klv) < 0)
+ return -1;
+
+ if (mxf_write_content_storage(s, &klv) < 0)
+ return -1;
+
+ if (mxf_build_strctural_metadata(s, &klv, MaterialPackage) < 0)
+ return -1;
+
+ if (mxf_build_strctural_metadata(s, &klv, SourcePackage) < 0)
+ return -1;
+ return 0;
+}
+
+static int mxf_write_header_partition(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ ByteIOContext *pb = s->pb;
+ int64_t header_metadata_start;
+ //for op1a, only 1 essence container
+ uint64_t partitionLen = 88 + 16;
+
+ // generate Source Package Set UMID for op1a
+ // will be used by material_package->source_track->sequence->structual_component->source_package_id
+ mxf_generate_umid(s, mxf->top_sour_package_uid);
+
+ //write klv
+ put_buffer(pb, header_partition_key, 16);
+ klv_encode_ber_length(pb, partitionLen);
+
+ //write partition value
+ put_be16(pb, 1);//majorVersion
+ put_be16(pb, 2);//minorVersion
+ put_be32(pb, 1);//kagSize
+
+ put_be64(pb, 0);//thisPartition
+ put_be64(pb, 0);//previousPartition
+
+ //set offset
+ mxf->header_footer_partition_offset = url_ftell(pb);
+ put_be64(pb, 0);//footerPartition,update later
+
+ //set offset
+ mxf->header_byte_count_offset = url_ftell(pb);
+ put_be64(pb, 0);//headerByteCount, update later
+
+ //no indexTable
+ put_be64(pb, 0);//indexByteCount
+ put_be32(pb, 0);//indexSID
+ put_be64(pb, 0);//bodyOffset
+
+ put_be32(pb, 1);//bodySID
+ put_buffer(pb, op1a_ul, 16);//operational pattern
+ put_be32(pb,1);
+ put_be32(pb,16);
+ put_buffer(pb, mxf_picture_essence_container_uls->uid, 16);
+
+ //mark the start of the headermetadata and calculate metadata size
+ header_metadata_start = url_ftell(s->pb);
+ mxf_write_primer_pack(s);
+ if (mxf_write_header_metadata_sets < 0)
+ goto fail;
+ mxf->header_byte_count = url_ftell(s->pb) - header_metadata_start;
+ return 0;
+
+fail:
+ mxf_free_refs(s);
+ return -1;
+}
+
+static int mux_write_header(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ ByteIOContext *pb = s->pb;
+ av_init_random(0xbeefdead, &mxf->random_state);
+
+ //mark the header start position, for some fields update later
+ mxf->header_start = url_ftell(pb);
+ mxf_write_header_partition(s);
+
+ put_flush_packet(pb);
+ return 0;
+}
+
+static int mux_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MXFContext *mxf = s->priv_data;
+ ByteIOContext *pb = s->pb;
+
+ put_buffer(pb, mxf->track_essence_element_key[pkt->stream_index], 16);//write key
+ klv_encode_ber_length(pb, pkt->size);//write length
+ put_buffer(pb, pkt->data, pkt->size);//write value
+
+ put_flush_packet(pb);
+ return 0;
+}
+
+static int mxf_update_header_partition(AVFormatContext *s, int64_t footer_partition_offset)
+{
+ MXFContext *mxf = s->priv_data;
+ ByteIOContext *pb = s->pb;
+
+ url_fseek(pb, mxf->header_byte_count_offset, SEEK_SET);
+ put_be64(pb, mxf->header_byte_count);
+ put_flush_packet(pb);
+
+ url_fseek(pb, mxf->header_footer_partition_offset, SEEK_SET);
+ put_be64(pb, footer_partition_offset);
+ put_flush_packet(pb);
+ return 0;
+}
+
+
+static int mux_write_footer(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ ByteIOContext *pb = s->pb;
+
+ int64_t this_partition = url_ftell(pb) - mxf->header_start;
+ int64_t partitionLen = 88 + 16;
+
+ //write klv
+ put_buffer(pb, footer_partition_key, 16);
+ klv_encode_ber_length(pb, partitionLen);
+
+ //write partition value
+ put_be16(pb, 1);//majorVersion
+ put_be16(pb, 2);//minorVersion
+ put_be32(pb, 1);//kagSize
+
+ put_be64(pb, this_partition);
+ put_be64(pb, 0);//previousPartition
+ put_be64(pb, this_partition);
+ put_be64(pb, 0);//header byte count
+
+ //no indexTable
+ put_be64(pb, 0);//indexByteCount
+ put_be32(pb, 0);//indexSID
+ put_be64(pb, 0);//bodyOffset
+
+ put_be32(pb, 0);//bodySID
+ put_buffer(pb, op1a_ul, 16);//operational pattern
+ put_be32(pb,1);
+ put_be32(pb,16);
+ put_buffer(pb, mxf_picture_essence_container_uls->uid, 16);
+
+ put_flush_packet(pb);
+
+ mxf_update_header_partition(s, this_partition);
+ mxf_free_refs(s);
+ return 0;
+}
+
+AVOutputFormat mxf_muxer = {
+ "mxf",
+ "material exchange file fromat",
+ NULL,
+ "mxf",
+ sizeof(MXFContext),
+ CODEC_ID_PCM_S16LE,
+ CODEC_ID_MPEG2VIDEO,
+ mux_write_header,
+ mux_write_packet,
+ mux_write_footer,
+};
+
+
More information about the FFmpeg-soc
mailing list