diff options
Diffstat (limited to 'libavformat/dvenc.c')
-rw-r--r-- | libavformat/dvenc.c | 126 |
1 files changed, 79 insertions, 47 deletions
diff --git a/libavformat/dvenc.c b/libavformat/dvenc.c index cf79534..93c103b 100644 --- a/libavformat/dvenc.c +++ b/libavformat/dvenc.c @@ -11,20 +11,20 @@ * 50 Mbps (DVCPRO50) support * Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com> * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <time.h> @@ -35,12 +35,17 @@ #include "libavcodec/dv_profile.h" #include "libavcodec/dv.h" #include "dv.h" +#include "libavutil/avassert.h" #include "libavutil/fifo.h" #include "libavutil/mathematics.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/timecode.h" #define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32-bit audio struct DVMuxContext { + AVClass *av_class; const AVDVProfile* 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 */ @@ -50,6 +55,7 @@ struct DVMuxContext { int has_audio; /* frame under construction has audio */ int has_video; /* frame under construction has video */ uint8_t frame_buf[DV_MAX_FRAME_SIZE]; /* frame under construction */ + AVTimecode tc; /* timecode context */ }; static const int dv_aaux_packs_dist[12][9] = { @@ -67,8 +73,16 @@ static const int dv_aaux_packs_dist[12][9] = { { 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff }, }; -static int dv_audio_frame_size(const AVDVProfile* sys, int frame) +static int dv_audio_frame_size(const AVDVProfile* sys, int frame, int sample_rate) { + if ((sys->time_base.den == 25 || sys->time_base.den == 50) && sys->time_base.num == 1) { + if (sample_rate == 32000) return 1280; + else if (sample_rate == 44100) return 1764; + else return 1920; + } + + av_assert0(sample_rate == 48000); + return sys->audio_samples_dist[frame % (sizeof(sys->audio_samples_dist) / sizeof(sys->audio_samples_dist[0]))]; } @@ -77,41 +91,29 @@ 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; + int audio_type = 0; + int channel; 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); - ff_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 */ + timecode = av_timecode_get_smpte_from_framenum(&c->tc, c->frames); + 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); + channel = va_arg(ap, int); + if (c->ast[channel]->codecpar->sample_rate == 44100) { + audio_type = 1; + } else if (c->ast[channel]->codecpar->sample_rate == 32000) + audio_type = 2; buf[1] = (1 << 7) | /* locked mode -- SMPTE only supports locked mode */ (1 << 6) | /* reserved -- always 1 */ - (dv_audio_frame_size(c->sys, c->frames) - - c->sys->audio_min_samples[0]); + (dv_audio_frame_size(c->sys, c->frames, c->ast[channel]->codecpar->sample_rate) - + c->sys->audio_min_samples[audio_type]); /* # of samples */ buf[2] = (0 << 7) | /* multi-stereo */ (0 << 5) | /* #of audio channels per block: 0 -- 1 channel */ @@ -123,8 +125,9 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu (c->sys->n_difchan & 2); /* definition: 0 -- 25Mbps, 2 -- 50Mbps */ buf[4] = (1 << 7) | /* emphasis: 1 -- off */ (0 << 6) | /* emphasis time constant: 0 -- reserved */ - (0 << 3) | /* frequency: 0 -- 48kHz, 1 -- 44,1kHz, 2 -- 32kHz */ + (audio_type << 3) | /* frequency: 0 -- 48kHz, 1 -- 44,1kHz, 2 -- 32kHz */ 0; /* quantization: 0 -- 16-bit linear, 1 -- 12-bit nonlinear */ + va_end(ap); break; case dv_audio_control: @@ -184,12 +187,12 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu static void dv_inject_audio(DVMuxContext *c, int channel, uint8_t* frame_ptr) { int i, j, d, of, size; - size = 4 * dv_audio_frame_size(c->sys, c->frames); + size = 4 * dv_audio_frame_size(c->sys, c->frames, c->ast[channel]->codecpar->sample_rate); frame_ptr += channel * c->sys->difseg_size * 150 * 80; for (i = 0; i < c->sys->difseg_size; i++) { frame_ptr += 6 * 80; /* skip DIF segment header */ for (j = 0; j < 9; j++) { - dv_write_pack(dv_aaux_packs_dist[i][j], c, &frame_ptr[3], i >= c->sys->difseg_size/2); + dv_write_pack(dv_aaux_packs_dist[i][j], c, &frame_ptr[3], channel, i >= c->sys->difseg_size/2); for (d = 8; d < 80; d+=2) { of = c->sys->audio_shuffle[i][j] + (d - 8)/2 * c->sys->audio_stride; if (of*2 >= size) @@ -243,7 +246,6 @@ static int dv_assemble_frame(AVFormatContext *s, int i, reqasize; *frame = &c->frame_buf[0]; - reqasize = 4 * dv_audio_frame_size(c->sys, c->frames); switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_VIDEO: @@ -267,6 +269,8 @@ static int dv_assemble_frame(AVFormatContext *s, av_log(s, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient video data or severe sync problem.\n", c->frames); av_fifo_generic_write(c->audio_data[i], data, data_size, NULL); + reqasize = 4 * dv_audio_frame_size(c->sys, c->frames, st->codecpar->sample_rate); + /* Let us see if we've got enough audio for one DV frame. */ c->has_audio |= ((reqasize <= av_fifo_size(c->audio_data[i])) << i); @@ -281,6 +285,7 @@ static int dv_assemble_frame(AVFormatContext *s, c->has_audio = 0; for (i=0; i < c->n_ast; i++) { dv_inject_audio(c, i, *frame); + reqasize = 4 * dv_audio_frame_size(c->sys, c->frames, c->ast[i]->codecpar->sample_rate); av_fifo_drain(c->audio_data[i], reqasize); c->has_audio |= ((reqasize <= av_fifo_size(c->audio_data[i])) << i); } @@ -299,7 +304,6 @@ static DVMuxContext* dv_init_mux(AVFormatContext* s) { DVMuxContext *c = s->priv_data; AVStream *vst = NULL; - AVDictionaryEntry *t; int i; /* we support at most 1 video and 2 audio streams */ @@ -329,15 +333,28 @@ static DVMuxContext* dv_init_mux(AVFormatContext* s) if (!vst || vst->codecpar->codec_id != AV_CODEC_ID_DVVIDEO) goto bail_out; for (i=0; i<c->n_ast; i++) { - if (c->ast[i] && (c->ast[i]->codecpar->codec_id != AV_CODEC_ID_PCM_S16LE || - c->ast[i]->codecpar->sample_rate != 48000 || - c->ast[i]->codecpar->channels != 2)) - goto bail_out; + if (c->ast[i]) { + if(c->ast[i]->codecpar->codec_id != AV_CODEC_ID_PCM_S16LE || + c->ast[i]->codecpar->channels != 2) + goto bail_out; + if (c->ast[i]->codecpar->sample_rate != 48000 && + c->ast[i]->codecpar->sample_rate != 44100 && + c->ast[i]->codecpar->sample_rate != 32000 ) + goto bail_out; + } } - c->sys = av_dv_codec_profile(vst->codecpar->width, vst->codecpar->height, vst->codecpar->format); + c->sys = av_dv_codec_profile2(vst->codecpar->width, vst->codecpar->height, + vst->codecpar->format, vst->time_base); if (!c->sys) goto bail_out; + if ((c->sys->time_base.den != 25 && c->sys->time_base.den != 50) || c->sys->time_base.num != 1) { + if (c->ast[0] && c->ast[0]->codecpar->sample_rate != 48000) + goto bail_out; + if (c->ast[1] && c->ast[1]->codecpar->sample_rate != 48000) + goto bail_out; + } + if ((c->n_ast > 1) && (c->sys->n_difchan < 2)) { /* only 1 stereo pair is allowed in 25Mbps mode */ goto bail_out; @@ -347,14 +364,13 @@ static DVMuxContext* dv_init_mux(AVFormatContext* s) c->frames = 0; c->has_audio = 0; c->has_video = 0; - if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) - c->start_time = ff_iso8601_to_unix_time(t->value); + ff_parse_creation_time_metadata(s, &c->start_time, 1); for (i=0; i < c->n_ast; i++) { - if (c->ast[i] && !(c->audio_data[i]=av_fifo_alloc(100*MAX_AUDIO_FRAME_SIZE))) { + if (c->ast[i] && !(c->audio_data[i]=av_fifo_alloc_array(100, MAX_AUDIO_FRAME_SIZE))) { while (i > 0) { i--; - av_fifo_free(c->audio_data[i]); + av_fifo_freep(&c->audio_data[i]); } goto bail_out; } @@ -370,19 +386,35 @@ static void dv_delete_mux(DVMuxContext *c) { int i; for (i=0; i < c->n_ast; i++) - av_fifo_free(c->audio_data[i]); + av_fifo_freep(&c->audio_data[i]); } static int dv_write_header(AVFormatContext *s) { + AVRational rate; + DVMuxContext *dvc = s->priv_data; + AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0); + 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" - " video: 25fps or 29.97fps, audio: 2ch/48kHz/PCM\n" + " video: 25fps or 29.97fps, audio: 2ch/48|44|32kHz/PCM\n" " (50Mbps allows an optional second audio stream)\n"); return -1; } - return 0; + rate.num = dvc->sys->ltc_divisor; + rate.den = 1; + if (!tcr) { // no global timecode, look into the streams + int i; + for (i = 0; i < s->nb_streams; i++) { + tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0); + if (tcr) + break; + } + } + if (tcr && av_timecode_init_from_string(&dvc->tc, rate, tcr->value, s) >= 0) + return 0; + return av_timecode_init(&dvc->tc, rate, 0, 0, s); } static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt) |