summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2006-09-09 11:21:56 +0000
committerKostya Shishkov <kostya.shishkov@gmail.com>2006-09-09 11:21:56 +0000
commit1dc1ce643e141e78c7a10d98c51f3c9f01802e81 (patch)
treea104fc72f44510e7835c16a042f9b439ce2fc718
parent0288a7474b89fe388440f766de20a5cad66cd805 (diff)
Proper support for B/BI frames
Originally committed as revision 6207 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--libavcodec/vc1.c309
-rw-r--r--libavcodec/vc1data.h17
2 files changed, 274 insertions, 52 deletions
diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c
index f9d32fb4f8..1f1430317d 100644
--- a/libavcodec/vc1.c
+++ b/libavcodec/vc1.c
@@ -369,6 +369,7 @@ typedef struct VC1Context{
//@}
int p_frame_skipped;
+ int bi_type;
} VC1Context;
/**
@@ -778,8 +779,14 @@ static void vc1_mc_1mv(VC1Context *v, int dir)
if(!v->s.last_picture.data[0])return;
- mx = s->mv[0][0][0];
- my = s->mv[0][0][1];
+ mx = s->mv[dir][0][0];
+ my = s->mv[dir][0][1];
+
+ // store motion vectors for further use in B frames
+ if(s->pict_type == P_TYPE) {
+ s->current_picture.motion_val[1][s->block_index[0]][0] = mx;
+ s->current_picture.motion_val[1][s->block_index[0]][1] = my;
+ }
uvmx = (mx + ((mx & 3) == 3)) >> 1;
uvmy = (my + ((my & 3) == 3)) >> 1;
if(!dir) {
@@ -1040,6 +1047,8 @@ static void vc1_mc_4mv_chroma(VC1Context *v)
} else
return; //no need to do MC for inter blocks
+ s->current_picture.motion_val[1][s->block_index[0]][0] = tx;
+ s->current_picture.motion_val[1][s->block_index[0]][1] = ty;
uvmx = (tx + ((tx&3) == 3)) >> 1;
uvmy = (ty + ((ty&3) == 3)) >> 1;
@@ -1383,18 +1392,19 @@ static int vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
} else v->s.pict_type = P_TYPE;
} else v->s.pict_type = v->s.pict_type ? P_TYPE : I_TYPE;
- if(v->s.pict_type == I_TYPE)
- get_bits(gb, 7); // skip buffer fullness
+ v->bi_type = 0;
if(v->s.pict_type == B_TYPE) {
v->bfraction = get_vlc2(gb, vc1_bfraction_vlc.table, VC1_BFRACTION_VLC_BITS, 1);
v->bfraction = vc1_bfraction_lut[v->bfraction];
- if(v->bfraction == -1) {
+ if(v->bfraction == 0) {
v->s.pict_type = BI_TYPE;
}
}
+ if(v->s.pict_type == I_TYPE || v->s.pict_type == BI_TYPE)
+ get_bits(gb, 7); // skip buffer fullness
/* calculate RND */
- if(v->s.pict_type == I_TYPE)
+ if(v->s.pict_type == I_TYPE || v->s.pict_type == BI_TYPE)
v->rnd = 1;
if(v->s.pict_type == P_TYPE)
v->rnd ^= 1;
@@ -1568,6 +1578,10 @@ static int vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
/* DC Syntax */
v->s.dc_table_index = get_bits(gb, 1);
+ if(v->s.pict_type == BI_TYPE) {
+ v->s.pict_type = B_TYPE;
+ v->bi_type = 1;
+ }
return 0;
}
@@ -2078,71 +2092,242 @@ static void vc1_interp_mc(VC1Context *v)
dsp->avg_qpel_pixels_tab[1][uvdxy](s->dest[2], srcV, s->uvlinesize);
}
+static always_inline int scale_mv(int value, int bfrac, int inv, int qs)
+{
+ int n = bfrac;
+
+#if B_FRACTION_DEN==256
+ if(inv)
+ n -= 256;
+ if(!qs)
+ return 2 * ((value * n + 255) >> 9);
+ return (value * n + 128) >> 8;
+#else
+ if(inv)
+ n -= B_FRACTION_DEN;
+ if(!qs)
+ return 2 * ((value * n + B_FRACTION_DEN - 1) / (2 * B_FRACTION_DEN));
+ return (value * n + B_FRACTION_DEN/2) / B_FRACTION_DEN;
+#endif
+}
+
/** Reconstruct motion vector for B-frame and do motion compensation
*/
static inline void vc1_b_mc(VC1Context *v, int dmv_x[2], int dmv_y[2], int direct, int mode)
{
+ if(direct) {
+ vc1_mc_1mv(v, 0);
+ vc1_interp_mc(v);
+ return;
+ }
+ if(mode == BMV_TYPE_INTERPOLATED) {
+ vc1_mc_1mv(v, 0);
+ vc1_interp_mc(v);
+ return;
+ }
+
+ vc1_mc_1mv(v, (mode == BMV_TYPE_FORWARD));
+}
+
+static inline void vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], int direct, int mvtype)
+{
MpegEncContext *s = &v->s;
- int mx[4], my[4], mv_x, mv_y;
- int i;
+ int xy, wrap, off = 0;
+ int16_t *A, *B, *C;
+ int px, py;
+ int sum;
+ int r_x, r_y;
+ const uint8_t *is_intra = v->mb_type[0];
+ r_x = v->range_x;
+ r_y = v->range_y;
/* scale MV difference to be quad-pel */
dmv_x[0] <<= 1 - s->quarter_sample;
dmv_y[0] <<= 1 - s->quarter_sample;
dmv_x[1] <<= 1 - s->quarter_sample;
dmv_y[1] <<= 1 - s->quarter_sample;
- if(direct) {
- for(i = 0; i < 4; i++) {
- mx[i] = s->last_picture.motion_val[0][s->block_index[i]][0];
- my[i] = s->last_picture.motion_val[0][s->block_index[i]][1];
- }
- mv_x = median4(mx[0], mx[1], mx[2], mx[3]);
- mv_y = median4(my[0], my[1], my[2], my[3]);
- s->mv[0][0][0] = (mv_x * v->bfraction + B_FRACTION_DEN/2) / B_FRACTION_DEN;
- s->mv[0][0][1] = (mv_y * v->bfraction + B_FRACTION_DEN/2) / B_FRACTION_DEN;
- vc1_mc_1mv(v, 0);
+ wrap = s->b8_stride;
+ xy = s->block_index[0];
- for(i = 0; i < 4; i++) {
- mx[i] = s->next_picture.motion_val[0][s->block_index[i]][0];
- my[i] = s->next_picture.motion_val[0][s->block_index[i]][1];
- }
- mv_x = median4(mx[0], mx[1], mx[2], mx[3]);
- mv_y = median4(my[0], my[1], my[2], my[3]);
- s->mv[1][0][0] = (mv_x * (B_FRACTION_DEN - v->bfraction) + B_FRACTION_DEN/2) / B_FRACTION_DEN;
- s->mv[1][0][1] = (mv_y * (B_FRACTION_DEN - v->bfraction) + B_FRACTION_DEN/2) / B_FRACTION_DEN;
- vc1_interp_mc(v);
+ if(s->mb_intra) {
+ s->current_picture.motion_val[0][xy][0] =
+ s->current_picture.motion_val[0][xy][1] =
+ s->current_picture.motion_val[1][xy][0] =
+ s->current_picture.motion_val[1][xy][1] = 0;
return;
}
- if(mode == BMV_TYPE_INTERPOLATED) {
- s->mv[0][0][0] = dmv_x[0];
- s->mv[0][0][1] = dmv_y[0];
- vc1_mc_1mv(v, 0);
- s->mv[1][0][0] = dmv_x[1];
- s->mv[1][0][1] = dmv_y[1];
- vc1_interp_mc(v);
+ s->mv[0][0][0] = scale_mv(s->next_picture.motion_val[1][xy][0], v->bfraction, 1, s->quarter_sample);
+ s->mv[0][0][1] = scale_mv(s->next_picture.motion_val[1][xy][1], v->bfraction, 1, s->quarter_sample);
+ s->mv[1][0][0] = scale_mv(s->next_picture.motion_val[1][xy][0], v->bfraction, 0, s->quarter_sample);
+ s->mv[1][0][1] = scale_mv(s->next_picture.motion_val[1][xy][1], v->bfraction, 0, s->quarter_sample);
+ if(direct) {
+ s->current_picture.motion_val[0][xy][0] = s->mv[0][0][0];
+ s->current_picture.motion_val[0][xy][1] = s->mv[0][0][1];
+ s->current_picture.motion_val[1][xy][0] = s->mv[1][0][0];
+ s->current_picture.motion_val[1][xy][1] = s->mv[1][0][1];
return;
}
- if(mode == BMV_TYPE_BACKWARD) {
- for(i = 0; i < 4; i++) {
- mx[i] = s->last_picture.motion_val[0][s->block_index[i]][0];
- my[i] = s->last_picture.motion_val[0][s->block_index[i]][1];
+ if((mvtype == BMV_TYPE_BACKWARD) || (mvtype == BMV_TYPE_INTERPOLATED)) {
+ C = s->current_picture.motion_val[0][xy - 2];
+ A = s->current_picture.motion_val[0][xy - wrap*2];
+ off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2;
+ B = s->current_picture.motion_val[0][xy - wrap*2 + off];
+
+ if(!s->first_slice_line) { // predictor A is not out of bounds
+ if(s->mb_width == 1) {
+ px = A[0];
+ py = A[1];
+ } else {
+ px = mid_pred(A[0], B[0], C[0]);
+ py = mid_pred(A[1], B[1], C[1]);
+ }
+ } else if(s->mb_x) { // predictor C is not out of bounds
+ px = C[0];
+ py = C[1];
+ } else {
+ px = py = 0;
}
- } else {
- for(i = 0; i < 4; i++) {
- mx[i] = s->next_picture.motion_val[0][s->block_index[i]][0];
- my[i] = s->next_picture.motion_val[0][s->block_index[i]][1];
+ /* Pullback MV as specified in 8.3.5.3.4 */
+ {
+ int qx, qy, X, Y;
+ if(v->profile < PROFILE_ADVANCED) {
+ qx = (s->mb_x << 5);
+ qy = (s->mb_y << 5);
+ X = (s->mb_width << 5) - 4;
+ Y = (s->mb_height << 5) - 4;
+ if(qx + px < -28) px = -28 - qx;
+ if(qy + py < -28) py = -28 - qy;
+ if(qx + px > X) px = X - qx;
+ if(qy + py > Y) py = Y - qy;
+ } else {
+ qx = (s->mb_x << 6);
+ qy = (s->mb_y << 6);
+ X = (s->mb_width << 6) - 4;
+ Y = (s->mb_height << 6) - 4;
+ if(qx + px < -60) px = -60 - qx;
+ if(qy + py < -60) py = -60 - qy;
+ if(qx + px > X) px = X - qx;
+ if(qy + py > Y) py = Y - qy;
+ }
}
- }
-
- /* XXX: not right but how to determine 4-MV intra/inter in another frame? */
- mv_x = median4(mx[0], mx[1], mx[2], mx[3]);
- mv_y = median4(my[0], my[1], my[2], my[3]);
- s->mv[0][0][0] = mv_x;
- s->mv[0][0][1] = mv_y;
+ /* Calculate hybrid prediction as specified in 8.3.5.3.5 */
+ if(0 && !s->first_slice_line && s->mb_x) {
+ if(is_intra[xy - wrap])
+ sum = ABS(px) + ABS(py);
+ else
+ sum = ABS(px - A[0]) + ABS(py - A[1]);
+ if(sum > 32) {
+ if(get_bits1(&s->gb)) {
+ px = A[0];
+ py = A[1];
+ } else {
+ px = C[0];
+ py = C[1];
+ }
+ } else {
+ if(is_intra[xy - 2])
+ sum = ABS(px) + ABS(py);
+ else
+ sum = ABS(px - C[0]) + ABS(py - C[1]);
+ if(sum > 32) {
+ if(get_bits1(&s->gb)) {
+ px = A[0];
+ py = A[1];
+ } else {
+ px = C[0];
+ py = C[1];
+ }
+ }
+ }
+ }
+ /* store MV using signed modulus of MV range defined in 4.11 */
+ s->mv[0][0][0] = ((px + dmv_x[0] + r_x) & ((r_x << 1) - 1)) - r_x;
+ s->mv[0][0][1] = ((py + dmv_y[0] + r_y) & ((r_y << 1) - 1)) - r_y;
+ }
+ if((mvtype == BMV_TYPE_FORWARD) || (mvtype == BMV_TYPE_INTERPOLATED)) {
+ C = s->current_picture.motion_val[1][xy - 2];
+ A = s->current_picture.motion_val[1][xy - wrap*2];
+ off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2;
+ B = s->current_picture.motion_val[1][xy - wrap*2 + off];
+
+ if(!s->first_slice_line) { // predictor A is not out of bounds
+ if(s->mb_width == 1) {
+ px = A[0];
+ py = A[1];
+ } else {
+ px = mid_pred(A[0], B[0], C[0]);
+ py = mid_pred(A[1], B[1], C[1]);
+ }
+ } else if(s->mb_x) { // predictor C is not out of bounds
+ px = C[0];
+ py = C[1];
+ } else {
+ px = py = 0;
+ }
+ /* Pullback MV as specified in 8.3.5.3.4 */
+ {
+ int qx, qy, X, Y;
+ if(v->profile < PROFILE_ADVANCED) {
+ qx = (s->mb_x << 5);
+ qy = (s->mb_y << 5);
+ X = (s->mb_width << 5) - 4;
+ Y = (s->mb_height << 5) - 4;
+ if(qx + px < -28) px = -28 - qx;
+ if(qy + py < -28) py = -28 - qy;
+ if(qx + px > X) px = X - qx;
+ if(qy + py > Y) py = Y - qy;
+ } else {
+ qx = (s->mb_x << 6);
+ qy = (s->mb_y << 6);
+ X = (s->mb_width << 6) - 4;
+ Y = (s->mb_height << 6) - 4;
+ if(qx + px < -60) px = -60 - qx;
+ if(qy + py < -60) py = -60 - qy;
+ if(qx + px > X) px = X - qx;
+ if(qy + py > Y) py = Y - qy;
+ }
+ }
+ /* Calculate hybrid prediction as specified in 8.3.5.3.5 */
+ if(0 && !s->first_slice_line && s->mb_x) {
+ if(is_intra[xy - wrap])
+ sum = ABS(px) + ABS(py);
+ else
+ sum = ABS(px - A[0]) + ABS(py - A[1]);
+ if(sum > 32) {
+ if(get_bits1(&s->gb)) {
+ px = A[0];
+ py = A[1];
+ } else {
+ px = C[0];
+ py = C[1];
+ }
+ } else {
+ if(is_intra[xy - 2])
+ sum = ABS(px) + ABS(py);
+ else
+ sum = ABS(px - C[0]) + ABS(py - C[1]);
+ if(sum > 32) {
+ if(get_bits1(&s->gb)) {
+ px = A[0];
+ py = A[1];
+ } else {
+ px = C[0];
+ py = C[1];
+ }
+ }
+ }
+ }
+ /* store MV using signed modulus of MV range defined in 4.11 */
- vc1_mc_1mv(v, (mode == BMV_TYPE_FORWARD));
+ s->mv[1][0][0] = ((px + dmv_x[1] + r_x) & ((r_x << 1) - 1)) - r_x;
+ s->mv[1][0][1] = ((py + dmv_y[1] + r_y) & ((r_y << 1) - 1)) - r_y;
+ }
+ s->current_picture.motion_val[0][xy][0] = s->mv[0][0][0];
+ s->current_picture.motion_val[0][xy][1] = s->mv[0][0][1];
+ s->current_picture.motion_val[1][xy][0] = s->mv[1][0][0];
+ s->current_picture.motion_val[1][xy][1] = s->mv[1][0][1];
}
/** Get predicted DC value for I-frames only
@@ -3101,6 +3286,10 @@ static int vc1_decode_p_mb(VC1Context *v)
{
GET_MVDATA(dmv_x, dmv_y);
+ if (s->mb_intra) {
+ s->current_picture.motion_val[1][s->block_index[0]][0] = 0;
+ s->current_picture.motion_val[1][s->block_index[0]][1] = 0;
+ }
s->current_picture.mb_type[mb_pos] = s->mb_intra ? MB_TYPE_INTRA : MB_TYPE_16x16;
vc1_pred_mv(s, 0, dmv_x, dmv_y, 1, v->range_x, v->range_y, v->mb_type[0]);
@@ -3354,10 +3543,16 @@ static void vc1_decode_b_mb(VC1Context *v)
break;
case 2:
bmvtype = BMV_TYPE_INTERPOLATED;
+ dmv_x[1] = dmv_y[1] = 0;
}
}
}
+ for(i = 0; i < 6; i++)
+ v->mb_type[0][s->block_index[i]] = s->mb_intra;
+
if (skipped) {
+ if(direct) bmvtype = BMV_TYPE_INTERPOLATED;
+ vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
return;
}
@@ -3369,10 +3564,13 @@ static void vc1_decode_b_mb(VC1Context *v)
s->current_picture.qscale_table[mb_pos] = mquant;
if(!v->ttmbf)
ttmb = get_vlc2(gb, vc1_ttmb_vlc[v->tt_index].table, VC1_TTMB_VLC_BITS, 2);
+ dmv_x[0] = dmv_y[0] = dmv_x[1] = dmv_y[1] = 0;
+ vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
} else {
if(!mb_has_coeffs && !s->mb_intra) {
/* no coded blocks - effectively skipped */
+ vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
return;
}
@@ -3381,17 +3579,21 @@ static void vc1_decode_b_mb(VC1Context *v)
s->current_picture.qscale_table[mb_pos] = mquant;
s->ac_pred = get_bits1(gb);
cbp = 0;
+ vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
} else {
if(bmvtype == BMV_TYPE_INTERPOLATED) {
GET_MVDATA(dmv_x[1], dmv_y[1]);
if(!mb_has_coeffs) {
/* interpolated skipped block */
+ vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
return;
}
}
- if(!s->mb_intra)
+ vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype);
+ if(!s->mb_intra) {
vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype);
+ }
if(s->mb_intra)
s->ac_pred = get_bits1(gb);
cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc->table, VC1_CBPCY_P_VLC_BITS, 2);
@@ -3804,7 +4006,10 @@ static void vc1_decode_blocks(VC1Context *v)
vc1_decode_p_blocks(v);
break;
case B_TYPE:
- vc1_decode_b_blocks(v);
+ if(v->bi_type)
+ vc1_decode_i_blocks(v);
+ else
+ vc1_decode_b_blocks(v);
break;
}
}
diff --git a/libavcodec/vc1data.h b/libavcodec/vc1data.h
index 9f9e21b4a4..bffa7b83b3 100644
--- a/libavcodec/vc1data.h
+++ b/libavcodec/vc1data.h
@@ -6,6 +6,7 @@
#ifndef VC1DATA_H
#define VC1DATA_H
+#if 0 //original bfraction from vc9data.h, not conforming to standard
/* Denominator used for vc1_bfraction_lut */
#define B_FRACTION_DEN 840
@@ -19,6 +20,22 @@ const int16_t vc1_bfraction_lut[23] = {
525 /*5/8*/, 735 /*7/8*/,
-1 /*inv.*/, 0 /*BI fm*/
};
+#else
+/* Denominator used for vc1_bfraction_lut */
+#define B_FRACTION_DEN 256
+
+/* pre-computed scales for all bfractions and base=256 */
+const int16_t vc1_bfraction_lut[23] = {
+ 128 /*1/2*/, 85 /*1/3*/, 170 /*2/3*/, 64 /*1/4*/,
+ 192 /*3/4*/, 51 /*1/5*/, 102 /*2/5*/,
+ 153 /*3/5*/, 204 /*4/5*/, 43 /*1/6*/, 215 /*5/6*/,
+ 37 /*1/7*/, 74 /*2/7*/, 111 /*3/7*/, 148 /*4/7*/,
+ 185 /*5/7*/, 222 /*6/7*/, 32 /*1/8*/, 96 /*3/8*/,
+ 160 /*5/8*/, 224 /*7/8*/,
+ -1 /*inv.*/, 0 /*BI fm*/
+};
+#endif
+
const uint8_t vc1_bfraction_bits[23] = {
3, 3, 3, 3,
3, 3, 3,