Commit 79f76632 authored by romansh's avatar romansh

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

specified in SMPTE 370M



git-svn-id: file:///var/local/repositories/ffmpeg/trunk@15010 9553f0bf-9b14-0410-a0b8-cfaf0461ba5b
parent ced7583c
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);
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;
y_ptr = s->picture.data[0] + ((mb_y * s->picture.linesize[0] + mb_x)<<log2_blocksize);
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);
/* 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 */
}
/* 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);
/* 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 {
mb->idct_put(y_ptr + (((j & 1) + (j >> 1) * s->picture.linesize[0])<<log2_blocksize),
s->picture.linesize[0], block);
y_stride = 0;
}
} else {
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=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_ptr, *c_ptr1, *ptr, *ptr1;
int x, y, linesize;
/* NOTE: at end of line, the macroblock is handled as 420 */
uint8_t *pixels = (uint8_t*)aligned_pixels;
uint8_t *c_ptr1, *ptr1;
int x, y;
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];
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];
}
c_ptr += linesize;
ptr += 8;
}
block += 64; mb++;
} 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);
}
}
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