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
This commit is contained in:
parent
42f72a3ac4
commit
f8007a1473
@ -1,6 +1,7 @@
|
||||
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
|
||||
|
137
libavcodec/dv.c
137
libavcodec/dv.c
@ -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;
|
||||
|
3722
libavcodec/dvdata.h
3722
libavcodec/dvdata.h
File diff suppressed because it is too large
Load Diff
@ -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) */
|
||||
|
Loading…
x
Reference in New Issue
Block a user