|
|
|
@@ -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; |
|
|
|
|