Signed-off-by: Sasi Inguva <is...@google.com> --- libavformat/matroska.h | 1 + libavformat/matroskadec.c | 21 +++++++++++++- libavformat/matroskaenc.c | 66 ++++++++++++++++++++++++++++++++++++++------ tests/fate/wavpack.mak | 4 +-- tests/ref/acodec/tta | 4 +-- tests/ref/fate/binsub-mksenc | 2 +- tests/ref/lavf/mkv | 8 +++--- tests/ref/seek/lavf-mkv | 44 ++++++++++++++--------------- 8 files changed, 109 insertions(+), 41 deletions(-)
diff --git a/libavformat/matroska.h b/libavformat/matroska.h index 344b2c3..e44b001 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -167,6 +167,7 @@ #define MATROSKA_ID_SIMPLETAG 0x67C8 #define MATROSKA_ID_TAGNAME 0x45A3 #define MATROSKA_ID_TAGSTRING 0x4487 +#define MATROSKA_ID_TAGBINARY 0x4485 #define MATROSKA_ID_TAGLANG 0x447A #define MATROSKA_ID_TAGDEFAULT 0x4484 #define MATROSKA_ID_TAGDEFAULT_BUG 0x44B4 diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 1807cae..92698a1 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -221,6 +221,7 @@ typedef struct MatroskaIndex { typedef struct MatroskaTag { char *name; char *string; + EbmlBin binary; char *lang; uint64_t def; EbmlList sub; @@ -528,6 +529,7 @@ static const EbmlSyntax matroska_index[] = { static const EbmlSyntax matroska_simpletag[] = { { MATROSKA_ID_TAGNAME, EBML_UTF8, 0, offsetof(MatroskaTag, name) }, { MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, offsetof(MatroskaTag, string) }, + { MATROSKA_ID_TAGBINARY, EBML_BIN, 0, offsetof(MatroskaTag, binary) }, { MATROSKA_ID_TAGLANG, EBML_STR, 0, offsetof(MatroskaTag, lang), { .s = "und" } }, { MATROSKA_ID_TAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTag, def) }, { MATROSKA_ID_TAGDEFAULT_BUG, EBML_UINT, 0, offsetof(MatroskaTag, def) }, @@ -1375,10 +1377,16 @@ static void matroska_convert_tag(AVFormatContext *s, EbmlList *list, av_log(s, AV_LOG_WARNING, "Skipping invalid tag with no TagName.\n"); continue; } + + if (!tags[i].string) { + continue; + } + if (prefix) snprintf(key, sizeof(key), "%s/%s", prefix, tags[i].name); else av_strlcpy(key, tags[i].name, sizeof(key)); + if (tags[i].def || !lang) { av_dict_set(metadata, key, tags[i].string, 0); if (tags[i].sub.nb_elem) @@ -1419,9 +1427,20 @@ static void matroska_convert_tags(AVFormatContext *s) } else if (tags[i].target.trackuid) { MatroskaTrack *track = matroska->tracks.elem; for (j = 0; j < matroska->tracks.nb_elem; j++) - if (track[j].uid == tags[i].target.trackuid && track[j].stream) + if (track[j].uid == tags[i].target.trackuid && track[j].stream) { + MatroskaTag *track_tags = tags[i].tag.elem; + for (int ind = 0; ind < tags[i].tag.nb_elem; ++ind) { + if (track_tags[ind].name && + !av_strcasecmp(track_tags[ind].name, "duration") && + track_tags[ind].binary.data && + track_tags[ind].binary.size == 8) { + track[j].stream->duration = AV_RL64(track_tags[ind].binary.data); + } + } + matroska_convert_tag(s, &tags[i].tag, &track[j].stream->metadata, NULL); + } } else { matroska_convert_tag(s, &tags[i].tag, &s->metadata, tags[i].target.type); diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 2d0d5f6..cb6e24d 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -131,6 +131,9 @@ typedef struct MatroskaMuxContext { int64_t last_track_timestamp[MAX_TRACKS]; + int64_t* stream_durations; + int64_t* stream_duration_offsets; + int allow_raw_vfw; } MatroskaMuxContext; @@ -1117,9 +1120,11 @@ static int mkv_write_chapters(AVFormatContext *s) return 0; } -static int mkv_write_simpletag(AVIOContext *pb, AVDictionaryEntry *t) +static int mkv_write_simpletag(AVIOContext *pb, + const char* tag_name, const void* data, int size, + int write_as_string, int64_t* tag_offset) { - uint8_t *key = av_strdup(t->key); + uint8_t *key = av_strdup(tag_name); uint8_t *p = key; const uint8_t *lang = NULL; ebml_master tag; @@ -1144,19 +1149,23 @@ static int mkv_write_simpletag(AVIOContext *pb, AVDictionaryEntry *t) put_ebml_string(pb, MATROSKA_ID_TAGNAME, key); if (lang) put_ebml_string(pb, MATROSKA_ID_TAGLANG, lang); - put_ebml_string(pb, MATROSKA_ID_TAGSTRING, t->value); + + if (tag_offset) + *tag_offset = avio_tell(pb); + + put_ebml_binary(pb, write_as_string == 0 ? MATROSKA_ID_TAGBINARY : MATROSKA_ID_TAGSTRING, data, size); end_ebml_master(pb, tag); av_freep(&key); return 0; } -static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid, - unsigned int uid, ebml_master *tags) +static int mkv_write_tag_targets(AVFormatContext *s, + unsigned int elementid, unsigned int uid, + ebml_master *tags, ebml_master* tag) { MatroskaMuxContext *mkv = s->priv_data; - ebml_master tag, targets; - AVDictionaryEntry *t = NULL; + ebml_master targets; int ret; if (!tags->pos) { @@ -1166,17 +1175,30 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme *tags = start_ebml_master(s->pb, MATROSKA_ID_TAGS, 0); } - tag = start_ebml_master(s->pb, MATROSKA_ID_TAG, 0); + *tag = start_ebml_master(s->pb, MATROSKA_ID_TAG, 0); targets = start_ebml_master(s->pb, MATROSKA_ID_TAGTARGETS, 0); if (elementid) put_ebml_uint(s->pb, elementid, uid); end_ebml_master(s->pb, targets); + return 0; +} + +static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid, + unsigned int uid, ebml_master *tags) +{ + ebml_master tag; + int ret; + AVDictionaryEntry *t = NULL; + + ret = mkv_write_tag_targets(s, elementid, uid, tags, &tag); + if (ret < 0) + return ret; while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) { if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode") && av_strcasecmp(t->key, "encoding_tool")) { - ret = mkv_write_simpletag(s->pb, t); + ret = mkv_write_simpletag(s->pb, t->key, t->value, strlen(t->value), 1, NULL); if (ret < 0) return ret; } @@ -1220,6 +1242,18 @@ static int mkv_write_tags(AVFormatContext *s) if (ret < 0) return ret; } + mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t)); + mkv->stream_duration_offsets = av_mallocz(s->nb_streams * sizeof(int64_t)); + + for (i = 0; i < s->nb_streams; i++) { + ebml_master tag; + mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags, &tag); + mkv_write_simpletag(s->pb, "duration", + mkv->stream_durations + i, sizeof(int64_t), + 0, mkv->stream_duration_offsets + i); + end_ebml_master(s->pb, tag); + } + for (i = 0; i < s->nb_chapters; i++) { AVChapter *ch = s->chapters[i]; @@ -1801,6 +1835,9 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_ } mkv->duration = FFMAX(mkv->duration, ts + duration); + mkv->stream_durations[pkt->stream_index] = + FFMAX(mkv->stream_durations[pkt->stream_index], ts + duration); + return 0; } @@ -1978,6 +2015,15 @@ static int mkv_write_trailer(AVFormatContext *s) avio_seek(pb, mkv->duration_offset, SEEK_SET); put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration); + // update stream durations + for (int i = 0; i < s->nb_streams; ++i) { + av_log(s, AV_LOG_DEBUG, "stream %d end duration = %" PRIu64 "\n", i, + mkv->stream_durations[i]); + avio_seek(pb, mkv->stream_duration_offsets[i], SEEK_SET); + put_ebml_binary(pb, MATROSKA_ID_TAGBINARY, mkv->stream_durations + i, + sizeof(int64_t)); + } + avio_seek(pb, currentpos, SEEK_SET); } @@ -1987,6 +2033,8 @@ static int mkv_write_trailer(AVFormatContext *s) av_freep(&mkv->tracks); av_freep(&mkv->cues->entries); av_freep(&mkv->cues); + av_freep(&mkv->stream_durations); + av_freep(&mkv->stream_duration_offsets); return 0; } diff --git a/tests/fate/wavpack.mak b/tests/fate/wavpack.mak index 240f5ea..e3d0edd 100644 --- a/tests/fate/wavpack.mak +++ b/tests/fate/wavpack.mak @@ -91,12 +91,12 @@ fate-wavpack-matroskamode: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/matros FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-mono fate-wavpack-matroska_mux-mono: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/mono_16bit_int.wv -c copy -fflags +bitexact -f matroska fate-wavpack-matroska_mux-mono: CMP = oneline -fate-wavpack-matroska_mux-mono: REF = a2987e2e51e01a35e47e7da13eb47a35 +fate-wavpack-matroska_mux-mono: REF = d0f5cbf0cfdc630ccf19fecd44034b06 FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-61 fate-wavpack-matroska_mux-61: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/eva_2.22_6.1_16bit-partial.wv -c copy -fflags +bitexact -f matroska fate-wavpack-matroska_mux-61: CMP = oneline -fate-wavpack-matroska_mux-61: REF = ffba4ddea1ba71f7a5901d9ed1a267be +fate-wavpack-matroska_mux-61: REF = 3c6252a863b5cc713c62721c60767367 FATE_SAMPLES_AVCONV += $(FATE_WAVPACK-yes) fate-wavpack: $(FATE_WAVPACK-yes) diff --git a/tests/ref/acodec/tta b/tests/ref/acodec/tta index b4b9611..ccef17b 100644 --- a/tests/ref/acodec/tta +++ b/tests/ref/acodec/tta @@ -1,4 +1,4 @@ -aeeb0f2e75d044dbe2f89b7e70a54c82 *tests/data/fate/acodec-tta.matroska -331080 tests/data/fate/acodec-tta.matroska +e271e3ce535ac8c9cb89c9af42e349b8 *tests/data/fate/acodec-tta.matroska +331136 tests/data/fate/acodec-tta.matroska 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-tta.out.wav stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 diff --git a/tests/ref/fate/binsub-mksenc b/tests/ref/fate/binsub-mksenc index c473497..c28580a 100644 --- a/tests/ref/fate/binsub-mksenc +++ b/tests/ref/fate/binsub-mksenc @@ -1 +1 @@ -2dad5f63688ec613a04e94c8d4d167db +e68ea99e034876b82ac957b1a7e30c90 diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv index edbfe60..46b378a 100644 --- a/tests/ref/lavf/mkv +++ b/tests/ref/lavf/mkv @@ -1,6 +1,6 @@ -bab98f5a04a9f7991fb960041c996478 *./tests/data/lavf/lavf.mkv -472668 ./tests/data/lavf/lavf.mkv +5200b77dabf4513e028358fe3783d2b1 *./tests/data/lavf/lavf.mkv +472836 ./tests/data/lavf/lavf.mkv ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 -c93950920d4ee57eb3ff5ba0cf0c8b19 *./tests/data/lavf/lavf.mkv -320412 ./tests/data/lavf/lavf.mkv +bb7f2d72e3d455a7ab66315804e599ac *./tests/data/lavf/lavf.mkv +320524 ./tests/data/lavf/lavf.mkv ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 diff --git a/tests/ref/seek/lavf-mkv b/tests/ref/seek/lavf-mkv index 11275d6..ed0a2c2 100644 --- a/tests/ref/seek/lavf-mkv +++ b/tests/ref/seek/lavf-mkv @@ -1,48 +1,48 @@ -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 661 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 773 size: 208 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 989 size: 27837 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292403 size: 27834 ret: 0 st: 0 flags:0 ts: 0.788000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292403 size: 27834 ret: 0 st: 0 flags:1 ts:-0.317000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 989 size: 27837 ret:-1 st: 1 flags:0 ts: 2.577000 ret: 0 st: 1 flags:1 ts: 1.471000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320132 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320244 size: 209 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146844 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146956 size: 27925 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 989 size: 27837 ret:-1 st: 0 flags:0 ts: 2.153000 ret: 0 st: 0 flags:1 ts: 1.048000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292403 size: 27834 ret: 0 st: 1 flags:0 ts:-0.058000 -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 661 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 773 size: 208 ret: 0 st: 1 flags:1 ts: 2.836000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320132 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320244 size: 209 ret:-1 st:-1 flags:0 ts: 1.730004 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146844 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146956 size: 27925 ret: 0 st: 0 flags:0 ts:-0.482000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 989 size: 27837 ret: 0 st: 0 flags:1 ts: 2.413000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292403 size: 27834 ret:-1 st: 1 flags:0 ts: 1.307000 ret: 0 st: 1 flags:1 ts: 0.201000 -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 661 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 773 size: 208 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 989 size: 27837 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292403 size: 27834 ret: 0 st: 0 flags:0 ts: 0.883000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292403 size: 27834 ret: 0 st: 0 flags:1 ts:-0.222000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 989 size: 27837 ret:-1 st: 1 flags:0 ts: 2.672000 ret: 0 st: 1 flags:1 ts: 1.566000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320132 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320244 size: 209 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146844 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146956 size: 27925 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 989 size: 27837 -- 2.5.0.rc2.392.g76e840b _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel