From 8d54850f33fbd7240934998d43ade3fa732f5537 Mon Sep 17 00:00:00 2001 From: Mark Reid Date: Sat, 14 Mar 2015 17:59:50 -0700 Subject: [PATCH] libavformat/mxfenc: write user comment metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Tomas Härdin Signed-off-by: Michael Niedermayer --- libavformat/mxfenc.c | 66 +++++++++++++++++++++++++++++++++++++-- tests/ref/lavf/mxf | 6 ++-- tests/ref/lavf/mxf_d10 | 2 +- tests/ref/lavf/mxf_opatom | 2 +- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 898951c7b3..0c25499abf 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -312,6 +312,7 @@ typedef struct MXFContext { uint32_t instance_number; uint8_t umid[16]; ///< unique material identifier int channel_count; + uint32_t tagged_value_count; } MXFContext; static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd }; @@ -368,6 +369,7 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { { 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 */ + { 0x4406, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x0C,0x00,0x00,0x00}}, /* User Comments */ { 0x4701, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x02,0x03,0x00,0x00}}, /* Descriptor */ // Track { 0x4801, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x01,0x07,0x01,0x01,0x00,0x00,0x00,0x00}}, /* Track ID */ @@ -387,6 +389,9 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { { 0x1501, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x03,0x01,0x05,0x00,0x00}}, /* Start Time Code */ { 0x1502, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x04,0x01,0x01,0x02,0x06,0x00,0x00}}, /* Rounded Time Code Base */ { 0x1503, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x04,0x01,0x01,0x05,0x00,0x00,0x00}}, /* Drop Frame */ + // Tagged Value + { 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 */ // File Descriptor { 0x3F01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x06,0x01,0x01,0x04,0x06,0x0B,0x00,0x00}}, /* Sub Descriptors reference array */ { 0x3006, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x06,0x01,0x01,0x03,0x05,0x00,0x00,0x00}}, /* Linked Track ID */ @@ -1140,21 +1145,72 @@ static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st) mxf_write_generic_sound_common(s, st, mxf_generic_sound_descriptor_key, 0); } +static const uint8_t mxf_indirect_value_utf16le[] = { 0x4c,0x00,0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 }; + +static int mxf_write_tagged_value(AVFormatContext *s, const char* name, const char* value) +{ + MXFContext *mxf = s->priv_data; + AVIOContext *pb = s->pb; + int name_size = mxf_utf16_local_tag_length(name); + int indirect_value_size = 13 + mxf_utf16_local_tag_length(value); + + if (!name_size || indirect_value_size == 13) + return 1; + + mxf_write_metadata_key(pb, 0x013f00); + klv_encode_ber_length(pb, 24 + name_size + indirect_value_size); + + // write instance UID + mxf_write_local_tag(pb, 16, 0x3C0A); + mxf_write_uuid(pb, TaggedValue, mxf->tagged_value_count); + + // write name + mxf_write_local_tag_utf16(pb, 0x5001, name); // Name + + // write indirect value + mxf_write_local_tag(pb, indirect_value_size, 0x5003); + avio_write(pb, mxf_indirect_value_utf16le, 17); + avio_put_str16le(pb, value); + + mxf->tagged_value_count++; + return 0; +} + +static int mxf_write_user_comments(AVFormatContext *s, const AVDictionary *m) +{ + MXFContext *mxf = s->priv_data; + AVDictionaryEntry *t = NULL; + int count = 0; + + while ((t = av_dict_get(m, "comment_", t, AV_DICT_IGNORE_SUFFIX))) { + if (mxf->tagged_value_count >= UINT16_MAX) { + av_log(s, AV_LOG_ERROR, "too many tagged values, ignoring remaining\n"); + return count; + } + + if (mxf_write_tagged_value(s, t->key + 8, t->value) == 0) + count++; + } + return count; +} + static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, const char *package_name) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; int i, track_count = s->nb_streams+1; int name_size = mxf_utf16_local_tag_length(package_name); + int user_comment_count = 0; if (type == MaterialPackage) { + user_comment_count = mxf_write_user_comments(s, s->metadata); mxf_write_metadata_key(pb, 0x013600); PRINT_KEY(s, "Material Package key", pb->buf_ptr - 16); - klv_encode_ber_length(pb, 92 + name_size + (16*track_count)); + klv_encode_ber_length(pb, 104 + name_size + (16*track_count) + (16*user_comment_count)); } else { mxf_write_metadata_key(pb, 0x013700); PRINT_KEY(s, "Source Package key", pb->buf_ptr - 16); - klv_encode_ber_length(pb, 112 + name_size + (16*track_count)); // 20 bytes length for descriptor reference + klv_encode_ber_length(pb, 124 + name_size + (16*track_count)); // 20 bytes length for descriptor reference } // write uid @@ -1188,6 +1244,12 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, for (i = 0; i < s->nb_streams; i++) mxf_write_uuid(pb, type == MaterialPackage ? Track : Track + TypeBottom, i); + // write user comment refs + mxf_write_local_tag(pb, user_comment_count*16 + 8, 0x4406); + mxf_write_refs_count(pb, user_comment_count); + for (i = 0; i < user_comment_count; i++) + mxf_write_uuid(pb, TaggedValue, mxf->tagged_value_count - user_comment_count + i); + // write multiple descriptor reference if (type == SourcePackage) { mxf_write_local_tag(pb, 16, 0x4701); diff --git a/tests/ref/lavf/mxf b/tests/ref/lavf/mxf index 38db9ac452..71d8649756 100644 --- a/tests/ref/lavf/mxf +++ b/tests/ref/lavf/mxf @@ -1,9 +1,9 @@ -c4eb3fab4d6b24687b81913036c79ce9 *./tests/data/lavf/lavf.mxf +57d6a4992ab92f4c2c9385803962f466 *./tests/data/lavf/lavf.mxf 525369 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1 -54cb97d1fc47c58f5580e8c897ef0874 *./tests/data/lavf/lavf.mxf +0d04b523972648406e506b26fbd63d23 *./tests/data/lavf/lavf.mxf 560697 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0x11a6178e -872c48b66705925cb0c6d638c82cd7d4 *./tests/data/lavf/lavf.mxf +10f4607a8db351854f3aeb3b1f2c89f9 *./tests/data/lavf/lavf.mxf 525369 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1 diff --git a/tests/ref/lavf/mxf_d10 b/tests/ref/lavf/mxf_d10 index 7a5e1540d8..e9205174e0 100644 --- a/tests/ref/lavf/mxf_d10 +++ b/tests/ref/lavf/mxf_d10 @@ -1,3 +1,3 @@ -c92818ebed05077efb27fc47a0351730 *./tests/data/lavf/lavf.mxf_d10 +6ac315755a974f38796a90c80ac6737b *./tests/data/lavf/lavf.mxf_d10 5330989 ./tests/data/lavf/lavf.mxf_d10 ./tests/data/lavf/lavf.mxf_d10 CRC=0x6c74d488 diff --git a/tests/ref/lavf/mxf_opatom b/tests/ref/lavf/mxf_opatom index 3230174d43..453efc7408 100644 --- a/tests/ref/lavf/mxf_opatom +++ b/tests/ref/lavf/mxf_opatom @@ -1,3 +1,3 @@ -6e2d9890ebda56b2e167e257750618ad *./tests/data/lavf/lavf.mxf_opatom +e1264a5d716f1289473689b5a1245809 *./tests/data/lavf/lavf.mxf_opatom 4716601 ./tests/data/lavf/lavf.mxf_opatom ./tests/data/lavf/lavf.mxf_opatom CRC=0xbdd696b9