Compute individual stream durations in matroska muxer. Write them as string tags in the same format as mkvmerge tool does. Signed-off-by: Sasi Inguva <isasi@google.com>tags/n2.8
| @@ -44,6 +44,7 @@ | |||||
| #include "libavutil/mathematics.h" | #include "libavutil/mathematics.h" | ||||
| #include "libavutil/opt.h" | #include "libavutil/opt.h" | ||||
| #include "libavutil/random_seed.h" | #include "libavutil/random_seed.h" | ||||
| #include "libavutil/rational.h" | |||||
| #include "libavutil/samplefmt.h" | #include "libavutil/samplefmt.h" | ||||
| #include "libavutil/sha.h" | #include "libavutil/sha.h" | ||||
| #include "libavutil/stereo3d.h" | #include "libavutil/stereo3d.h" | ||||
| @@ -131,6 +132,9 @@ typedef struct MatroskaMuxContext { | |||||
| int64_t last_track_timestamp[MAX_TRACKS]; | int64_t last_track_timestamp[MAX_TRACKS]; | ||||
| int64_t* stream_durations; | |||||
| int64_t* stream_duration_offsets; | |||||
| int allow_raw_vfw; | int allow_raw_vfw; | ||||
| } MatroskaMuxContext; | } MatroskaMuxContext; | ||||
| @@ -1151,12 +1155,12 @@ static int mkv_write_simpletag(AVIOContext *pb, AVDictionaryEntry *t) | |||||
| return 0; | 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; | MatroskaMuxContext *mkv = s->priv_data; | ||||
| ebml_master tag, targets; | |||||
| AVDictionaryEntry *t = NULL; | |||||
| ebml_master targets; | |||||
| int ret; | int ret; | ||||
| if (!tags->pos) { | if (!tags->pos) { | ||||
| @@ -1166,11 +1170,24 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme | |||||
| *tags = start_ebml_master(s->pb, MATROSKA_ID_TAGS, 0); | *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); | targets = start_ebml_master(s->pb, MATROSKA_ID_TAGTARGETS, 0); | ||||
| if (elementid) | if (elementid) | ||||
| put_ebml_uint(s->pb, elementid, uid); | put_ebml_uint(s->pb, elementid, uid); | ||||
| end_ebml_master(s->pb, targets); | 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))) { | while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) { | ||||
| if (av_strcasecmp(t->key, "title") && | if (av_strcasecmp(t->key, "title") && | ||||
| @@ -1220,6 +1237,25 @@ static int mkv_write_tags(AVFormatContext *s) | |||||
| if (ret < 0) return ret; | if (ret < 0) return ret; | ||||
| } | } | ||||
| if (!mkv->is_live) { | |||||
| for (i = 0; i < s->nb_streams; i++) { | |||||
| ebml_master tag_target; | |||||
| ebml_master tag; | |||||
| mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags, &tag_target); | |||||
| tag = start_ebml_master(s->pb, MATROSKA_ID_SIMPLETAG, 0); | |||||
| put_ebml_string(s->pb, MATROSKA_ID_TAGNAME, "DURATION"); | |||||
| mkv->stream_duration_offsets[i] = avio_tell(s->pb); | |||||
| // Reserve space to write duration as a 20-byte string. | |||||
| // 2 (ebml id) + 1 (data size) + 20 (data) | |||||
| put_ebml_void(s->pb, 23); | |||||
| end_ebml_master(s->pb, tag); | |||||
| end_ebml_master(s->pb, tag_target); | |||||
| } | |||||
| } | |||||
| for (i = 0; i < s->nb_chapters; i++) { | for (i = 0; i < s->nb_chapters; i++) { | ||||
| AVChapter *ch = s->chapters[i]; | AVChapter *ch = s->chapters[i]; | ||||
| @@ -1430,6 +1466,10 @@ static int mkv_write_header(AVFormatContext *s) | |||||
| } | } | ||||
| end_ebml_master(pb, segment_info); | end_ebml_master(pb, segment_info); | ||||
| // initialize stream_duration fields | |||||
| mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t)); | |||||
| mkv->stream_duration_offsets = av_mallocz(s->nb_streams * sizeof(int64_t)); | |||||
| ret = mkv_write_tracks(s); | ret = mkv_write_tracks(s); | ||||
| if (ret < 0) | if (ret < 0) | ||||
| return ret; | return ret; | ||||
| @@ -1801,6 +1841,11 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_ | |||||
| } | } | ||||
| mkv->duration = FFMAX(mkv->duration, ts + duration); | mkv->duration = FFMAX(mkv->duration, ts + duration); | ||||
| if (mkv->stream_durations) | |||||
| mkv->stream_durations[pkt->stream_index] = | |||||
| FFMAX(mkv->stream_durations[pkt->stream_index], ts + duration); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -1978,6 +2023,28 @@ static int mkv_write_trailer(AVFormatContext *s) | |||||
| avio_seek(pb, mkv->duration_offset, SEEK_SET); | avio_seek(pb, mkv->duration_offset, SEEK_SET); | ||||
| put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration); | put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration); | ||||
| // update stream durations | |||||
| if (mkv->stream_durations) { | |||||
| for (int i = 0; i < s->nb_streams; ++i) { | |||||
| AVStream *st = s->streams[i]; | |||||
| double duration_sec = mkv->stream_durations[i] * av_q2d(st->time_base); | |||||
| char duration_string[20] = ""; | |||||
| av_log(s, AV_LOG_DEBUG, "stream %d end duration = %" PRIu64 "\n", i, | |||||
| mkv->stream_durations[i]); | |||||
| if (!mkv->is_live && mkv->stream_duration_offsets[i] > 0) { | |||||
| avio_seek(pb, mkv->stream_duration_offsets[i], SEEK_SET); | |||||
| snprintf(duration_string, 20, "%02d:%02d:%012.9f", | |||||
| (int) duration_sec / 3600, ((int) duration_sec / 60) % 60, | |||||
| fmod(duration_sec, 60)); | |||||
| put_ebml_binary(pb, MATROSKA_ID_TAGSTRING, duration_string, 20); | |||||
| } | |||||
| } | |||||
| } | |||||
| avio_seek(pb, currentpos, SEEK_SET); | avio_seek(pb, currentpos, SEEK_SET); | ||||
| } | } | ||||
| @@ -1987,6 +2054,8 @@ static int mkv_write_trailer(AVFormatContext *s) | |||||
| av_freep(&mkv->tracks); | av_freep(&mkv->tracks); | ||||
| av_freep(&mkv->cues->entries); | av_freep(&mkv->cues->entries); | ||||
| av_freep(&mkv->cues); | av_freep(&mkv->cues); | ||||
| av_freep(&mkv->stream_durations); | |||||
| av_freep(&mkv->stream_duration_offsets); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -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-$(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: 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: CMP = oneline | ||||
| fate-wavpack-matroska_mux-mono: REF = a2987e2e51e01a35e47e7da13eb47a35 | |||||
| fate-wavpack-matroska_mux-mono: REF = 4befcc41dab6c690a15d0c396c324468 | |||||
| FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-61 | 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: 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: CMP = oneline | ||||
| fate-wavpack-matroska_mux-61: REF = ffba4ddea1ba71f7a5901d9ed1a267be | |||||
| fate-wavpack-matroska_mux-61: REF = 7fedbfc3b9ea7348761db664626c29f4 | |||||
| FATE_SAMPLES_AVCONV += $(FATE_WAVPACK-yes) | FATE_SAMPLES_AVCONV += $(FATE_WAVPACK-yes) | ||||
| fate-wavpack: $(FATE_WAVPACK-yes) | fate-wavpack: $(FATE_WAVPACK-yes) | ||||
| @@ -1,4 +1,4 @@ | |||||
| aeeb0f2e75d044dbe2f89b7e70a54c82 *tests/data/fate/acodec-tta.matroska | |||||
| 331080 tests/data/fate/acodec-tta.matroska | |||||
| 6c260836d7a32e4bd714453a3546c0d5 *tests/data/fate/acodec-tta.matroska | |||||
| 331148 tests/data/fate/acodec-tta.matroska | |||||
| 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-tta.out.wav | 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-tta.out.wav | ||||
| stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 | stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 | ||||
| @@ -1 +1 @@ | |||||
| 2dad5f63688ec613a04e94c8d4d167db | |||||
| 37a212f8d56ad71e7466d5129f88e756 | |||||
| @@ -1,6 +1,6 @@ | |||||
| bab98f5a04a9f7991fb960041c996478 *./tests/data/lavf/lavf.mkv | |||||
| 472668 ./tests/data/lavf/lavf.mkv | |||||
| 7c6509f597fb57bab002cbceec960011 *./tests/data/lavf/lavf.mkv | |||||
| 472872 ./tests/data/lavf/lavf.mkv | |||||
| ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 | ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 | ||||
| c93950920d4ee57eb3ff5ba0cf0c8b19 *./tests/data/lavf/lavf.mkv | |||||
| 320412 ./tests/data/lavf/lavf.mkv | |||||
| 5f8cb4b7e98610347dd8d0d58a828a0f *./tests/data/lavf/lavf.mkv | |||||
| 320548 ./tests/data/lavf/lavf.mkv | |||||
| ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 | ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 | ||||
| @@ -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: 797 size: 208 | |||||
| ret: 0 st:-1 flags:0 ts:-1.000000 | 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: 1013 size: 27837 | |||||
| ret: 0 st:-1 flags:1 ts: 1.894167 | 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: 292427 size: 27834 | |||||
| ret: 0 st: 0 flags:0 ts: 0.788000 | 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: 292427 size: 27834 | |||||
| ret: 0 st: 0 flags:1 ts:-0.317000 | 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: 1013 size: 27837 | |||||
| ret:-1 st: 1 flags:0 ts: 2.577000 | ret:-1 st: 1 flags:0 ts: 2.577000 | ||||
| ret: 0 st: 1 flags:1 ts: 1.471000 | 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: 320268 size: 209 | |||||
| ret: 0 st:-1 flags:0 ts: 0.365002 | 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: 146980 size: 27925 | |||||
| ret: 0 st:-1 flags:1 ts:-0.740831 | 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: 1013 size: 27837 | |||||
| ret:-1 st: 0 flags:0 ts: 2.153000 | ret:-1 st: 0 flags:0 ts: 2.153000 | ||||
| ret: 0 st: 0 flags:1 ts: 1.048000 | 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: 292427 size: 27834 | |||||
| ret: 0 st: 1 flags:0 ts:-0.058000 | 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: 797 size: 208 | |||||
| ret: 0 st: 1 flags:1 ts: 2.836000 | 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: 320268 size: 209 | |||||
| ret:-1 st:-1 flags:0 ts: 1.730004 | ret:-1 st:-1 flags:0 ts: 1.730004 | ||||
| ret: 0 st:-1 flags:1 ts: 0.624171 | 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: 146980 size: 27925 | |||||
| ret: 0 st: 0 flags:0 ts:-0.482000 | 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: 1013 size: 27837 | |||||
| ret: 0 st: 0 flags:1 ts: 2.413000 | 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: 292427 size: 27834 | |||||
| ret:-1 st: 1 flags:0 ts: 1.307000 | ret:-1 st: 1 flags:0 ts: 1.307000 | ||||
| ret: 0 st: 1 flags:1 ts: 0.201000 | 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: 797 size: 208 | |||||
| ret: 0 st:-1 flags:0 ts:-0.904994 | 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: 1013 size: 27837 | |||||
| ret: 0 st:-1 flags:1 ts: 1.989173 | 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: 292427 size: 27834 | |||||
| ret: 0 st: 0 flags:0 ts: 0.883000 | 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: 292427 size: 27834 | |||||
| ret: 0 st: 0 flags:1 ts:-0.222000 | 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: 1013 size: 27837 | |||||
| ret:-1 st: 1 flags:0 ts: 2.672000 | ret:-1 st: 1 flags:0 ts: 2.672000 | ||||
| ret: 0 st: 1 flags:1 ts: 1.566000 | 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: 320268 size: 209 | |||||
| ret: 0 st:-1 flags:0 ts: 0.460008 | 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: 146980 size: 27925 | |||||
| ret: 0 st:-1 flags:1 ts:-0.645825 | 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: 1013 size: 27837 | |||||