Browse code

timecode: move timecode muxer options to metadata.

Some demuxers set a timecode in the format or streams metadata. The
muxers now make use of this metadata instead of a duplicated private
option.

This makes possible transparent copy of the timecode when transmuxing
and transcoding.

-timecode option for MPEG1/2 codec is also renamed to -gop_timecode. The
global ffmpeg -timecode option will set it anyway so no option change
visible for the user.

Clément Bœsch authored on 2012/05/30 17:26:53
Showing 6 changed files
... ...
@@ -5618,6 +5618,16 @@ static int opt_deinterlace(const char *opt, const char *arg)
5618 5618
     return 0;
5619 5619
 }
5620 5620
 
5621
+static int opt_timecode(OptionsContext *o, const char *opt, const char *arg)
5622
+{
5623
+    char *tcr = av_asprintf("timecode=%s", arg);
5624
+    int ret = parse_option(o, "metadata:g", tcr, options);
5625
+    if (ret >= 0)
5626
+        ret = opt_default("gop_timecode", arg);
5627
+    av_free(tcr);
5628
+    return ret;
5629
+}
5630
+
5621 5631
 static void parse_cpuflags(int argc, char **argv, const OptionDef *options)
5622 5632
 {
5623 5633
     int idx = locate_option(argc, argv, options, "cpuflags");
... ...
@@ -5752,6 +5762,7 @@ static const OptionDef options[] = {
5752 5752
     { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant}, "use same quantizer as source (implies VBR)" },
5753 5753
     { "same_quant", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant},
5754 5754
       "use same quantizer as source (implies VBR)" },
5755
+    { "timecode", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_timecode}, "set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
5755 5756
     { "pass", HAS_ARG | OPT_VIDEO, {(void*)opt_pass}, "select the pass number (1 or 2)", "n" },
5756 5757
     { "passlogfile", HAS_ARG | OPT_VIDEO, {(void*)&opt_passlogfile}, "select two pass log file name prefix", "prefix" },
5757 5758
     { "deinterlace", OPT_EXPERT | OPT_VIDEO, {(void*)opt_deinterlace},
... ...
@@ -931,8 +931,7 @@ static void mpeg1_encode_block(MpegEncContext *s,
931 931
 #define OFFSET(x) offsetof(MpegEncContext, x)
932 932
 #define VE AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
933 933
 #define COMMON_OPTS\
934
-        {AV_TIMECODE_OPTION(MpegEncContext, tc_opt_str, \
935
-         AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)},\
934
+    { "gop_timecode",        "MPEG GOP Timecode in hh:mm:ss[:;.]ff format", OFFSET(tc_opt_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, VE },\
936 935
     { "intra_vlc",           "Use MPEG-2 intra VLC table.",       OFFSET(intra_vlc_format),    AV_OPT_TYPE_INT, { 0 }, 0, 1, VE },\
937 936
     { "drop_frame_timecode", "Timecode is in drop frame format.", OFFSET(drop_frame_timecode), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE}, \
938 937
     { "scan_offset",         "Reserve space for SVCD scan offset user data.", OFFSET(scan_offset), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE },
... ...
@@ -52,7 +52,6 @@ struct DVMuxContext {
52 52
     int               has_audio;     /* frame under contruction has audio */
53 53
     int               has_video;     /* frame under contruction has video */
54 54
     uint8_t           frame_buf[DV_MAX_FRAME_SIZE]; /* frame under contruction */
55
-    char             *tc_opt_str;    /* timecode option string */
56 55
     AVTimecode        tc;            /* timecode context */
57 56
 };
58 57
 
... ...
@@ -356,6 +355,7 @@ static int dv_write_header(AVFormatContext *s)
356 356
 {
357 357
     AVRational rate;
358 358
     DVMuxContext *dvc = s->priv_data;
359
+    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
359 360
 
360 361
     if (!dv_init_mux(s)) {
361 362
         av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n"
... ...
@@ -366,9 +366,16 @@ static int dv_write_header(AVFormatContext *s)
366 366
     }
367 367
     rate.num = dvc->sys->ltc_divisor;
368 368
     rate.den = 1;
369
-    if (dvc->tc_opt_str)
370
-        return av_timecode_init_from_string(&dvc->tc, rate,
371
-                                            dvc->tc_opt_str, s);
369
+    if (!tcr) { // no global timecode, look into the streams
370
+        int i;
371
+        for (i = 0; i < s->nb_streams; i++) {
372
+            tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
373
+            if (tcr)
374
+                break;
375
+        }
376
+    }
377
+    if (tcr)
378
+        return av_timecode_init_from_string(&dvc->tc, rate, tcr->value, s);
372 379
     return av_timecode_init(&dvc->tc, rate, 0, 0, s);
373 380
 }
374 381
 
... ...
@@ -398,16 +405,6 @@ static int dv_write_trailer(struct AVFormatContext *s)
398 398
     return 0;
399 399
 }
400 400
 
401
-static const AVClass class = {
402
-    .class_name = "dv",
403
-    .item_name  = av_default_item_name,
404
-    .version    = LIBAVUTIL_VERSION_INT,
405
-    .option     = (const AVOption[]){
406
-        {AV_TIMECODE_OPTION(DVMuxContext, tc_opt_str, AV_OPT_FLAG_ENCODING_PARAM)},
407
-        {NULL},
408
-    },
409
-};
410
-
411 401
 AVOutputFormat ff_dv_muxer = {
412 402
     .name              = "dv",
413 403
     .long_name         = NULL_IF_CONFIG_SMALL("DV video format"),
... ...
@@ -418,5 +415,4 @@ AVOutputFormat ff_dv_muxer = {
418 418
     .write_header      = dv_write_header,
419 419
     .write_packet      = dv_write_packet,
420 420
     .write_trailer     = dv_write_trailer,
421
-    .priv_class        = &class,
422 421
 };
... ...
@@ -41,7 +41,6 @@ typedef struct GXFTimecode{
41 41
     int ff;
42 42
     int color;
43 43
     int drop;
44
-    char *str;
45 44
 } GXFTimecode;
46 45
 
47 46
 typedef struct GXFStreamContext {
... ...
@@ -655,11 +654,11 @@ static void gxf_init_timecode_track(GXFStreamContext *sc, GXFStreamContext *vsc)
655 655
     sc->fields = vsc->fields;
656 656
 }
657 657
 
658
-static int gxf_init_timecode(AVFormatContext *s, GXFTimecode *tc, int fields)
658
+static int gxf_init_timecode(AVFormatContext *s, GXFTimecode *tc, const char *tcstr, int fields)
659 659
 {
660 660
     char c;
661 661
 
662
-    if (sscanf(tc->str, "%d:%d:%d%c%d", &tc->hh, &tc->mm, &tc->ss, &c, &tc->ff) != 5) {
662
+    if (sscanf(tcstr, "%d:%d:%d%c%d", &tc->hh, &tc->mm, &tc->ss, &c, &tc->ff) != 5) {
663 663
         av_log(s, AV_LOG_ERROR, "unable to parse timecode, "
664 664
                                 "syntax: hh:mm:ss[:;.]ff\n");
665 665
         return -1;
... ...
@@ -681,6 +680,7 @@ static int gxf_write_header(AVFormatContext *s)
681 681
     GXFStreamContext *vsc = NULL;
682 682
     uint8_t tracks[255] = {0};
683 683
     int i, media_info = 0;
684
+    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
684 685
 
685 686
     if (!pb->seekable) {
686 687
         av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome");
... ...
@@ -741,6 +741,8 @@ static int gxf_write_header(AVFormatContext *s)
741 741
                        "gxf muxer only accepts PAL or NTSC resolutions currently\n");
742 742
                 return -1;
743 743
             }
744
+            if (!tcr)
745
+                tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
744 746
             avpriv_set_pts_info(st, 64, gxf->time_base.num, gxf->time_base.den);
745 747
             if (gxf_find_lines_index(st) < 0)
746 748
                 sc->lines_index = -1;
... ...
@@ -792,9 +794,8 @@ static int gxf_write_header(AVFormatContext *s)
792 792
     if (ff_audio_interleave_init(s, GXF_samples_per_frame, (AVRational){ 1, 48000 }) < 0)
793 793
         return -1;
794 794
 
795
-    if (gxf->tc.str) {
796
-        gxf_init_timecode(s, &gxf->tc, vsc->fields);
797
-    }
795
+    if (tcr)
796
+        gxf_init_timecode(s, &gxf->tc, tcr->value, vsc->fields);
798 797
 
799 798
     gxf_init_timecode_track(&gxf->timecode_track, vsc);
800 799
     gxf->flags |= 0x200000; // time code track is non-drop frame
... ...
@@ -983,18 +984,6 @@ static int gxf_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *pk
983 983
                                ff_interleave_packet_per_dts, gxf_compare_field_nb);
984 984
 }
985 985
 
986
-static const AVOption options[] = {
987
-    { AV_TIMECODE_OPTION(GXFContext, tc.str, AV_OPT_FLAG_ENCODING_PARAM) },
988
-    { NULL }
989
-};
990
-
991
-static const AVClass gxf_muxer_class = {
992
-    .class_name     = "GXF muxer",
993
-    .item_name      = av_default_item_name,
994
-    .option         = options,
995
-    .version        = LIBAVUTIL_VERSION_INT,
996
-};
997
-
998 986
 AVOutputFormat ff_gxf_muxer = {
999 987
     .name              = "gxf",
1000 988
     .long_name         = NULL_IF_CONFIG_SMALL("GXF format"),
... ...
@@ -1006,5 +995,4 @@ AVOutputFormat ff_gxf_muxer = {
1006 1006
     .write_packet      = gxf_write_packet,
1007 1007
     .write_trailer     = gxf_write_trailer,
1008 1008
     .interleave_packet = gxf_interleave_packet,
1009
-    .priv_class        = &gxf_muxer_class,
1010 1009
 };
... ...
@@ -189,7 +189,6 @@ typedef struct MXFContext {
189 189
     unsigned body_partitions_count;
190 190
     int last_key_index;  ///< index of last key frame
191 191
     uint64_t duration;
192
-    char *tc_opt_str;    ///< timecode option string
193 192
     AVTimecode tc;       ///< timecode context
194 193
     AVStream *timecode_track;
195 194
     int timecode_base;       ///< rounded time code base (25 or 30)
... ...
@@ -1403,6 +1402,7 @@ static int mxf_write_header(AVFormatContext *s)
1403 1403
     const int *samples_per_frame = NULL;
1404 1404
     AVDictionaryEntry *t;
1405 1405
     int64_t timestamp = 0;
1406
+    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
1406 1407
 
1407 1408
     if (!s->nb_streams)
1408 1409
         return -1;
... ...
@@ -1443,9 +1443,10 @@ static int mxf_write_header(AVFormatContext *s)
1443 1443
             }
1444 1444
             rate = (AVRational){mxf->time_base.den, mxf->time_base.num};
1445 1445
             avpriv_set_pts_info(st, 64, mxf->time_base.num, mxf->time_base.den);
1446
-            if (mxf->tc_opt_str)
1447
-                ret = av_timecode_init_from_string(&mxf->tc, rate,
1448
-                                                   mxf->tc_opt_str, s);
1446
+            if (!tcr)
1447
+                tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
1448
+            if (tcr)
1449
+                ret = av_timecode_init_from_string(&mxf->tc, rate, tcr->value, s);
1449 1450
             else
1450 1451
                 ret = av_timecode_init(&mxf->tc, rate, 0, 0, s);
1451 1452
             if (ret < 0)
... ...
@@ -1877,26 +1878,6 @@ static int mxf_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int
1877 1877
                                mxf_interleave_get_packet, mxf_compare_timestamps);
1878 1878
 }
1879 1879
 
1880
-static const AVClass mxf_class = {
1881
-    .class_name = "mxf",
1882
-    .item_name  = av_default_item_name,
1883
-    .version    = LIBAVUTIL_VERSION_INT,
1884
-    .option     = (const AVOption[]){
1885
-        {AV_TIMECODE_OPTION(MXFContext, tc_opt_str, AV_OPT_FLAG_ENCODING_PARAM)},
1886
-        {NULL}
1887
-    },
1888
-};
1889
-
1890
-static const AVClass mxf_d10_class = {
1891
-    .class_name = "mxf_d10",
1892
-    .item_name  = av_default_item_name,
1893
-    .version    = LIBAVUTIL_VERSION_INT,
1894
-    .option     = (const AVOption[]){
1895
-        {AV_TIMECODE_OPTION(MXFContext, tc_opt_str, AV_OPT_FLAG_ENCODING_PARAM)},
1896
-        {NULL}
1897
-    },
1898
-};
1899
-
1900 1880
 AVOutputFormat ff_mxf_muxer = {
1901 1881
     .name              = "mxf",
1902 1882
     .long_name         = NULL_IF_CONFIG_SMALL("Material eXchange Format"),
... ...
@@ -1910,7 +1891,6 @@ AVOutputFormat ff_mxf_muxer = {
1910 1910
     .write_trailer     = mxf_write_footer,
1911 1911
     .flags             = AVFMT_NOTIMESTAMPS,
1912 1912
     .interleave_packet = mxf_interleave,
1913
-    .priv_class        = &mxf_class,
1914 1913
 };
1915 1914
 
1916 1915
 AVOutputFormat ff_mxf_d10_muxer = {
... ...
@@ -1925,5 +1905,4 @@ AVOutputFormat ff_mxf_d10_muxer = {
1925 1925
     .write_trailer     = mxf_write_footer,
1926 1926
     .flags             = AVFMT_NOTIMESTAMPS,
1927 1927
     .interleave_packet = mxf_interleave,
1928
-    .priv_class        = &mxf_d10_class,
1929 1928
 };
... ...
@@ -32,12 +32,6 @@
32 32
 
33 33
 #define AV_TIMECODE_STR_SIZE 16
34 34
 
35
-#define AV_TIMECODE_OPTION(ctx, string_field, flags)                     \
36
-    "timecode", "set timecode value following hh:mm:ss[:;.]ff format, "  \
37
-                "use ';' or '.' before frame number for drop frame",     \
38
-    offsetof(ctx, string_field),                                         \
39
-    AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, flags
40
-
41 35
 enum AVTimecodeFlag {
42 36
     AV_TIMECODE_FLAG_DROPFRAME      = 1<<0, ///< timecode is drop frame
43 37
     AV_TIMECODE_FLAG_24HOURSMAX     = 1<<1, ///< timecode wraps after 24 hours