diff options
author | Mark Reid <mindmark@gmail.com> | 2015-03-05 10:59:11 -0800 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2015-03-10 01:00:38 +0100 |
commit | 399e31419ab20d39d87786c1c1dcb230f801c41f (patch) | |
tree | 5ebf781d58c0d815e556504d0c75587a661f86db /libavformat/mxfenc.c | |
parent | 2c8cff2be4a044c66e4904efa156dafd0d332d25 (diff) | |
download | ffmpeg-399e31419ab20d39d87786c1c1dcb230f801c41f.tar.gz |
libavformat/mxfenc: write package name metadata
Previous-version-reviewed-by: Tomas Härdin <tomas.hardin@codemill.se>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/mxfenc.c')
-rw-r--r-- | libavformat/mxfenc.c | 97 |
1 files changed, 86 insertions, 11 deletions
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 7d35af4dcc..898951c7b3 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -624,14 +624,61 @@ static void mxf_write_preface(AVFormatContext *s) } /* - * Write a local tag containing an ascii string as utf-16 + * Returns the length of the UTF-16 string, in 16-bit characters, that would result + * from decoding the utf-8 string. + */ +static uint64_t mxf_utf16len(const char *utf8_str) +{ + const uint8_t *q = utf8_str; + uint64_t size = 0; + while (*q) { + uint32_t ch; + GET_UTF8(ch, *q++, goto invalid;) + if (ch < 0x10000) + size++; + else + size += 2; + continue; +invalid: + av_log(NULL, AV_LOG_ERROR, "Invaid UTF8 sequence in mxf_utf16len\n\n"); + } + size += 1; + return size; +} + +/* + * Returns the calculated length a local tag containing an utf-8 string as utf-16 + */ +static int mxf_utf16_local_tag_length(const char *utf8_str) +{ + uint64_t size; + + if (!utf8_str) + return 0; + + size = mxf_utf16len(utf8_str); + if (size >= UINT16_MAX/2) { + av_log(NULL, AV_LOG_ERROR, "utf16 local tag size %"PRIx64" invalid (too large), ignoring\n", size); + return 0; + } + + return 4 + size * 2; +} + +/* + * Write a local tag containing an utf-8 string as utf-16 */ static void mxf_write_local_tag_utf16(AVIOContext *pb, int tag, const char *value) { - int i, size = strlen(value); + uint64_t size = mxf_utf16len(value); + + if (size >= UINT16_MAX/2) { + av_log(NULL, AV_LOG_ERROR, "utf16 local tag size %"PRIx64" invalid (too large), ignoring\n", size); + return; + } + mxf_write_local_tag(pb, size*2, tag); - for (i = 0; i < size; i++) - avio_wb16(pb, value[i]); + avio_put_str16be(pb, value); } static void mxf_write_identification(AVFormatContext *s) @@ -648,7 +695,9 @@ static void mxf_write_identification(AVFormatContext *s) version = s->flags & AVFMT_FLAG_BITEXACT ? "0.0.0" : AV_STRINGIFY(LIBAVFORMAT_VERSION); - length = 84 + (strlen(company)+strlen(product)+strlen(version))*2; // utf-16 + length = 72 + mxf_utf16_local_tag_length(company) + + mxf_utf16_local_tag_length(product) + + mxf_utf16_local_tag_length(version); klv_encode_ber_length(pb, length); // write uid @@ -659,7 +708,6 @@ static void mxf_write_identification(AVFormatContext *s) // write generation uid mxf_write_local_tag(pb, 16, 0x3C09); mxf_write_uuid(pb, Identification, 1); - mxf_write_local_tag_utf16(pb, 0x3C01, company); // Company Name mxf_write_local_tag_utf16(pb, 0x3C02, product); // Product Name mxf_write_local_tag_utf16(pb, 0x3C04, version); // Version String @@ -1092,20 +1140,21 @@ 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 void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type) +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); if (type == MaterialPackage) { mxf_write_metadata_key(pb, 0x013600); PRINT_KEY(s, "Material Package key", pb->buf_ptr - 16); - klv_encode_ber_length(pb, 92 + 16*track_count); + klv_encode_ber_length(pb, 92 + name_size + (16*track_count)); } else { mxf_write_metadata_key(pb, 0x013700); PRINT_KEY(s, "Source Package key", pb->buf_ptr - 16); - klv_encode_ber_length(pb, 112 + 16*track_count); // 20 bytes length for descriptor reference + klv_encode_ber_length(pb, 112 + name_size + (16*track_count)); // 20 bytes length for descriptor reference } // write uid @@ -1119,6 +1168,10 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type) mxf_write_umid(s, type == SourcePackage); PRINT_KEY(s, "package umid second part", pb->buf_ptr - 16); + // package name + if (name_size) + mxf_write_local_tag_utf16(pb, 0x4402, package_name); + // package creation date mxf_write_local_tag(pb, 8, 0x4405); avio_wb64(pb, mxf->timestamp); @@ -1187,11 +1240,33 @@ static int mxf_write_essence_container_data(AVFormatContext *s) static int mxf_write_header_metadata_sets(AVFormatContext *s) { + const char *material_package_name = NULL; + const char *file_package_name = NULL; + AVDictionaryEntry *entry = NULL; + AVStream *st = NULL; + int i; + + if (entry = av_dict_get(s->metadata, "material_package_name", NULL, 0)) + material_package_name = entry->value; + + if (entry = av_dict_get(s->metadata, "file_package_name", NULL, 0)) { + file_package_name = entry->value; + } else { + /* check if any of the streams contain a file_package_name */ + for (i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + if (entry = av_dict_get(st->metadata, "file_package_name", NULL, 0)) { + file_package_name = entry->value; + break; + } + } + } + mxf_write_preface(s); mxf_write_identification(s); mxf_write_content_storage(s); - mxf_write_package(s, MaterialPackage); - mxf_write_package(s, SourcePackage); + mxf_write_package(s, MaterialPackage, material_package_name); + mxf_write_package(s, SourcePackage, file_package_name); mxf_write_essence_container_data(s); return 0; } |