dv: honor timecode in DV muxer.
authorClément Bœsch <clement.boesch@smartjog.com>
Wed, 6 Jul 2011 13:08:28 +0000 (15:08 +0200)
committerClément Bœsch <ubitux@gmail.com>
Sat, 13 Aug 2011 17:13:03 +0000 (19:13 +0200)
This is based on the original work by Baptiste Coudurier.

libavformat/dvenc.c
tests/ref/lavf/dv_fmt
tests/ref/vsynth1/dv
tests/ref/vsynth1/dv50
tests/ref/vsynth2/dv
tests/ref/vsynth2/dv50

index ff816b6..289f124 100644 (file)
 #include "avformat.h"
 #include "internal.h"
 #include "libavcodec/dvdata.h"
+#include "libavcodec/timecode.h"
 #include "dv.h"
 #include "libavutil/fifo.h"
 #include "libavutil/mathematics.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
 
 struct DVMuxContext {
+    AVClass          *av_class;
     const DVprofile*  sys;           /* current DV profile, e.g.: 525/60, 625/50 */
     int               n_ast;         /* number of stereo audio streams (up to 2) */
     AVStream         *ast[2];        /* stereo audio streams */
@@ -47,6 +51,7 @@ struct DVMuxContext {
     int               has_audio;     /* frame under contruction has audio */
     int               has_video;     /* frame under contruction has video */
     uint8_t           frame_buf[DV_MAX_FRAME_SIZE]; /* frame under contruction */
+    struct ff_timecode tc;
 };
 
 static const int dv_aaux_packs_dist[12][9] = {
@@ -75,33 +80,23 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu
     struct tm tc;
     time_t ct;
     int ltc_frame;
+    uint32_t timecode;
     va_list ap;
 
     buf[0] = (uint8_t)pack_id;
     switch (pack_id) {
     case dv_timecode:
-        ct = (time_t)av_rescale_rnd(c->frames, c->sys->time_base.num,
-                                    c->sys->time_base.den, AV_ROUND_DOWN);
-        brktimegm(ct, &tc);
         /*
          * LTC drop-frame frame counter drops two frames (0 and 1) every
          * minute, unless it is exactly divisible by 10
          */
-        ltc_frame = (c->frames + 2 * ct / 60 - 2 * ct / 600) % c->sys->ltc_divisor;
-        buf[1] = (0                 << 7) | /* color frame: 0 - unsync; 1 - sync mode */
-                 (1                 << 6) | /* drop frame timecode: 0 - nondrop; 1 - drop */
-                 ((ltc_frame / 10)  << 4) | /* tens of frames */
-                 (ltc_frame % 10);          /* units of frames */
-        buf[2] = (1                 << 7) | /* biphase mark polarity correction: 0 - even; 1 - odd */
-                 ((tc.tm_sec / 10)  << 4) | /* tens of seconds */
-                 (tc.tm_sec % 10);          /* units of seconds */
-        buf[3] = (1                 << 7) | /* binary group flag BGF0 */
-                 ((tc.tm_min / 10)  << 4) | /* tens of minutes */
-                 (tc.tm_min % 10);          /* units of minutes */
-        buf[4] = (1                 << 7) | /* binary group flag BGF2 */
-                 (1                 << 6) | /* binary group flag BGF1 */
-                 ((tc.tm_hour / 10) << 4) | /* tens of hours */
-                 (tc.tm_hour % 10);         /* units of hours */
+        ltc_frame = c->tc.start + c->frames;
+        if (c->tc.drop)
+            ltc_frame = ff_framenum_to_drop_timecode(ltc_frame);
+        timecode = ff_framenum_to_smtpe_timecode(ltc_frame, c->sys->ltc_divisor,
+                                                 c->tc.drop);
+        timecode |= 1<<23 | 1<<15 | 1<<7 | 1<<6; // biphase and binary group flags
+        AV_WB32(buf + 1, timecode);
         break;
     case dv_audio_source:  /* AAUX source pack */
         va_start(ap, buf);
@@ -371,6 +366,8 @@ static void dv_delete_mux(DVMuxContext *c)
 
 static int dv_write_header(AVFormatContext *s)
 {
+    DVMuxContext *dvc = s->priv_data;
+
     if (!dv_init_mux(s)) {
         av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n"
                     "Make sure that you supply exactly two streams:\n"
@@ -378,6 +375,12 @@ static int dv_write_header(AVFormatContext *s)
                     "     (50Mbps allows an optional second audio stream)\n");
         return -1;
     }
+    if (dvc->tc.str) {
+        dvc->tc.rate.num = dvc->sys->time_base.den;
+        dvc->tc.rate.den = dvc->sys->time_base.num;
+        if (ff_init_smtpe_timecode(s, &dvc->tc) < 0)
+            return -1;
+    }
     return 0;
 }
 
@@ -407,6 +410,16 @@ static int dv_write_trailer(struct AVFormatContext *s)
     return 0;
 }
 
+static const AVClass class = {
+    .class_name = "dv",
+    .item_name  = av_default_item_name,
+    .version    = LIBAVUTIL_VERSION_INT,
+    .option     = (const AVOption[]){
+        {TIMECODE_OPT(DVMuxContext, AV_OPT_FLAG_ENCODING_PARAM)},
+        {NULL},
+    },
+};
+
 AVOutputFormat ff_dv_muxer = {
     .name              = "dv",
     .long_name         = NULL_IF_CONFIG_SMALL("DV video format"),
@@ -417,4 +430,5 @@ AVOutputFormat ff_dv_muxer = {
     .write_header      = dv_write_header,
     .write_packet      = dv_write_packet,
     .write_trailer     = dv_write_trailer,
+    .priv_class        = &class,
 };
index 7406dff..f39ff39 100644 (file)
@@ -1,3 +1,3 @@
-522e5e5a46b99f8ad8aabdaf3d2f1869 *./tests/data/lavf/lavf.dv
+188f804bd2d10cd436c8a7b111bdcd2a *./tests/data/lavf/lavf.dv
 3600000 ./tests/data/lavf/lavf.dv
 ./tests/data/lavf/lavf.dv CRC=0x02c0af30
index cb0427c..5b55c4f 100644 (file)
@@ -1,8 +1,8 @@
-27ade3031b17214cf81c19cbf70f37d7 *./tests/data/vsynth1/dv.dv
+4d572f758b55a1756adf9f54132f3b9e *./tests/data/vsynth1/dv.dv
 7200000 ./tests/data/vsynth1/dv.dv
 02ac7cdeab91d4d5621e7ce96dddc498 *./tests/data/dv.vsynth1.out.yuv
 stddev:    6.90 PSNR: 31.34 MAXDIFF:   76 bytes:  7603200/  7603200
-bd67f2431db160d4bb6dcd791cea6efd *./tests/data/vsynth1/dv411.dv
+f179899efba432c6f01149c36c709092 *./tests/data/vsynth1/dv411.dv
 7200000 ./tests/data/vsynth1/dv411.dv
 b6640a3a572353f51284acb746eb00c4 *./tests/data/dv.vsynth1.out.yuv
 stddev:   30.76 PSNR: 18.37 MAXDIFF:  205 bytes:  7603200/  7603200
index 9ae3385..461392e 100644 (file)
@@ -1,4 +1,4 @@
-26dba84f0ea895b914ef5b333d8394ac *./tests/data/vsynth1/dv50.dv
+a193c5f92bf6e74c604e759d5f4f0f94 *./tests/data/vsynth1/dv50.dv
 14400000 ./tests/data/vsynth1/dv50.dv
 a2ff093e93ffed10f730fa21df02fc50 *./tests/data/dv50.vsynth1.out.yuv
 stddev:    1.72 PSNR: 43.38 MAXDIFF:   29 bytes:  7603200/  7603200
index 676b209..b05dc4f 100644 (file)
@@ -1,8 +1,8 @@
-bfa766f89bfeabc0ae1044f3954bed52 *./tests/data/vsynth2/dv.dv
+85b8d55b0b68bb3fc2e90babb580f9b7 *./tests/data/vsynth2/dv.dv
 7200000 ./tests/data/vsynth2/dv.dv
 7ec62bd3350a6848364669e6e1e4b9cc *./tests/data/dv.vsynth2.out.yuv
 stddev:    1.71 PSNR: 43.47 MAXDIFF:   33 bytes:  7603200/  7603200
-00a9d8683ac6826af41bcf7223fb0389 *./tests/data/vsynth2/dv411.dv
+e428508f400327aeb96969c08fb9e1b5 *./tests/data/vsynth2/dv411.dv
 7200000 ./tests/data/vsynth2/dv411.dv
 7f9fa421028aabb11eaf4c6513a5a843 *./tests/data/dv.vsynth2.out.yuv
 stddev:   10.09 PSNR: 28.05 MAXDIFF:   60 bytes:  7603200/  7603200
index 7e0083b..cc468b8 100644 (file)
@@ -1,4 +1,4 @@
-61e31c79e8949b25c849753a0785b0d7 *./tests/data/vsynth2/dv50.dv
+0032a07167199e6f49e07fa7ed4d5f62 *./tests/data/vsynth2/dv50.dv
 14400000 ./tests/data/vsynth2/dv50.dv
 af3f2dd5ab62c1a1d98b07d4aeb6852f *./tests/data/dv50.vsynth2.out.yuv
 stddev:    0.82 PSNR: 49.82 MAXDIFF:   12 bytes:  7603200/  7603200