... | ... |
@@ -6,7 +6,7 @@ version next: |
6 | 6 |
- v410 Quicktime Uncompressed 4:4:4 10-bit encoder and decoder |
7 | 7 |
- SBaGen (SBG) binaural beats script demuxer |
8 | 8 |
- OpenMG Audio muxer |
9 |
-- dv: add timecode to metadata |
|
9 |
+- Timecode extraction in DV and MOV |
|
10 | 10 |
- thumbnail video filter |
11 | 11 |
- XML output in ffprobe |
12 | 12 |
- asplit audio filter |
... | ... |
@@ -36,6 +36,7 @@ |
36 | 36 |
#include "riff.h" |
37 | 37 |
#include "isom.h" |
38 | 38 |
#include "libavcodec/get_bits.h" |
39 |
+#include "libavcodec/timecode.h" |
|
39 | 40 |
#include "id3v1.h" |
40 | 41 |
#include "mov_chan.h" |
41 | 42 |
|
... | ... |
@@ -2615,6 +2616,46 @@ finish: |
2615 | 2615 |
avio_seek(sc->pb, cur_pos, SEEK_SET); |
2616 | 2616 |
} |
2617 | 2617 |
|
2618 |
+static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st, |
|
2619 |
+ uint32_t value) |
|
2620 |
+{ |
|
2621 |
+ char buf[16]; |
|
2622 |
+ struct ff_timecode tc = { |
|
2623 |
+ .drop = st->codec->flags2 & CODEC_FLAG2_DROP_FRAME_TIMECODE, |
|
2624 |
+ .rate = (AVRational){st->codec->time_base.den, |
|
2625 |
+ st->codec->time_base.num}, |
|
2626 |
+ }; |
|
2627 |
+ |
|
2628 |
+ if (avpriv_check_timecode_rate(s, tc.rate, tc.drop) < 0) |
|
2629 |
+ return AVERROR(EINVAL); |
|
2630 |
+ av_dict_set(&st->metadata, "timecode", |
|
2631 |
+ avpriv_timecode_to_string(buf, &tc, value), 0); |
|
2632 |
+ return 0; |
|
2633 |
+} |
|
2634 |
+ |
|
2635 |
+static int mov_read_timecode_track(AVFormatContext *s, AVStream *st) |
|
2636 |
+{ |
|
2637 |
+ MOVStreamContext *sc = st->priv_data; |
|
2638 |
+ int64_t cur_pos = avio_tell(sc->pb); |
|
2639 |
+ uint32_t value; |
|
2640 |
+ |
|
2641 |
+ if (!st->nb_index_entries) |
|
2642 |
+ return -1; |
|
2643 |
+ |
|
2644 |
+ avio_seek(sc->pb, st->index_entries->pos, SEEK_SET); |
|
2645 |
+ value = avio_rb32(s->pb); |
|
2646 |
+ |
|
2647 |
+ /* Assume Counter flag is set to 1 in tmcd track (even though it is likely |
|
2648 |
+ * not the case) and thus assume "frame number format" instead of QT one. |
|
2649 |
+ * No sample with tmcd track can be found with a QT timecode at the moment, |
|
2650 |
+ * despite what the tmcd track "suggests" (Counter flag set to 0 means QT |
|
2651 |
+ * format). */ |
|
2652 |
+ parse_timecode_in_framenum_format(s, st, value); |
|
2653 |
+ |
|
2654 |
+ avio_seek(sc->pb, cur_pos, SEEK_SET); |
|
2655 |
+ return 0; |
|
2656 |
+} |
|
2657 |
+ |
|
2618 | 2658 |
static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) |
2619 | 2659 |
{ |
2620 | 2660 |
MOVContext *mov = s->priv_data; |
... | ... |
@@ -2640,8 +2681,14 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) |
2640 | 2640 |
} |
2641 | 2641 |
av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); |
2642 | 2642 |
|
2643 |
- if (pb->seekable && mov->chapter_track > 0) |
|
2644 |
- mov_read_chapters(s); |
|
2643 |
+ if (pb->seekable) { |
|
2644 |
+ int i; |
|
2645 |
+ if (mov->chapter_track > 0) |
|
2646 |
+ mov_read_chapters(s); |
|
2647 |
+ for (i = 0; i < s->nb_streams; i++) |
|
2648 |
+ if (s->streams[i]->codec->codec_tag == AV_RL32("tmcd")) |
|
2649 |
+ mov_read_timecode_track(s, s->streams[i]); |
|
2650 |
+ } |
|
2645 | 2651 |
|
2646 | 2652 |
return 0; |
2647 | 2653 |
} |