From c44eae157f62b6792bbf8403f937658cb9d12621 Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 7 Oct 2016 02:46:22 -0300 Subject: avformat/matroskaenc: fix targets for attachment tags Attachment tags were being written targeting non-existent streams in the output file. Also filter filename and mimetype entries, as they are standard elements in the Attachment master. Signed-off-by: James Almer --- libavformat/matroskaenc.c | 66 ++++++++++++++++++++++++++++++++++++++++++----- tests/ref/lavf/mkv | 4 +-- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 593ddd1843..e330a12b38 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -96,6 +96,16 @@ typedef struct mkv_track { int64_t ts_offset; } mkv_track; +typedef struct mkv_attachment { + int stream_idx; + uint32_t fileuid; +} mkv_attachment; + +typedef struct mkv_attachments { + mkv_attachment *entries; + int num_entries; +} mkv_attachments; + #define MODE_MATROSKAv2 0x01 #define MODE_WEBM 0x02 @@ -121,6 +131,7 @@ typedef struct MatroskaMuxContext { mkv_seekhead *main_seekhead; mkv_cues *cues; mkv_track *tracks; + mkv_attachments *attachments; AVPacket cur_audio_pkt; @@ -368,6 +379,10 @@ static void mkv_free(MatroskaMuxContext *mkv) { av_freep(&mkv->cues->entries); av_freep(&mkv->cues); } + if (mkv->attachments) { + av_freep(&mkv->attachments->entries); + av_freep(&mkv->attachments); + } av_freep(&mkv->tracks); av_freep(&mkv->stream_durations); av_freep(&mkv->stream_duration_offsets); @@ -1393,7 +1408,10 @@ static int mkv_check_tag_name(const char *name, unsigned int elementid) av_strcasecmp(name, "encoding_tool") && av_strcasecmp(name, "duration") && (elementid != MATROSKA_ID_TAGTARGETS_TRACKUID || - av_strcasecmp(name, "language")); + av_strcasecmp(name, "language")) && + (elementid != MATROSKA_ID_TAGTARGETS_ATTACHUID || + (av_strcasecmp(name, "filename") && + av_strcasecmp(name, "mimetype"))); } static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid, @@ -1446,6 +1464,9 @@ static int mkv_write_tags(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; + if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) + continue; + if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID)) continue; @@ -1456,9 +1477,13 @@ static int mkv_write_tags(AVFormatContext *s) if (s->pb->seekable && !mkv->is_live) { for (i = 0; i < s->nb_streams; i++) { AVIOContext *pb; + AVStream *st = s->streams[i]; ebml_master tag_target; ebml_master tag; + if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) + continue; + mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags, &tag_target); pb = mkv->tags_bc; @@ -1484,6 +1509,20 @@ static int mkv_write_tags(AVFormatContext *s) if (ret < 0) return ret; } + if (mkv->have_attachments) { + for (i = 0; i < mkv->attachments->num_entries; i++) { + mkv_attachment *attachment = &mkv->attachments->entries[i]; + AVStream *st = s->streams[attachment->stream_idx]; + + if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID)) + continue; + + ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, attachment->fileuid, &mkv->tags); + if (ret < 0) + return ret; + } + } + if (mkv->tags.pos) { if (s->pb->seekable && !mkv->is_live) put_ebml_void(s->pb, avio_tell(mkv->tags_bc) + ((mkv->write_crc && mkv->mode != MODE_WEBM) ? 2 /* ebml id + data size */ + 4 /* CRC32 */ : 0)); @@ -1504,6 +1543,10 @@ static int mkv_write_attachments(AVFormatContext *s) if (!mkv->have_attachments) return 0; + mkv->attachments = av_mallocz(sizeof(*mkv->attachments)); + if (!mkv->attachments) + return ret; + av_lfg_init(&c, av_get_random_seed()); ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_ATTACHMENTS, avio_tell(pb)); @@ -1515,13 +1558,19 @@ static int mkv_write_attachments(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; ebml_master attached_file; + mkv_attachment *attachment = mkv->attachments->entries; AVDictionaryEntry *t; const char *mimetype = NULL; - uint64_t fileuid; + uint32_t fileuid; if (st->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT) continue; + attachment = av_realloc_array(attachment, mkv->attachments->num_entries + 1, sizeof(mkv_attachment)); + if (!attachment) + return AVERROR(ENOMEM); + mkv->attachments->entries = attachment; + attached_file = start_ebml_master(dyn_cp, MATROSKA_ID_ATTACHEDFILE, 0); if (t = av_dict_get(st->metadata, "title", NULL, 0)) @@ -1561,17 +1610,20 @@ static int mkv_write_attachments(AVFormatContext *s) av_sha_update(sha, st->codecpar->extradata, st->codecpar->extradata_size); av_sha_final(sha, digest); av_free(sha); - fileuid = AV_RL64(digest); + fileuid = AV_RL32(digest); } else { fileuid = av_lfg_get(&c); } - av_log(s, AV_LOG_VERBOSE, "Using %.16"PRIx64" for attachment %d\n", - fileuid, i); + av_log(s, AV_LOG_VERBOSE, "Using %.8"PRIx32" for attachment %d\n", + fileuid, mkv->attachments->num_entries); put_ebml_string(dyn_cp, MATROSKA_ID_FILEMIMETYPE, mimetype); put_ebml_binary(dyn_cp, MATROSKA_ID_FILEDATA, st->codecpar->extradata, st->codecpar->extradata_size); put_ebml_uint(dyn_cp, MATROSKA_ID_FILEUID, fileuid); end_ebml_master(dyn_cp, attached_file); + + mkv->attachments->entries[mkv->attachments->num_entries].stream_idx = i; + mkv->attachments->entries[mkv->attachments->num_entries++].fileuid = fileuid; } end_ebml_master_crc32(pb, &dyn_cp, mkv, attachments); @@ -1751,11 +1803,11 @@ static int mkv_write_header(AVFormatContext *s) if (ret < 0) goto fail; - ret = mkv_write_tags(s); + ret = mkv_write_attachments(s); if (ret < 0) goto fail; - ret = mkv_write_attachments(s); + ret = mkv_write_tags(s); if (ret < 0) goto fail; } diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv index 0fc5becef5..5f570833d5 100644 --- a/tests/ref/lavf/mkv +++ b/tests/ref/lavf/mkv @@ -1,5 +1,5 @@ -591d55099c938bd7560585da13874a4c *./tests/data/lavf/lavf.mkv -472929 ./tests/data/lavf/lavf.mkv +a06683a6eb4af6fe8ffe5603c1942a97 *./tests/data/lavf/lavf.mkv +472755 ./tests/data/lavf/lavf.mkv ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 c1009a6b9b4ef7e0eb0775d227131415 *./tests/data/lavf/lavf.mkv 320599 ./tests/data/lavf/lavf.mkv -- cgit v1.2.3