Current scaling code is buggy and twisted. This patch re-implements it.
This fixes visible artifacts in a number of samples.
The code in scale_field_mv follows corresponding code from reference
decoder. I do not take credit for the code itself.
---
libavcodec/vc1.c | 34 +++++--
libavcodec/vc1.h | 9 ++-
libavcodec/vc1data.c | 55 ++++-------
libavcodec/vc1data.h | 6 +-
libavcodec/vc1dec.c | 250 ++++++++++++--------------------------------------
5 files changed, 114 insertions(+), 240 deletions(-)
diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c
index 0e218af..37c9922 100644
--- a/libavcodec/vc1.c
+++ b/libavcodec/vc1.c
@@ -892,20 +892,27 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v,
GetBitContext* gb)
if (v->interlace)
v->uvsamp = get_bits1(gb);
if (v->field_mode) {
+ int brfd, frfd;
+ VC1FieldMVScalingContext *scalectx = &v->scalectx;
if (!v->refdist_flag)
- v->refdist = 0;
+ scalectx->p_refdist = 0;
else if ((v->s.pict_type != AV_PICTURE_TYPE_B) && (v->s.pict_type !=
AV_PICTURE_TYPE_BI)) {
- v->refdist = get_bits(gb, 2);
- if (v->refdist == 3)
- v->refdist += get_unary(gb, 0, 16);
+ frfd = get_bits(gb, 2);
+ if (frfd == 3)
+ frfd += get_unary(gb, 0, 16);
+ if (frfd > 3)
+ frfd = 3;
+ scalectx->p_refdist = frfd;
}
if ((v->s.pict_type == AV_PICTURE_TYPE_B) || (v->s.pict_type ==
AV_PICTURE_TYPE_BI)) {
v->bfraction_lut_index = get_vlc2(gb, ff_vc1_bfraction_vlc.table,
VC1_BFRACTION_VLC_BITS, 1);
v->bfraction =
ff_vc1_bfraction_lut[v->bfraction_lut_index];
- v->frfd = (v->bfraction * v->refdist) >> 8;
- v->brfd = v->refdist - v->frfd - 1;
- if (v->brfd < 0)
- v->brfd = 0;
+ frfd = (v->bfraction * scalectx->p_refdist) >> 8;
+ brfd = av_clip(scalectx->p_refdist - frfd - 1, 0, 3);
+ if (frfd > 3)
+ frfd = 3;
+ scalectx->b_refdist[0] = frfd;
+ scalectx->b_refdist[1] = brfd;
}
goto parse_common_info;
}
@@ -988,6 +995,9 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v,
GetBitContext* gb)
v->reffield = get_bits1(gb);
v->ref_field_type[0] = v->reffield ^ !v->cur_field_type;
}
+ v->scalectx.field_mv_scales_tab[0] =
+
vc1_field_mvpred_scales[v->second_field][v->scalectx.p_refdist];
+ v->scalectx.field_mv_scales_tab[1] = NULL;
}
if (v->extended_mv)
v->mvrange = get_unary(gb, 0, 3);
@@ -1182,6 +1192,14 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v,
GetBitContext* gb)
v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[fourmvbptab];
}
v->numref = 1; // interlaced field B pictures are always 2-ref
+ v->scalectx.field_mv_scales_tab[0] =
+
vc1_field_mvpred_scales[v->second_field][v->scalectx.b_refdist[0]];
+ if (v->second_field)
+ v->scalectx.field_mv_scales_tab[1] =
+ vc1_field_mvpred_scales[0][v->scalectx.b_refdist[1]];
+ else
+ v->scalectx.field_mv_scales_tab[1] =
+ vc1_field_mvpred_scales[2][v->scalectx.b_refdist[1]];
} else {
v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV :
MV_PMODE_1MV_HPEL_BILIN;
v->qs_last = v->s.quarter_sample;
diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h
index 5806b80..da48218 100644
--- a/libavcodec/vc1.h
+++ b/libavcodec/vc1.h
@@ -174,6 +174,12 @@ enum FrameCodingMode {
ILACE_FIELD ///< in the bitstream is reported as 11b
};
+typedef struct VC1FieldMVScalingContext {
+ const uint16_t *field_mv_scales_tab[2];
+ int p_refdist;
+ int b_refdist[2];
+} VC1FieldMVScalingContext;
+
/** The VC1 Context
* @todo Change size wherever another size is more efficient
* Many members are only used for Advanced Profile
@@ -182,6 +188,7 @@ typedef struct VC1Context{
MpegEncContext s;
IntraX8Context x8;
VC1DSPContext vc1dsp;
+ VC1FieldMVScalingContext scalectx;
int bits;
@@ -357,7 +364,6 @@ typedef struct VC1Context{
int field_mode; ///< 1 for interlaced field pictures
int fptype;
int second_field;
- int refdist; ///< distance of the current picture from reference
int numref; ///< number of past field pictures used as
reference
// 0 corresponds to 1 and 1 corresponds to 2
references
int reffield; ///< if numref = 0 (1 reference) then reffield
decides which
@@ -369,7 +375,6 @@ typedef struct VC1Context{
int blocks_off, mb_off;
int qs_last; ///< if qpel has been used in the previous (tr.)
picture
int bmvtype;
- int frfd, brfd; ///< reference frame distance (forward or backward)
int pic_header_flag;
/** Frame decoding info for sprite modes */
diff --git a/libavcodec/vc1data.c b/libavcodec/vc1data.c
index 70cead8..dd8a31c 100644
--- a/libavcodec/vc1data.c
+++ b/libavcodec/vc1data.c
@@ -1093,41 +1093,26 @@ const int32_t ff_vc1_dqscale[63] = {
0x11F7, 0x11A8, 0x115B, 0x1111, 0x10C9, 0x1084, 0x1000
};
-/* P Interlaced field picture MV predictor scaling values (Table 114) */
-const uint16_t ff_vc1_field_mvpred_scales[2][7][4] = {
-// Refdist:
-// 0 1 2 3 or greater
- { // current field is first
- { 128, 192, 213, 224 }, // SCALEOPP
- { 512, 341, 307, 293 }, // SCALESAME1
- { 219, 236, 242, 245 }, // SCALESAME2
- { 32, 48, 53, 56 }, // SCALEZONE1_X
- { 8, 12, 13, 14 }, // SCALEZONE1_Y
- { 37, 20, 14, 11 }, // ZONE1OFFSET_X
- { 10, 5, 4, 3 } // ZONE1OFFSET_Y
- },
- { // current field is second
- { 128, 64, 43, 32 }, // SCALEOPP
- { 512, 1024, 1536, 2048 }, // SCALESAME1
- { 219, 204, 200, 198 }, // SCALESAME2
- { 32, 16, 11, 8 }, // SCALEZONE1_X
- { 8, 4, 3, 2 }, // SCALEZONE1_Y
- { 37, 52, 56, 58 }, // ZONE1OFFSET_X
- { 10, 13, 14, 15 } // ZONE1OFFSET_Y
- }
-};
-
-/* B Interlaced field picture backward MV predictor scaling values for first
field (Table 115) */
-const uint16_t ff_vc1_b_field_mvpred_scales[7][4] = {
- // BRFD:
- // 0 1 2 3 or greater
- { 171, 205, 219, 228 }, // SCALESAME
- { 384, 320, 299, 288 }, // SCALEOPP1
- { 230, 239, 244, 246 }, // SCALEOPP2
- { 43, 51, 55, 57 }, // SCALEZONE1_X
- { 11, 13, 14, 14 }, // SCALEZONE1_Y
- { 26, 17, 12, 10 }, // ZONE1OFFSET_X
- { 7, 4, 3, 3 } // ZONE1OFFSET_Y
+/* Interlaced field picture MV predictor scaling values */
+const uint16_t vc1_field_mvpred_scales[3][4][8] = {
+ { /* Forward 1st or Backward 2nd */
+ { 128, 512, 219, 32, 8, 37, 10, 0 },
+ { 192, 341, 236, 48, 12, 20, 5, 0 },
+ { 213, 307, 242, 53, 13, 14, 4, 0 },
+ { 224, 293, 245, 56, 14, 11, 3, 0 }
+ },
+ { /* Forward 2nd */
+ { 128, 512, 219, 32, 8, 37, 10, 0 },
+ { 64, 1024, 204, 16, 4, 52, 13, 0 },
+ { 43, 1536, 200, 11, 3, 56, 14, 0 },
+ { 32, 2048, 198, 8, 2, 58, 15, 0 }
+ },
+ { /* Backward 1st */
+ { 171, 384, 230, 43, 11, 26, 7, 1 },
+ { 205, 320, 239, 51, 13, 17, 4, 1 },
+ { 219, 299, 244, 55, 14, 12, 3, 1 },
+ { 228, 288, 246, 57, 14, 10, 3, 1 }
+ }
};
const int ff_vc1_ac_sizes[AC_MODES] = {
diff --git a/libavcodec/vc1data.h b/libavcodec/vc1data.h
index 84e8188..4aaaa55 100644
--- a/libavcodec/vc1data.h
+++ b/libavcodec/vc1data.h
@@ -196,10 +196,8 @@ extern const int8_t ff_vc1_intra_vert_8x8_zz [64];
/* DQScale as specified in 8.1.3.9 - almost identical to 0x40000/i */
extern const int32_t ff_vc1_dqscale[63];
-/* P Interlaced field picture MV predictor scaling values (Table 114) */
-extern const uint16_t ff_vc1_field_mvpred_scales[2][7][4];
-/* B Interlaced field picture backward MV predictor scaling values for first
field (Table 115) */
-extern const uint16_t ff_vc1_b_field_mvpred_scales[7][4];
+/* Interlaced field picture MV predictor scaling values */
+extern const uint16_t vc1_field_mvpred_scales[3][4][8];
#define AC_MODES 8
diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c
index 7b0b8c9..22ad325 100644
--- a/libavcodec/vc1dec.c
+++ b/libavcodec/vc1dec.c
@@ -1164,177 +1164,57 @@ static av_always_inline void
get_mvdata_interlaced(VC1Context *v, int *dmv_x,
}
}
-static av_always_inline int scaleforsame_x(VC1Context *v, int n /* MV */, int
dir)
+static void scale_field_mv(VC1Context *v, int16_t *mv, int opp, int dir)
{
- int scaledvalue, refdist;
- int scalesame1, scalesame2;
- int scalezone1_x, zone1offset_x;
- int table_index = dir ^ v->second_field;
-
- if (v->s.pict_type != AV_PICTURE_TYPE_B)
- refdist = v->refdist;
- else
- refdist = dir ? v->brfd : v->frfd;
- if (refdist > 3)
- refdist = 3;
- scalesame1 = ff_vc1_field_mvpred_scales[table_index][1][refdist];
- scalesame2 = ff_vc1_field_mvpred_scales[table_index][2][refdist];
- scalezone1_x = ff_vc1_field_mvpred_scales[table_index][3][refdist];
- zone1offset_x = ff_vc1_field_mvpred_scales[table_index][5][refdist];
-
- if (FFABS(n) > 255)
- scaledvalue = n;
- else {
- if (FFABS(n) < scalezone1_x)
- scaledvalue = (n * scalesame1) >> 8;
- else {
- if (n < 0)
- scaledvalue = ((n * scalesame2) >> 8) - zone1offset_x;
- else
- scaledvalue = ((n * scalesame2) >> 8) + zone1offset_x;
- }
- }
- return av_clip(scaledvalue, -v->range_x, v->range_x - 1);
-}
-
-static av_always_inline int scaleforsame_y(VC1Context *v, int i, int n /* MV
*/, int dir)
-{
- int scaledvalue, refdist;
- int scalesame1, scalesame2;
- int scalezone1_y, zone1offset_y;
- int table_index = dir ^ v->second_field;
-
- if (v->s.pict_type != AV_PICTURE_TYPE_B)
- refdist = v->refdist;
- else
- refdist = dir ? v->brfd : v->frfd;
- if (refdist > 3)
- refdist = 3;
- scalesame1 = ff_vc1_field_mvpred_scales[table_index][1][refdist];
- scalesame2 = ff_vc1_field_mvpred_scales[table_index][2][refdist];
- scalezone1_y = ff_vc1_field_mvpred_scales[table_index][4][refdist];
- zone1offset_y = ff_vc1_field_mvpred_scales[table_index][6][refdist];
-
- if (FFABS(n) > 63)
- scaledvalue = n;
- else {
- if (FFABS(n) < scalezone1_y)
- scaledvalue = (n * scalesame1) >> 8;
- else {
- if (n < 0)
- scaledvalue = ((n * scalesame2) >> 8) - zone1offset_y;
- else
- scaledvalue = ((n * scalesame2) >> 8) + zone1offset_y;
- }
- }
-
- if (v->cur_field_type && !v->ref_field_type[dir])
- return av_clip(scaledvalue, -v->range_y / 2 + 1, v->range_y / 2);
- else
- return av_clip(scaledvalue, -v->range_y / 2, v->range_y / 2 - 1);
-}
-
-static av_always_inline int scaleforopp_x(VC1Context *v, int n /* MV */)
-{
- int scalezone1_x, zone1offset_x;
- int scaleopp1, scaleopp2, brfd;
- int scaledvalue;
-
- brfd = FFMIN(v->brfd, 3);
- scalezone1_x = ff_vc1_b_field_mvpred_scales[3][brfd];
- zone1offset_x = ff_vc1_b_field_mvpred_scales[5][brfd];
- scaleopp1 = ff_vc1_b_field_mvpred_scales[1][brfd];
- scaleopp2 = ff_vc1_b_field_mvpred_scales[2][brfd];
-
- if (FFABS(n) > 255)
- scaledvalue = n;
- else {
- if (FFABS(n) < scalezone1_x)
- scaledvalue = (n * scaleopp1) >> 8;
- else {
- if (n < 0)
- scaledvalue = ((n * scaleopp2) >> 8) - zone1offset_x;
- else
- scaledvalue = ((n * scaleopp2) >> 8) + zone1offset_x;
- }
- }
- return av_clip(scaledvalue, -v->range_x, v->range_x - 1);
-}
-
-static av_always_inline int scaleforopp_y(VC1Context *v, int n /* MV */, int
dir)
-{
- int scalezone1_y, zone1offset_y;
- int scaleopp1, scaleopp2, brfd;
- int scaledvalue;
-
- brfd = FFMIN(v->brfd, 3);
- scalezone1_y = ff_vc1_b_field_mvpred_scales[4][brfd];
- zone1offset_y = ff_vc1_b_field_mvpred_scales[6][brfd];
- scaleopp1 = ff_vc1_b_field_mvpred_scales[1][brfd];
- scaleopp2 = ff_vc1_b_field_mvpred_scales[2][brfd];
-
- if (FFABS(n) > 63)
- scaledvalue = n;
- else {
- if (FFABS(n) < scalezone1_y)
- scaledvalue = (n * scaleopp1) >> 8;
- else {
- if (n < 0)
- scaledvalue = ((n * scaleopp2) >> 8) - zone1offset_y;
- else
- scaledvalue = ((n * scaleopp2) >> 8) + zone1offset_y;
- }
- }
- if (v->cur_field_type && !v->ref_field_type[dir]) {
- return av_clip(scaledvalue, -v->range_y / 2 + 1, v->range_y / 2);
+ const uint16_t *scales_tab = v->scalectx.field_mv_scales_tab[dir];
+ int scaleupopp = (int)scales_tab[7];
+ int hpel = !v->s.quarter_sample;
+ int px = (int)mv[0] >> hpel;
+ int py = (int)mv[1] >> hpel;
+
+ if (opp != scaleupopp) {
+ int scale = (int)scales_tab[0];
+ px = (px * scale) >> 8;
+ py = (py * scale) >> 8;
} else {
- return av_clip(scaledvalue, -v->range_y / 2, v->range_y / 2 - 1);
- }
-}
-
-static av_always_inline int scaleforsame(VC1Context *v, int i, int n /* MV */,
- int dim, int dir)
-{
- int brfd, scalesame;
- int hpel = 1 - v->s.quarter_sample;
-
- n >>= hpel;
- if (v->s.pict_type != AV_PICTURE_TYPE_B || v->second_field || !dir) {
- if (dim)
- n = scaleforsame_y(v, i, n, dir) << hpel;
- else
- n = scaleforsame_x(v, n, dir) << hpel;
- return n;
- }
- brfd = FFMIN(v->brfd, 3);
- scalesame = ff_vc1_b_field_mvpred_scales[0][brfd];
-
- n = (n * scalesame >> 8) << hpel;
- return n;
-}
-
-static av_always_inline int scaleforopp(VC1Context *v, int n /* MV */,
- int dim, int dir)
-{
- int refdist, scaleopp;
- int hpel = 1 - v->s.quarter_sample;
-
- n >>= hpel;
- if (v->s.pict_type == AV_PICTURE_TYPE_B && !v->second_field && dir == 1) {
- if (dim)
- n = scaleforopp_y(v, n, dir) << hpel;
- else
- n = scaleforopp_x(v, n) << hpel;
- return n;
- }
- if (v->s.pict_type != AV_PICTURE_TYPE_B)
- refdist = FFMIN(v->refdist, 3);
- else
- refdist = dir ? v->brfd : v->frfd;
- scaleopp = ff_vc1_field_mvpred_scales[dir ^ v->second_field][0][refdist];
-
- n = (n * scaleopp >> 8) << hpel;
- return n;
+ int range_x = v->range_x;
+ int range_y = v->range_y;
+ int scale1 = (int)scales_tab[1];
+ int scale2 = (int)scales_tab[2];
+ int scalezone1_x = (int)scales_tab[3];
+ int scalezone1_y = (int)scales_tab[4];
+ int zone1offset_x = (int)scales_tab[5];
+ int zone1offset_y = (int)scales_tab[6];
+
+ if (FFABS(px) <= 255) {
+ if (FFABS(px) < scalezone1_x)
+ px = (px * scale1) >> 8;
+ else if (px < 0)
+ px = ((px * scale2) >> 8) - zone1offset_x;
+ else
+ px = ((px * scale2) >> 8) + zone1offset_x;
+ }
+
+ px = av_clip(px, -range_x, range_x - 1);
+
+ if (FFABS(py) <= 63) {
+ if (FFABS(py) < scalezone1_y)
+ py = (py * scale1) >> 8;
+ else if (py < 0)
+ py = ((py * scale2) >> 8) - zone1offset_y;
+ else
+ py = ((py * scale2) >> 8) + zone1offset_y;
+ }
+
+ if (opp && v->cur_field_type)
+ py--;
+ py = av_clip(py, -range_y, range_y - 1);
+ if (opp && v->cur_field_type)
+ py++;
+ }
+
+ mv[0] = (int16_t)(px << hpel);
+ mv[1] = (int16_t)(py << hpel);
}
/** Predict and set motion vector
@@ -1464,33 +1344,21 @@ static inline void vc1_pred_mv(VC1Context *v, int n,
int dmv_x, int dmv_y,
} else
opposit = 0;
if (opposit) {
- if (a_valid && !a_f) {
- field_predA[0] = scaleforopp(v, field_predA[0], 0, dir);
- field_predA[1] = scaleforopp(v, field_predA[1], 1, dir);
- }
- if (b_valid && !b_f) {
- field_predB[0] = scaleforopp(v, field_predB[0], 0, dir);
- field_predB[1] = scaleforopp(v, field_predB[1], 1, dir);
- }
- if (c_valid && !c_f) {
- field_predC[0] = scaleforopp(v, field_predC[0], 0, dir);
- field_predC[1] = scaleforopp(v, field_predC[1], 1, dir);
- }
+ if (a_valid && !a_f)
+ scale_field_mv(v, field_predA, 1, dir);
+ if (b_valid && !b_f)
+ scale_field_mv(v, field_predB, 1, dir);
+ if (c_valid && !c_f)
+ scale_field_mv(v, field_predC, 1, dir);
v->mv_f[dir][xy + v->blocks_off] = 1;
v->ref_field_type[dir] = !v->cur_field_type;
} else {
- if (a_valid && a_f) {
- field_predA[0] = scaleforsame(v, n, field_predA[0], 0, dir);
- field_predA[1] = scaleforsame(v, n, field_predA[1], 1, dir);
- }
- if (b_valid && b_f) {
- field_predB[0] = scaleforsame(v, n, field_predB[0], 0, dir);
- field_predB[1] = scaleforsame(v, n, field_predB[1], 1, dir);
- }
- if (c_valid && c_f) {
- field_predC[0] = scaleforsame(v, n, field_predC[0], 0, dir);
- field_predC[1] = scaleforsame(v, n, field_predC[1], 1, dir);
- }
+ if (a_valid && a_f)
+ scale_field_mv(v, field_predA, 0, dir);
+ if (b_valid && b_f)
+ scale_field_mv(v, field_predB, 0, dir);
+ if (c_valid && c_f)
+ scale_field_mv(v, field_predC, 0, dir);
v->mv_f[dir][xy + v->blocks_off] = 0;
v->ref_field_type[dir] = v->cur_field_type;
}
--
1.7.4
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel