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

Reply via email to