Commit f8007a14 authored by Roman Shaposhnik's avatar Roman Shaposhnik

Intial implementation of the DV100 (AKA DVCPRO HD) decoder and demuxer as

specified in SMPTE 370M

Originally committed as revision 15010 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 42f72a3a
version <next>
- The "device" muxers and demuxers are now in a new libavdevice library
- DV50 AKA DVCPRO50 encoder, decoder, muxer and demuxer
- DV100 AKA DVCPRO HD decoder and demuxer
- TechSmith Camtasia (TSCC) video decoder
- IBM Ultimotion (ULTI) video decoder
- Sierra Online audio file demuxer and decoder
......
......@@ -9,6 +9,10 @@
* 50 Mbps (DVCPRO50) support
* Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com>
*
* 100 Mbps (DVCPRO HD) support
* Initial code by Daniel Maas <dmaas@maasdigital.com> (funded by BBC R&D)
* Final code by Roman Shaposhnik
*
* Many thanks to Dan Dennedy <dan@dennedy.org> for providing wealth
* of DV technical info.
*
......@@ -51,6 +55,7 @@ typedef struct DVVideoContext {
uint8_t dv_zigzag[2][64];
uint32_t dv_idct_factor[2][2][22][64];
uint32_t dv100_idct_factor[4][4][16][64];
void (*get_pixels)(DCTELEM *block, const uint8_t *pixels, int line_size);
void (*fdct[2])(DCTELEM *block);
......@@ -59,8 +64,8 @@ typedef struct DVVideoContext {
/* MultiThreading - dv_anchor applies to entire DV codec, not just the avcontext */
/* one element is needed for each video segment in a DV frame */
/* at most there are 2 DIF channels * 12 DIF sequences * 27 video segments (PAL 50Mbps) */
#define DV_ANCHOR_SIZE (2*12*27)
/* at most there are 4 DIF channels * 12 DIF sequences * 27 video segments (1080i50) */
#define DV_ANCHOR_SIZE (4*12*27)
static void* dv_anchor[DV_ANCHOR_SIZE];
......@@ -102,6 +107,17 @@ static void dv_build_unquantize_tables(DVVideoContext *s, uint8_t* perm)
}
}
}
for(a = 0; a < 4; a++) {
for(q = 0; q < 16; q++) {
for(i = 1; i < 64; i++) {
s->dv100_idct_factor[0][a][q][i]= (dv100_qstep[q]<<(a+9))*dv_iweight_1080_y[i];
s->dv100_idct_factor[1][a][q][i]= (dv100_qstep[q]<<(a+9))*dv_iweight_1080_c[i];
s->dv100_idct_factor[2][a][q][i]= (dv100_qstep[q]<<(a+9))*dv_iweight_720_y[i];
s->dv100_idct_factor[3][a][q][i]= (dv100_qstep[q]<<(a+9))*dv_iweight_720_c[i];
}
}
}
}
static av_cold int dvvideo_init(AVCodecContext *avctx)
......@@ -349,6 +365,7 @@ static inline void dv_decode_video_segment(DVVideoContext *s,
{
int quant, dc, dct_mode, class1, j;
int mb_index, mb_x, mb_y, v, last_index;
int y_stride, i;
DCTELEM *block, *block1;
int c_offset;
uint8_t *y_ptr;
......@@ -360,6 +377,7 @@ static inline void dv_decode_video_segment(DVVideoContext *s,
DECLARE_ALIGNED_8(uint8_t, mb_bit_buffer[80 + 4]); /* allow some slack */
DECLARE_ALIGNED_8(uint8_t, vs_bit_buffer[5 * 80 + 4]); /* allow some slack */
const int log2_blocksize= 3-s->avctx->lowres;
int is_field_mode[5];
assert((((int)mb_bit_buffer)&7)==0);
assert((((int)vs_bit_buffer)&7)==0);
......@@ -378,6 +396,7 @@ static inline void dv_decode_video_segment(DVVideoContext *s,
init_put_bits(&pb, mb_bit_buffer, 80);
mb = mb1;
block = block1;
is_field_mode[mb_index] = 0;
for(j = 0;j < s->sys->bpm; j++) {
last_index = s->sys->block_sizes[j];
init_get_bits(&gb, buf_ptr, last_index);
......@@ -386,10 +405,17 @@ static inline void dv_decode_video_segment(DVVideoContext *s,
dc = get_sbits(&gb, 9);
dct_mode = get_bits1(&gb);
class1 = get_bits(&gb, 2);
mb->idct_put = s->idct_put[dct_mode && log2_blocksize==3];
mb->scan_table = s->dv_zigzag[dct_mode];
mb->factor_table = s->dv_idct_factor[class1 == 3][dct_mode]
[quant + dv_quant_offset[class1]];
if (DV_PROFILE_IS_HD(s->sys)) {
mb->idct_put = s->idct_put[0];
mb->scan_table = s->dv_zigzag[0];
mb->factor_table = s->dv100_idct_factor[((s->sys->height == 720)<<1)&(j < 4)][class1][quant];
is_field_mode[mb_index] |= !j && dct_mode;
} else {
mb->idct_put = s->idct_put[dct_mode && log2_blocksize==3];
mb->scan_table = s->dv_zigzag[dct_mode];
mb->factor_table = s->dv_idct_factor[class1 == 3][dct_mode]
[quant + dv_quant_offset[class1]];
}
dc = dc << 2;
/* convert to unsigned because 128 is not added in the
standard IDCT */
......@@ -465,60 +491,54 @@ static inline void dv_decode_video_segment(DVVideoContext *s,
v = *mb_pos_ptr++;
mb_x = v & 0xff;
mb_y = v >> 8;
/* We work with 720p frames split in half. The odd half-frame (chan==2,3) is displaced :-( */
if (s->sys->height == 720 && ((s->buf[1]>>2)&0x3) == 0) {
mb_y -= (mb_y>17)?18:-72; /* shifting the Y coordinate down by 72/2 macro blocks */
}
/* idct_put'ting luminance */
if ((s->sys->pix_fmt == PIX_FMT_YUV420P) ||
(s->sys->pix_fmt == PIX_FMT_YUV411P && mb_x >= (704 / 8)) ||
(s->sys->height >= 720 && mb_y != 134)) {
y_stride = (s->picture.linesize[0]<<((!is_field_mode[mb_index])*log2_blocksize)) - (2<<log2_blocksize);
} else {
y_stride = 0;
}
y_ptr = s->picture.data[0] + ((mb_y * s->picture.linesize[0] + mb_x)<<log2_blocksize);
for(j = 0; j < 2; j++, y_ptr += y_stride) {
for (i=0; i<2; i++, block += 64, mb++, y_ptr += (1<<log2_blocksize))
if (s->sys->pix_fmt == PIX_FMT_YUV422P && s->sys->width == 720 && i)
y_ptr -= (1<<log2_blocksize);
else
mb->idct_put(y_ptr, s->picture.linesize[0]<<is_field_mode[mb_index], block);
}
/* idct_put'ting chrominance */
c_offset = (((mb_y>>(s->sys->pix_fmt == PIX_FMT_YUV420P)) * s->picture.linesize[1] +
(mb_x>>((s->sys->pix_fmt == PIX_FMT_YUV411P)?2:1)))<<log2_blocksize);
for(j = 0;j < 6; j++) {
if (s->sys->pix_fmt == PIX_FMT_YUV422P) { /* 4:2:2 */
if (j == 0 || j == 2) {
/* Y0 Y1 */
mb->idct_put(y_ptr + ((j >> 1)<<log2_blocksize),
s->picture.linesize[0], block);
} else if(j > 3) {
/* Cr Cb */
mb->idct_put(s->picture.data[6 - j] + c_offset,
s->picture.linesize[6 - j], block);
}
/* note: j=1 and j=3 are "dummy" blocks in 4:2:2 */
} else { /* 4:1:1 or 4:2:0 */
if (j < 4) {
if (s->sys->pix_fmt == PIX_FMT_YUV411P && mb_x < (704 / 8)) {
/* NOTE: at end of line, the macroblock is handled as 420 */
mb->idct_put(y_ptr + (j<<log2_blocksize), s->picture.linesize[0], block);
} else {
mb->idct_put(y_ptr + (((j & 1) + (j >> 1) * s->picture.linesize[0])<<log2_blocksize),
s->picture.linesize[0], block);
}
} else {
if (s->sys->pix_fmt == PIX_FMT_YUV411P && mb_x >= (704 / 8)) {
uint64_t aligned_pixels[64/8];
uint8_t *pixels= (uint8_t*)aligned_pixels;
uint8_t *c_ptr, *c_ptr1, *ptr, *ptr1;
int x, y, linesize;
/* NOTE: at end of line, the macroblock is handled as 420 */
mb->idct_put(pixels, 8, block);
linesize = s->picture.linesize[6 - j];
c_ptr = s->picture.data[6 - j] + c_offset;
ptr = pixels;
for(y = 0;y < (1<<log2_blocksize); y++) {
ptr1= ptr + (1<<(log2_blocksize-1));
c_ptr1 = c_ptr + (linesize<<log2_blocksize);
for(x=0; x < (1<<(log2_blocksize-1)); x++){
c_ptr[x]= ptr[x]; c_ptr1[x]= ptr1[x];
}
c_ptr += linesize;
ptr += 8;
}
} else {
/* don't ask me why they inverted Cb and Cr ! */
mb->idct_put(s->picture.data[6 - j] + c_offset,
s->picture.linesize[6 - j], block);
}
}
for(j=2; j; j--) {
uint8_t *c_ptr = s->picture.data[j] + c_offset;
if (s->sys->pix_fmt == PIX_FMT_YUV411P && mb_x >= (704 / 8)) {
uint64_t aligned_pixels[64/8];
uint8_t *pixels = (uint8_t*)aligned_pixels;
uint8_t *c_ptr1, *ptr1;
int x, y;
mb->idct_put(pixels, 8, block);
for(y = 0; y < (1<<log2_blocksize); y++, c_ptr += s->picture.linesize[j], pixels += 8) {
ptr1= pixels + (1<<(log2_blocksize-1));
c_ptr1 = c_ptr + (s->picture.linesize[j]<<log2_blocksize);
for(x=0; x < (1<<(log2_blocksize-1)); x++) {
c_ptr[x]= pixels[x];
c_ptr1[x]= ptr1[x];
}
}
block += 64; mb++;
} else {
y_stride = (mb_y == 134) ? (1<<log2_blocksize) :
s->picture.linesize[j]<<((!is_field_mode[mb_index])*log2_blocksize);
for (i=0; i<(1<<(s->sys->bpm==8)); i++, block += 64, mb++, c_ptr += y_stride)
mb->idct_put(c_ptr, s->picture.linesize[j]<<is_field_mode[mb_index], block);
}
block += 64;
mb++;
}
}
}
......@@ -968,6 +988,11 @@ static int dv_decode_mt(AVCodecContext *avctx, void* sl)
/* DIF sequence */
int seq = chan_slice / 27;
/* in 1080i50 and 720p50 some seq are unused */
if ((DV_PROFILE_IS_1080i50(s->sys) && chan != 0 && seq == 11) ||
(DV_PROFILE_IS_720p50(s->sys) && seq > 9))
return 0;
dv_decode_video_segment(s, &s->buf[(seq*6+(chan_slice/3)+chan_slice*5+7)*80 + chan_offset],
&s->sys->video_place[slice*5]);
return 0;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -8,8 +8,9 @@
* Raw DV format
* Copyright (c) 2002 Fabrice Bellard.
*
* 50 Mbps (DVCPRO50) support
* 50 Mbps (DVCPRO50) and 100 Mbps (DVCPRO HD) support
* Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com>
* Funded by BBC Research & Development
*
* This file is part of FFmpeg.
*
......@@ -36,9 +37,9 @@ struct DVDemuxContext {
const DVprofile* sys; /* Current DV profile. E.g.: 525/60, 625/50 */
AVFormatContext* fctx;
AVStream* vst;
AVStream* ast[2];
AVPacket audio_pkt[2];
uint8_t audio_buf[2][8192];
AVStream* ast[4];
AVPacket audio_pkt[4];
uint8_t audio_buf[4][8192];
int ach;
int frames;
uint64_t abytes;
......@@ -98,12 +99,13 @@ static const uint8_t* dv_extract_pack(uint8_t* frame, enum dv_pack_type t)
* 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples
* are converted into 16bit linear ones.
*/
static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2,
static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4],
const DVprofile *sys)
{
int size, chan, i, j, d, of, smpls, freq, quant, half_ch;
uint16_t lc, rc;
const uint8_t* as_pack;
uint8_t *pcm, ipcm;
as_pack = dv_extract_pack(frame, dv_audio_source);
if (!as_pack) /* No audio ? */
......@@ -119,6 +121,10 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2,
size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
half_ch = sys->difseg_size/2;
/* We work with 720p frames split in half, thus even frames have channels 0,1 and odd 2,3 */
ipcm = (sys->height == 720 && ((frame[1]>>2)&0x3) == 0)?2:0;
pcm = ppcm[ipcm++];
/* for each DIF channel */
for (chan = 0; chan < sys->n_difchan; chan++) {
/* for each DIF segment */
......@@ -126,10 +132,9 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2,
frame += 6 * 80; /* skip DIF segment header */
if (quant == 1 && i == half_ch) {
/* next stereo channel (12bit mode only) */
if (!pcm2)
pcm = ppcm[ipcm++];
if (!pcm)
break;
else
pcm = pcm2;
}
/* for each AV sequence */
......@@ -170,10 +175,10 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2,
}
}
/* next stereo channel (50Mbps only) */
if(!pcm2)
/* next stereo channel (50Mbps and 100Mbps only) */
pcm = ppcm[ipcm++];
if (!pcm)
break;
pcm = pcm2;
}
return size;
......@@ -196,6 +201,9 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame)
quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
/* note: ach counts PAIRS of channels (i.e. stereo channels) */
if (stype == 3) {
ach = 4;
} else
ach = (stype == 2 || (quant && (freq == 2))) ? 2 : 1;
/* Dynamic handling of the audio streams in DV */
......@@ -310,6 +318,7 @@ int dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
uint8_t* buf, int buf_size)
{
int size, i;
uint8_t *ppcm[4] = {0};
if (buf_size < DV_PROFILE_BYTES ||
!(c->sys = dv_frame_profile(buf)) ||
......@@ -323,10 +332,19 @@ int dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
for (i=0; i<c->ach; i++) {
c->audio_pkt[i].size = size;
c->audio_pkt[i].pts = c->abytes * 30000*8 / c->ast[i]->codec->bit_rate;
ppcm[i] = c->audio_buf[i];
}
dv_extract_audio(buf, c->audio_buf[0], c->audio_buf[1], c->sys);
dv_extract_audio(buf, ppcm, c->sys);
c->abytes += size;
/* We work with 720p frames split in half, thus even frames have channels 0,1 and odd 2,3 */
if (c->sys->height == 720) {
if (((buf[1]>>2)&0x3))
c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
else
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
}
/* Now it's time to return video packet */
size = dv_extract_video_info(c, buf);
av_init_packet(pkt);
......@@ -366,6 +384,7 @@ void dv_offset_reset(DVDemuxContext *c, int64_t frame_offset)
c->ast[0]->codec->bit_rate * (int64_t)c->sys->frame_rate_base,
8*c->sys->frame_rate);
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
}
/************************************************************
......@@ -391,6 +410,11 @@ static int dv_read_header(AVFormatContext *s,
return AVERROR(EIO);
c->dv_demux->sys = dv_frame_profile(c->buf);
if (!c->dv_demux->sys) {
av_log(s, AV_LOG_ERROR, "Can't determine profile of DV input stream.\n");
return -1;
}
s->bit_rate = av_rescale(c->dv_demux->sys->frame_size * 8,
c->dv_demux->sys->frame_rate,
c->dv_demux->sys->frame_rate_base);
......
......@@ -87,8 +87,12 @@ const AVCodecTag codec_movvideo_tags[] = {
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'p') }, /* DVCPRO50 PAL produced by FCP */
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'n') }, /* DVCPRO50 NTSC produced by FCP */
{ CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', 'v') }, /* AVID DV */
//{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '5') }, /* DVCPRO HD 50i produced by FCP */
//{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '6') }, /* DVCPRO HD 60i produced by FCP */
{ CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', '1') }, /* AVID DV */
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'q') }, /* DVCPRO HD 720p50 */
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'p') }, /* DVCPRO HD 720p60 */
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '5') }, /* DVCPRO HD 50i produced by FCP */
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '6') }, /* DVCPRO HD 60i produced by FCP */
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '3') }, /* DVCPRO HD 30p produced by FCP */
{ CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, /* On2 VP3 */
{ CODEC_ID_RPZA, MKTAG('r', 'p', 'z', 'a') }, /* Apple Video (RPZA) */
......
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