Commit 75af0e6a authored by Clément Bœsch's avatar Clément Bœsch Committed by Clément Bœsch

dv: honor timecode in DV muxer.

This is based on the original work by Baptiste Coudurier.
parent b49fe589
...@@ -33,11 +33,15 @@ ...@@ -33,11 +33,15 @@
#include "avformat.h" #include "avformat.h"
#include "internal.h" #include "internal.h"
#include "libavcodec/dvdata.h" #include "libavcodec/dvdata.h"
#include "libavcodec/timecode.h"
#include "dv.h" #include "dv.h"
#include "libavutil/fifo.h" #include "libavutil/fifo.h"
#include "libavutil/mathematics.h" #include "libavutil/mathematics.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
struct DVMuxContext { struct DVMuxContext {
AVClass *av_class;
const DVprofile* sys; /* current DV profile, e.g.: 525/60, 625/50 */ const DVprofile* sys; /* current DV profile, e.g.: 525/60, 625/50 */
int n_ast; /* number of stereo audio streams (up to 2) */ int n_ast; /* number of stereo audio streams (up to 2) */
AVStream *ast[2]; /* stereo audio streams */ AVStream *ast[2]; /* stereo audio streams */
...@@ -47,6 +51,7 @@ struct DVMuxContext { ...@@ -47,6 +51,7 @@ struct DVMuxContext {
int has_audio; /* frame under contruction has audio */ int has_audio; /* frame under contruction has audio */
int has_video; /* frame under contruction has video */ int has_video; /* frame under contruction has video */
uint8_t frame_buf[DV_MAX_FRAME_SIZE]; /* frame under contruction */ uint8_t frame_buf[DV_MAX_FRAME_SIZE]; /* frame under contruction */
struct ff_timecode tc;
}; };
static const int dv_aaux_packs_dist[12][9] = { 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 ...@@ -75,33 +80,23 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu
struct tm tc; struct tm tc;
time_t ct; time_t ct;
int ltc_frame; int ltc_frame;
uint32_t timecode;
va_list ap; va_list ap;
buf[0] = (uint8_t)pack_id; buf[0] = (uint8_t)pack_id;
switch (pack_id) { switch (pack_id) {
case dv_timecode: 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 * LTC drop-frame frame counter drops two frames (0 and 1) every
* minute, unless it is exactly divisible by 10 * minute, unless it is exactly divisible by 10
*/ */
ltc_frame = (c->frames + 2 * ct / 60 - 2 * ct / 600) % c->sys->ltc_divisor; ltc_frame = c->tc.start + c->frames;
buf[1] = (0 << 7) | /* color frame: 0 - unsync; 1 - sync mode */ if (c->tc.drop)
(1 << 6) | /* drop frame timecode: 0 - nondrop; 1 - drop */ ltc_frame = ff_framenum_to_drop_timecode(ltc_frame);
((ltc_frame / 10) << 4) | /* tens of frames */ timecode = ff_framenum_to_smtpe_timecode(ltc_frame, c->sys->ltc_divisor,
(ltc_frame % 10); /* units of frames */ c->tc.drop);
buf[2] = (1 << 7) | /* biphase mark polarity correction: 0 - even; 1 - odd */ timecode |= 1<<23 | 1<<15 | 1<<7 | 1<<6; // biphase and binary group flags
((tc.tm_sec / 10) << 4) | /* tens of seconds */ AV_WB32(buf + 1, timecode);
(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 */
break; break;
case dv_audio_source: /* AAUX source pack */ case dv_audio_source: /* AAUX source pack */
va_start(ap, buf); va_start(ap, buf);
...@@ -371,6 +366,8 @@ static void dv_delete_mux(DVMuxContext *c) ...@@ -371,6 +366,8 @@ static void dv_delete_mux(DVMuxContext *c)
static int dv_write_header(AVFormatContext *s) static int dv_write_header(AVFormatContext *s)
{ {
DVMuxContext *dvc = s->priv_data;
if (!dv_init_mux(s)) { if (!dv_init_mux(s)) {
av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n" av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n"
"Make sure that you supply exactly two streams:\n" "Make sure that you supply exactly two streams:\n"
...@@ -378,6 +375,12 @@ static int dv_write_header(AVFormatContext *s) ...@@ -378,6 +375,12 @@ static int dv_write_header(AVFormatContext *s)
" (50Mbps allows an optional second audio stream)\n"); " (50Mbps allows an optional second audio stream)\n");
return -1; 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; return 0;
} }
...@@ -407,6 +410,16 @@ static int dv_write_trailer(struct AVFormatContext *s) ...@@ -407,6 +410,16 @@ static int dv_write_trailer(struct AVFormatContext *s)
return 0; 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 = { AVOutputFormat ff_dv_muxer = {
.name = "dv", .name = "dv",
.long_name = NULL_IF_CONFIG_SMALL("DV video format"), .long_name = NULL_IF_CONFIG_SMALL("DV video format"),
...@@ -417,4 +430,5 @@ AVOutputFormat ff_dv_muxer = { ...@@ -417,4 +430,5 @@ AVOutputFormat ff_dv_muxer = {
.write_header = dv_write_header, .write_header = dv_write_header,
.write_packet = dv_write_packet, .write_packet = dv_write_packet,
.write_trailer = dv_write_trailer, .write_trailer = dv_write_trailer,
.priv_class = &class,
}; };
522e5e5a46b99f8ad8aabdaf3d2f1869 *./tests/data/lavf/lavf.dv 188f804bd2d10cd436c8a7b111bdcd2a *./tests/data/lavf/lavf.dv
3600000 ./tests/data/lavf/lavf.dv 3600000 ./tests/data/lavf/lavf.dv
./tests/data/lavf/lavf.dv CRC=0x02c0af30 ./tests/data/lavf/lavf.dv CRC=0x02c0af30
27ade3031b17214cf81c19cbf70f37d7 *./tests/data/vsynth1/dv.dv 4d572f758b55a1756adf9f54132f3b9e *./tests/data/vsynth1/dv.dv
7200000 ./tests/data/vsynth1/dv.dv 7200000 ./tests/data/vsynth1/dv.dv
02ac7cdeab91d4d5621e7ce96dddc498 *./tests/data/dv.vsynth1.out.yuv 02ac7cdeab91d4d5621e7ce96dddc498 *./tests/data/dv.vsynth1.out.yuv
stddev: 6.90 PSNR: 31.34 MAXDIFF: 76 bytes: 7603200/ 7603200 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 7200000 ./tests/data/vsynth1/dv411.dv
b6640a3a572353f51284acb746eb00c4 *./tests/data/dv.vsynth1.out.yuv b6640a3a572353f51284acb746eb00c4 *./tests/data/dv.vsynth1.out.yuv
stddev: 30.76 PSNR: 18.37 MAXDIFF: 205 bytes: 7603200/ 7603200 stddev: 30.76 PSNR: 18.37 MAXDIFF: 205 bytes: 7603200/ 7603200
26dba84f0ea895b914ef5b333d8394ac *./tests/data/vsynth1/dv50.dv a193c5f92bf6e74c604e759d5f4f0f94 *./tests/data/vsynth1/dv50.dv
14400000 ./tests/data/vsynth1/dv50.dv 14400000 ./tests/data/vsynth1/dv50.dv
a2ff093e93ffed10f730fa21df02fc50 *./tests/data/dv50.vsynth1.out.yuv a2ff093e93ffed10f730fa21df02fc50 *./tests/data/dv50.vsynth1.out.yuv
stddev: 1.72 PSNR: 43.38 MAXDIFF: 29 bytes: 7603200/ 7603200 stddev: 1.72 PSNR: 43.38 MAXDIFF: 29 bytes: 7603200/ 7603200
bfa766f89bfeabc0ae1044f3954bed52 *./tests/data/vsynth2/dv.dv 85b8d55b0b68bb3fc2e90babb580f9b7 *./tests/data/vsynth2/dv.dv
7200000 ./tests/data/vsynth2/dv.dv 7200000 ./tests/data/vsynth2/dv.dv
7ec62bd3350a6848364669e6e1e4b9cc *./tests/data/dv.vsynth2.out.yuv 7ec62bd3350a6848364669e6e1e4b9cc *./tests/data/dv.vsynth2.out.yuv
stddev: 1.71 PSNR: 43.47 MAXDIFF: 33 bytes: 7603200/ 7603200 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 7200000 ./tests/data/vsynth2/dv411.dv
7f9fa421028aabb11eaf4c6513a5a843 *./tests/data/dv.vsynth2.out.yuv 7f9fa421028aabb11eaf4c6513a5a843 *./tests/data/dv.vsynth2.out.yuv
stddev: 10.09 PSNR: 28.05 MAXDIFF: 60 bytes: 7603200/ 7603200 stddev: 10.09 PSNR: 28.05 MAXDIFF: 60 bytes: 7603200/ 7603200
61e31c79e8949b25c849753a0785b0d7 *./tests/data/vsynth2/dv50.dv 0032a07167199e6f49e07fa7ed4d5f62 *./tests/data/vsynth2/dv50.dv
14400000 ./tests/data/vsynth2/dv50.dv 14400000 ./tests/data/vsynth2/dv50.dv
af3f2dd5ab62c1a1d98b07d4aeb6852f *./tests/data/dv50.vsynth2.out.yuv af3f2dd5ab62c1a1d98b07d4aeb6852f *./tests/data/dv50.vsynth2.out.yuv
stddev: 0.82 PSNR: 49.82 MAXDIFF: 12 bytes: 7603200/ 7603200 stddev: 0.82 PSNR: 49.82 MAXDIFF: 12 bytes: 7603200/ 7603200
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment