* 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.
*
uint8_t *buf;
uint8_t dv_zigzag[2][64];
- uint8_t dv_idct_shift[2][2][22][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);
/* 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];
static void dv_build_unquantize_tables(DVVideoContext *s, uint8_t* perm)
{
- int i, q, j;
+ int i, q, a;
/* NOTE: max left shift is 6 */
for(q = 0; q < 22; q++) {
/* 88DCT */
- for(i = 1; i < 64; i++) {
- /* 88 table */
- j = perm[i];
- s->dv_idct_shift[0][0][q][j] =
- dv_quant_shifts[q][dv_88_areas[i]] + 1;
- s->dv_idct_shift[1][0][q][j] = s->dv_idct_shift[0][0][q][j] + 1;
+ i=1;
+ for(a = 0; a<4; a++) {
+ for(; i < dv_quant_areas[a]; i++) {
+ /* 88 table */
+ s->dv_idct_factor[0][0][q][i] = dv_iweight_88[i]<<(dv_quant_shifts[q][a] + 1);
+ s->dv_idct_factor[1][0][q][i] = s->dv_idct_factor[0][0][q][i]<<1;
+
+ /* 248 table */
+ s->dv_idct_factor[0][1][q][i] = dv_iweight_248[i]<<(dv_quant_shifts[q][a] + 1);
+ s->dv_idct_factor[1][1][q][i] = s->dv_idct_factor[0][1][q][i]<<1;
+ }
}
+ }
- /* 248DCT */
- for(i = 1; i < 64; i++) {
- /* 248 table */
- s->dv_idct_shift[0][1][q][i] =
- dv_quant_shifts[q][dv_248_areas[i]] + 1;
- s->dv_idct_shift[1][1][q][i] = s->dv_idct_shift[0][1][q][i] + 1;
+ 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 int dvvideo_init(AVCodecContext *avctx)
+static av_cold int dvvideo_init(AVCodecContext *avctx)
{
DVVideoContext *s = avctx->priv_data;
DSPContext dsp;
// #define printf(...) av_log(NULL, AV_LOG_ERROR, __VA_ARGS__)
typedef struct BlockInfo {
- const uint8_t *shift_table;
+ const uint32_t *factor_table;
const uint8_t *scan_table;
- const int *iweight_table;
uint8_t pos; /* position in block */
- uint8_t dct_mode;
+ void (*idct_put)(uint8_t *dest, int line_size, DCTELEM *block);
uint8_t partial_bit_count;
uint16_t partial_bit_buffer;
int shift_offset;
} BlockInfo;
-/* block size in bits */
-static const uint16_t block_sizes[6] = {
- 112, 112, 112, 112, 80, 80
-};
/* bit budget for AC only in 5 MBs */
static const int vs_total_ac_bits = (100 * 4 + 68*2) * 5;
/* see dv_88_areas and dv_248_areas for details */
return s->size_in_bits - get_bits_count(s);
}
-static inline int get_bits_size(GetBitContext *s)
-{
- return s->size_in_bits;
-}
-
static inline int put_bits_left(PutBitContext* s)
{
return (s->buf_end - s->buf) * 8 - put_bits_count(s);
/* decode ac coefs */
static void dv_decode_ac(GetBitContext *gb, BlockInfo *mb, DCTELEM *block)
{
- int last_index = get_bits_size(gb);
+ int last_index = gb->size_in_bits;
const uint8_t *scan_table = mb->scan_table;
- const uint8_t *shift_table = mb->shift_table;
- const int *iweight_table = mb->iweight_table;
+ const uint32_t *factor_table = mb->factor_table;
int pos = mb->pos;
int partial_bit_count = mb->partial_bit_count;
- int level, pos1, run, vlc_len, index;
+ int level, run, vlc_len, index;
OPEN_READER(re, gb);
UPDATE_CACHE(re, gb);
if (pos >= 64)
break;
- pos1 = scan_table[pos];
- level <<= shift_table[pos1];
-
- /* unweigh, round, and shift down */
- level = (level*iweight_table[pos] + (1 << (dv_iweight_bits-1))) >> dv_iweight_bits;
-
- block[pos1] = level;
+ level = (level*factor_table[pos] + (1 << (dv_iweight_bits-1))) >> dv_iweight_bits;
+ block[scan_table[pos]] = level;
UPDATE_CACHE(re, gb);
}
{
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;
- void (*idct_put)(uint8_t *dest, int line_size, DCTELEM *block);
const uint8_t *buf_ptr;
PutBitContext pb, vs_pb;
GetBitContext gb;
- BlockInfo mb_data[5 * 6], *mb, *mb1;
- DECLARE_ALIGNED_8(DCTELEM, sblock[5*6][64]);
+ BlockInfo mb_data[5 * DV_MAX_BPM], *mb, *mb1;
+ DECLARE_ALIGNED_16(DCTELEM, sblock[5*DV_MAX_BPM][64]);
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);
block1 = &sblock[0][0];
mb1 = mb_data;
init_put_bits(&vs_pb, vs_bit_buffer, 5 * 80);
- for(mb_index = 0; mb_index < 5; mb_index++, mb1 += 6, block1 += 6 * 64) {
+ for(mb_index = 0; mb_index < 5; mb_index++, mb1 += s->sys->bpm, block1 += s->sys->bpm * 64) {
/* skip header */
quant = buf_ptr[3] & 0x0f;
buf_ptr += 4;
init_put_bits(&pb, mb_bit_buffer, 80);
mb = mb1;
block = block1;
- for(j = 0;j < 6; j++) {
- last_index = block_sizes[j];
+ 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);
/* get the dc */
dc = get_sbits(&gb, 9);
dct_mode = get_bits1(&gb);
- mb->dct_mode = dct_mode;
- mb->scan_table = s->dv_zigzag[dct_mode];
- mb->iweight_table = dct_mode ? dv_iweight_248 : dv_iweight_88;
class1 = get_bits(&gb, 2);
- mb->shift_table = s->dv_idct_shift[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 */
mb = mb1;
init_get_bits(&gb, mb_bit_buffer, put_bits_count(&pb));
flush_put_bits(&pb);
- for(j = 0;j < 6; j++, block += 64, mb++) {
+ for(j = 0;j < s->sys->bpm; j++, block += 64, mb++) {
if (mb->pos < 64 && get_bits_left(&gb) > 0) {
dv_decode_ac(&gb, mb, block);
/* if still not finished, no need to parse other blocks */
}
/* all blocks are finished, so the extra bytes can be used at
the video segment level */
- if (j >= 6)
+ if (j >= s->sys->bpm)
bit_copy(&vs_pb, &gb);
}
init_get_bits(&gb, vs_bit_buffer, put_bits_count(&vs_pb));
flush_put_bits(&vs_pb);
for(mb_index = 0; mb_index < 5; mb_index++) {
- for(j = 0;j < 6; j++) {
+ for(j = 0;j < s->sys->bpm; j++) {
if (mb->pos < 64) {
#ifdef VLC_DEBUG
printf("start %d:%d\n", mb_index, j);
v = *mb_pos_ptr++;
mb_x = v & 0xff;
mb_y = v >> 8;
- if (s->sys->pix_fmt == PIX_FMT_YUV422P) {
- y_ptr = s->picture.data[0] + ((mb_y * s->picture.linesize[0] + (mb_x>>1))<<log2_blocksize);
- c_offset = ((mb_y * s->picture.linesize[1] + (mb_x >> 2))<<log2_blocksize);
- } else { /* 4:1:1 or 4:2:0 */
- y_ptr = s->picture.data[0] + ((mb_y * s->picture.linesize[0] + mb_x)<<log2_blocksize);
- if (s->sys->pix_fmt == PIX_FMT_YUV411P)
- c_offset = ((mb_y * s->picture.linesize[1] + (mb_x >> 2))<<log2_blocksize);
- else /* 4:2:0 */
- c_offset = (((mb_y >> 1) * s->picture.linesize[1] + (mb_x >> 1))<<log2_blocksize);
+ /* 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 */
}
- for(j = 0;j < 6; j++) {
- idct_put = s->idct_put[mb->dct_mode && log2_blocksize==3];
- if (s->sys->pix_fmt == PIX_FMT_YUV422P) { /* 4:2:2 */
- if (j == 0 || j == 2) {
- /* Y0 Y1 */
- idct_put(y_ptr + ((j >> 1)<<log2_blocksize),
- s->picture.linesize[0], block);
- } else if(j > 3) {
- /* Cr Cb */
- 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 */
- idct_put(y_ptr + (j<<log2_blocksize), s->picture.linesize[0], block);
- } else {
- 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 */
- 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 ! */
- idct_put(s->picture.data[6 - j] + c_offset,
- s->picture.linesize[6 - j], 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 {
+ 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=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++;
}
}
}
v = *mb_pos_ptr++;
mb_x = v & 0xff;
mb_y = v >> 8;
- if (s->sys->pix_fmt == PIX_FMT_YUV422P) {
- y_ptr = s->picture.data[0] + (mb_y * s->picture.linesize[0] * 8) + (mb_x * 4);
- } else { /* 4:1:1 */
- y_ptr = s->picture.data[0] + (mb_y * s->picture.linesize[0] * 8) + (mb_x * 8);
- }
- if (s->sys->pix_fmt == PIX_FMT_YUV420P) {
- c_offset = (((mb_y >> 1) * s->picture.linesize[1] * 8) + ((mb_x >> 1) * 8));
- } else { /* 4:2:2 or 4:1:1 */
- c_offset = ((mb_y * s->picture.linesize[1] * 8) + ((mb_x >> 2) * 8));
- }
+ y_ptr = s->picture.data[0] + ((mb_y * s->picture.linesize[0] + mb_x)<<3);
+ 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)))<<3);
do_edge_wrap = 0;
qnos[mb_index] = 15; /* No quantization */
ptr = dif + mb_index*80 + 4;
enc_blk->dct_mode ? dv_weight_248 : dv_weight_88,
j/4);
- init_put_bits(pb, ptr, block_sizes[j]/8);
+ init_put_bits(pb, ptr, s->sys->block_sizes[j]/8);
put_bits(pb, 9, (uint16_t)(((enc_blk->mb[0] >> 3) - 1024 + 2) >> 2));
put_bits(pb, 1, enc_blk->dct_mode);
put_bits(pb, 2, enc_blk->cno);
enc_blk->bit_size[2] + enc_blk->bit_size[3];
++enc_blk;
++pb;
- ptr += block_sizes[j]/8;
+ ptr += s->sys->block_sizes[j]/8;
}
}
/* byte offset of this channel's data */
int chan_offset = chan * s->sys->difseg_size * 150 * 80;
- dv_decode_video_segment(s, &s->buf[((chan_slice/27)*6+(chan_slice/3)+chan_slice*5+7)*80 + chan_offset],
+ /* 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;
}
-#ifdef CONFIG_ENCODERS
+#ifdef CONFIG_DVVIDEO_ENCODER
static int dv_encode_mt(AVCodecContext *avctx, void* sl)
{
DVVideoContext *s = avctx->priv_data;
s->picture.key_frame = 1;
s->picture.pict_type = FF_I_TYPE;
avctx->pix_fmt = s->sys->pix_fmt;
+ avctx->time_base = (AVRational){s->sys->frame_rate_base, s->sys->frame_rate};
avcodec_set_dimensions(avctx, s->sys->width, s->sys->height);
if(avctx->get_buffer(avctx, &s->picture) < 0) {
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return 5;
}
+#ifdef CONFIG_DVVIDEO_ENCODER
static void dv_format_frame(DVVideoContext* c, uint8_t* buf)
{
int chan, i, j, k;
}
-#ifdef CONFIG_ENCODERS
static int dvvideo_encode_frame(AVCodecContext *c, uint8_t *buf, int buf_size,
void *data)
{
sizeof(DVVideoContext),
dvvideo_init,
dvvideo_encode_frame,
- .pix_fmts = (enum PixelFormat[]) {PIX_FMT_YUV411P, PIX_FMT_YUV422P, PIX_FMT_YUV420P, -1},
+ .pix_fmts = (enum PixelFormat[]) {PIX_FMT_YUV411P, PIX_FMT_YUV422P, PIX_FMT_YUV420P, PIX_FMT_NONE},
+ .long_name = NULL_IF_CONFIG_SMALL("DV (Digital Video)"),
};
#endif // CONFIG_DVVIDEO_ENCODER
dvvideo_close,
dvvideo_decode_frame,
CODEC_CAP_DR1,
- NULL
+ NULL,
+ .long_name = NULL_IF_CONFIG_SMALL("DV (Digital Video)"),
};
#endif