On Sat, Aug 18, 2012 at 10:57:12PM +0600, Mashiat Sarker Shakkhar wrote:
> 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.
Too bad, one should have an idea what he's doing.
> ---
> 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;
lolwut? Read an escape value and ignore it immediately?
> + 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 }
> + }
> };
looks like transposing tables
> 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;
> }
> --
in general - please redo till you understand what you're doing besides pasting
reference decoder pieces
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel