This is based on the original work by Baptiste Coudurier.
| ... | ... |
@@ -33,11 +33,15 @@ |
| 33 | 33 |
#include "avformat.h" |
| 34 | 34 |
#include "internal.h" |
| 35 | 35 |
#include "libavcodec/dvdata.h" |
| 36 |
+#include "libavcodec/timecode.h" |
|
| 36 | 37 |
#include "dv.h" |
| 37 | 38 |
#include "libavutil/fifo.h" |
| 38 | 39 |
#include "libavutil/mathematics.h" |
| 40 |
+#include "libavutil/intreadwrite.h" |
|
| 41 |
+#include "libavutil/opt.h" |
|
| 39 | 42 |
|
| 40 | 43 |
struct DVMuxContext {
|
| 44 |
+ AVClass *av_class; |
|
| 41 | 45 |
const DVprofile* sys; /* current DV profile, e.g.: 525/60, 625/50 */ |
| 42 | 46 |
int n_ast; /* number of stereo audio streams (up to 2) */ |
| 43 | 47 |
AVStream *ast[2]; /* stereo audio streams */ |
| ... | ... |
@@ -47,6 +51,7 @@ struct DVMuxContext {
|
| 47 | 47 |
int has_audio; /* frame under contruction has audio */ |
| 48 | 48 |
int has_video; /* frame under contruction has video */ |
| 49 | 49 |
uint8_t frame_buf[DV_MAX_FRAME_SIZE]; /* frame under contruction */ |
| 50 |
+ struct ff_timecode tc; |
|
| 50 | 51 |
}; |
| 51 | 52 |
|
| 52 | 53 |
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 | 75 |
struct tm tc; |
| 76 | 76 |
time_t ct; |
| 77 | 77 |
int ltc_frame; |
| 78 |
+ uint32_t timecode; |
|
| 78 | 79 |
va_list ap; |
| 79 | 80 |
|
| 80 | 81 |
buf[0] = (uint8_t)pack_id; |
| 81 | 82 |
switch (pack_id) {
|
| 82 | 83 |
case dv_timecode: |
| 83 |
- ct = (time_t)av_rescale_rnd(c->frames, c->sys->time_base.num, |
|
| 84 |
- c->sys->time_base.den, AV_ROUND_DOWN); |
|
| 85 |
- brktimegm(ct, &tc); |
|
| 86 | 84 |
/* |
| 87 | 85 |
* LTC drop-frame frame counter drops two frames (0 and 1) every |
| 88 | 86 |
* minute, unless it is exactly divisible by 10 |
| 89 | 87 |
*/ |
| 90 |
- ltc_frame = (c->frames + 2 * ct / 60 - 2 * ct / 600) % c->sys->ltc_divisor; |
|
| 91 |
- buf[1] = (0 << 7) | /* color frame: 0 - unsync; 1 - sync mode */ |
|
| 92 |
- (1 << 6) | /* drop frame timecode: 0 - nondrop; 1 - drop */ |
|
| 93 |
- ((ltc_frame / 10) << 4) | /* tens of frames */ |
|
| 94 |
- (ltc_frame % 10); /* units of frames */ |
|
| 95 |
- buf[2] = (1 << 7) | /* biphase mark polarity correction: 0 - even; 1 - odd */ |
|
| 96 |
- ((tc.tm_sec / 10) << 4) | /* tens of seconds */ |
|
| 97 |
- (tc.tm_sec % 10); /* units of seconds */ |
|
| 98 |
- buf[3] = (1 << 7) | /* binary group flag BGF0 */ |
|
| 99 |
- ((tc.tm_min / 10) << 4) | /* tens of minutes */ |
|
| 100 |
- (tc.tm_min % 10); /* units of minutes */ |
|
| 101 |
- buf[4] = (1 << 7) | /* binary group flag BGF2 */ |
|
| 102 |
- (1 << 6) | /* binary group flag BGF1 */ |
|
| 103 |
- ((tc.tm_hour / 10) << 4) | /* tens of hours */ |
|
| 104 |
- (tc.tm_hour % 10); /* units of hours */ |
|
| 88 |
+ ltc_frame = c->tc.start + c->frames; |
|
| 89 |
+ if (c->tc.drop) |
|
| 90 |
+ ltc_frame = ff_framenum_to_drop_timecode(ltc_frame); |
|
| 91 |
+ timecode = ff_framenum_to_smtpe_timecode(ltc_frame, c->sys->ltc_divisor, |
|
| 92 |
+ c->tc.drop); |
|
| 93 |
+ timecode |= 1<<23 | 1<<15 | 1<<7 | 1<<6; // biphase and binary group flags |
|
| 94 |
+ AV_WB32(buf + 1, timecode); |
|
| 105 | 95 |
break; |
| 106 | 96 |
case dv_audio_source: /* AAUX source pack */ |
| 107 | 97 |
va_start(ap, buf); |
| ... | ... |
@@ -371,6 +366,8 @@ static void dv_delete_mux(DVMuxContext *c) |
| 371 | 371 |
|
| 372 | 372 |
static int dv_write_header(AVFormatContext *s) |
| 373 | 373 |
{
|
| 374 |
+ DVMuxContext *dvc = s->priv_data; |
|
| 375 |
+ |
|
| 374 | 376 |
if (!dv_init_mux(s)) {
|
| 375 | 377 |
av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n" |
| 376 | 378 |
"Make sure that you supply exactly two streams:\n" |
| ... | ... |
@@ -378,6 +375,12 @@ static int dv_write_header(AVFormatContext *s) |
| 378 | 378 |
" (50Mbps allows an optional second audio stream)\n"); |
| 379 | 379 |
return -1; |
| 380 | 380 |
} |
| 381 |
+ if (dvc->tc.str) {
|
|
| 382 |
+ dvc->tc.rate.num = dvc->sys->time_base.den; |
|
| 383 |
+ dvc->tc.rate.den = dvc->sys->time_base.num; |
|
| 384 |
+ if (ff_init_smtpe_timecode(s, &dvc->tc) < 0) |
|
| 385 |
+ return -1; |
|
| 386 |
+ } |
|
| 381 | 387 |
return 0; |
| 382 | 388 |
} |
| 383 | 389 |
|
| ... | ... |
@@ -407,6 +410,16 @@ static int dv_write_trailer(struct AVFormatContext *s) |
| 407 | 407 |
return 0; |
| 408 | 408 |
} |
| 409 | 409 |
|
| 410 |
+static const AVClass class = {
|
|
| 411 |
+ .class_name = "dv", |
|
| 412 |
+ .item_name = av_default_item_name, |
|
| 413 |
+ .version = LIBAVUTIL_VERSION_INT, |
|
| 414 |
+ .option = (const AVOption[]){
|
|
| 415 |
+ {TIMECODE_OPT(DVMuxContext, AV_OPT_FLAG_ENCODING_PARAM)},
|
|
| 416 |
+ {NULL},
|
|
| 417 |
+ }, |
|
| 418 |
+}; |
|
| 419 |
+ |
|
| 410 | 420 |
AVOutputFormat ff_dv_muxer = {
|
| 411 | 421 |
.name = "dv", |
| 412 | 422 |
.long_name = NULL_IF_CONFIG_SMALL("DV video format"),
|
| ... | ... |
@@ -417,4 +430,5 @@ AVOutputFormat ff_dv_muxer = {
|
| 417 | 417 |
.write_header = dv_write_header, |
| 418 | 418 |
.write_packet = dv_write_packet, |
| 419 | 419 |
.write_trailer = dv_write_trailer, |
| 420 |
+ .priv_class = &class, |
|
| 420 | 421 |
}; |
| ... | ... |
@@ -1,8 +1,8 @@ |
| 1 |
-27ade3031b17214cf81c19cbf70f37d7 *./tests/data/vsynth1/dv.dv |
|
| 1 |
+4d572f758b55a1756adf9f54132f3b9e *./tests/data/vsynth1/dv.dv |
|
| 2 | 2 |
7200000 ./tests/data/vsynth1/dv.dv |
| 3 | 3 |
02ac7cdeab91d4d5621e7ce96dddc498 *./tests/data/dv.vsynth1.out.yuv |
| 4 | 4 |
stddev: 6.90 PSNR: 31.34 MAXDIFF: 76 bytes: 7603200/ 7603200 |
| 5 |
-bd67f2431db160d4bb6dcd791cea6efd *./tests/data/vsynth1/dv411.dv |
|
| 5 |
+f179899efba432c6f01149c36c709092 *./tests/data/vsynth1/dv411.dv |
|
| 6 | 6 |
7200000 ./tests/data/vsynth1/dv411.dv |
| 7 | 7 |
b6640a3a572353f51284acb746eb00c4 *./tests/data/dv.vsynth1.out.yuv |
| 8 | 8 |
stddev: 30.76 PSNR: 18.37 MAXDIFF: 205 bytes: 7603200/ 7603200 |
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-26dba84f0ea895b914ef5b333d8394ac *./tests/data/vsynth1/dv50.dv |
|
| 1 |
+a193c5f92bf6e74c604e759d5f4f0f94 *./tests/data/vsynth1/dv50.dv |
|
| 2 | 2 |
14400000 ./tests/data/vsynth1/dv50.dv |
| 3 | 3 |
a2ff093e93ffed10f730fa21df02fc50 *./tests/data/dv50.vsynth1.out.yuv |
| 4 | 4 |
stddev: 1.72 PSNR: 43.38 MAXDIFF: 29 bytes: 7603200/ 7603200 |
| ... | ... |
@@ -1,8 +1,8 @@ |
| 1 |
-bfa766f89bfeabc0ae1044f3954bed52 *./tests/data/vsynth2/dv.dv |
|
| 1 |
+85b8d55b0b68bb3fc2e90babb580f9b7 *./tests/data/vsynth2/dv.dv |
|
| 2 | 2 |
7200000 ./tests/data/vsynth2/dv.dv |
| 3 | 3 |
7ec62bd3350a6848364669e6e1e4b9cc *./tests/data/dv.vsynth2.out.yuv |
| 4 | 4 |
stddev: 1.71 PSNR: 43.47 MAXDIFF: 33 bytes: 7603200/ 7603200 |
| 5 |
-00a9d8683ac6826af41bcf7223fb0389 *./tests/data/vsynth2/dv411.dv |
|
| 5 |
+e428508f400327aeb96969c08fb9e1b5 *./tests/data/vsynth2/dv411.dv |
|
| 6 | 6 |
7200000 ./tests/data/vsynth2/dv411.dv |
| 7 | 7 |
7f9fa421028aabb11eaf4c6513a5a843 *./tests/data/dv.vsynth2.out.yuv |
| 8 | 8 |
stddev: 10.09 PSNR: 28.05 MAXDIFF: 60 bytes: 7603200/ 7603200 |
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-61e31c79e8949b25c849753a0785b0d7 *./tests/data/vsynth2/dv50.dv |
|
| 1 |
+0032a07167199e6f49e07fa7ed4d5f62 *./tests/data/vsynth2/dv50.dv |
|
| 2 | 2 |
14400000 ./tests/data/vsynth2/dv50.dv |
| 3 | 3 |
af3f2dd5ab62c1a1d98b07d4aeb6852f *./tests/data/dv50.vsynth2.out.yuv |
| 4 | 4 |
stddev: 0.82 PSNR: 49.82 MAXDIFF: 12 bytes: 7603200/ 7603200 |