diff --git a/Changelog b/Changelog index 8b59ac8ff4..db4c7b3b5b 100644 --- a/Changelog +++ b/Changelog @@ -6,7 +6,7 @@ version next: - v410 Quicktime Uncompressed 4:4:4 10-bit encoder and decoder - SBaGen (SBG) binaural beats script demuxer - OpenMG Audio muxer -- dv: add timecode to metadata +- Timecode extraction in DV and MOV - thumbnail video filter - XML output in ffprobe - asplit audio filter diff --git a/libavformat/mov.c b/libavformat/mov.c index 5923fb7f82..6698b6a3a4 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -36,6 +36,7 @@ #include "riff.h" #include "isom.h" #include "libavcodec/get_bits.h" +#include "libavcodec/timecode.h" #include "id3v1.h" #include "mov_chan.h" @@ -2615,6 +2616,46 @@ finish: avio_seek(sc->pb, cur_pos, SEEK_SET); } +static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st, + uint32_t value) +{ + char buf[16]; + struct ff_timecode tc = { + .drop = st->codec->flags2 & CODEC_FLAG2_DROP_FRAME_TIMECODE, + .rate = (AVRational){st->codec->time_base.den, + st->codec->time_base.num}, + }; + + if (avpriv_check_timecode_rate(s, tc.rate, tc.drop) < 0) + return AVERROR(EINVAL); + av_dict_set(&st->metadata, "timecode", + avpriv_timecode_to_string(buf, &tc, value), 0); + return 0; +} + +static int mov_read_timecode_track(AVFormatContext *s, AVStream *st) +{ + MOVStreamContext *sc = st->priv_data; + int64_t cur_pos = avio_tell(sc->pb); + uint32_t value; + + if (!st->nb_index_entries) + return -1; + + avio_seek(sc->pb, st->index_entries->pos, SEEK_SET); + value = avio_rb32(s->pb); + + /* Assume Counter flag is set to 1 in tmcd track (even though it is likely + * not the case) and thus assume "frame number format" instead of QT one. + * No sample with tmcd track can be found with a QT timecode at the moment, + * despite what the tmcd track "suggests" (Counter flag set to 0 means QT + * format). */ + parse_timecode_in_framenum_format(s, st, value); + + avio_seek(sc->pb, cur_pos, SEEK_SET); + return 0; +} + static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) { MOVContext *mov = s->priv_data; @@ -2640,8 +2681,14 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) } av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); - if (pb->seekable && mov->chapter_track > 0) - mov_read_chapters(s); + if (pb->seekable) { + int i; + if (mov->chapter_track > 0) + mov_read_chapters(s); + for (i = 0; i < s->nb_streams; i++) + if (s->streams[i]->codec->codec_tag == AV_RL32("tmcd")) + mov_read_timecode_track(s, s->streams[i]); + } return 0; }