[FFmpeg-devel] [GSoC] Motion Interpolation

Michael Niedermayer michael at niedermayer.cc
Thu Aug 25 17:33:00 EEST 2016


On Tue, Aug 23, 2016 at 01:17:47PM +0000, Davinder Singh wrote:
> On Tue, Aug 23, 2016 at 5:38 AM Andy Furniss <adf.lists at gmail.com> wrote:
> 
> > [...]
> >
> > Nice I can see the edges are better than the last version.
> >
> > The doc/filters.texi hunk doesn't apply to git master.
> >
> > I was going to post some comparisons with mcfps tonight, but I'll need
> > to redo them to see what's changed.
> 
> 
> fixed docs conflict.
> 
> thanks for testing!

[...]
> +uint64_t ff_me_search_tss(AVMotionEstContext *me_ctx, int x_mb, int y_mb, int *mv)
> +{
> +    int x, y;
> +    int x_min = FFMAX(me_ctx->x_min, x_mb - me_ctx->search_param);
> +    int y_min = FFMAX(me_ctx->y_min, y_mb - me_ctx->search_param);
> +    int x_max = FFMIN(x_mb + me_ctx->search_param, me_ctx->x_max);
> +    int y_max = FFMIN(y_mb + me_ctx->search_param, me_ctx->y_max);
> +    uint64_t cost, cost_min;
> +    int step = ROUNDED_DIV(me_ctx->search_param, 2);
> +    int i;
> +

> +    int square[8][2] = {{0,-1}, {0,1}, {-1,0}, {1,0}, {-1,-1}, {-1,1}, {1,-1}, {1,1}};

const

> +
> +    mv[0] = x_mb;
> +    mv[1] = y_mb;
> +
> +    if (!(cost_min = me_ctx->get_cost(me_ctx, x_mb, y_mb, x_mb, y_mb)))
> +        return cost_min;
> +
> +    do {
> +        x = mv[0];
> +        y = mv[1];
> +
> +        for (i = 0; i < 8; i++)
> +            COST_P_MV(x + square[i][0] * step, y + square[i][1] * step);
> +

> +        step = step / 2;

 >>1 might be faster


> +
> +    } while (step > 0);
> +
> +    return cost_min;
> +}
> +
> +uint64_t ff_me_search_tdls(AVMotionEstContext *me_ctx, int x_mb, int y_mb, int *mv)
> +{
> +    int x, y;
> +    int x_min = FFMAX(me_ctx->x_min, x_mb - me_ctx->search_param);
> +    int y_min = FFMAX(me_ctx->y_min, y_mb - me_ctx->search_param);
> +    int x_max = FFMIN(x_mb + me_ctx->search_param, me_ctx->x_max);
> +    int y_max = FFMIN(y_mb + me_ctx->search_param, me_ctx->y_max);
> +    uint64_t cost, cost_min;
> +    int step = ROUNDED_DIV(me_ctx->search_param, 2);
> +    int i;
> +

> +    int dia2[4][2] = {{-1, 0}, { 0,-1},
> +                      { 1, 0}, { 0, 1}};

const


> +
> +    mv[0] = x_mb;
> +    mv[1] = y_mb;
> +
> +    if (!(cost_min = me_ctx->get_cost(me_ctx, x_mb, y_mb, x_mb, y_mb)))
> +        return cost_min;
> +
> +    do {
> +        x = mv[0];
> +        y = mv[1];
> +
> +        for (i = 0; i < 4; i++)
> +            COST_P_MV(x + dia2[i][0] * step, y + dia2[i][1] * step);
> +
> +        if (x == mv[0] && y == mv[1])
> +            step = step / 2;
> +
> +    } while (step > 0);
> +
> +    return cost_min;
> +}
> +
> +uint64_t ff_me_search_ntss(AVMotionEstContext *me_ctx, int x_mb, int y_mb, int *mv)
> +{
> +    int x, y;
> +    int x_min = FFMAX(me_ctx->x_min, x_mb - me_ctx->search_param);
> +    int y_min = FFMAX(me_ctx->y_min, y_mb - me_ctx->search_param);
> +    int x_max = FFMIN(x_mb + me_ctx->search_param, me_ctx->x_max);
> +    int y_max = FFMIN(y_mb + me_ctx->search_param, me_ctx->y_max);
> +    uint64_t cost, cost_min;
> +    int step = ROUNDED_DIV(me_ctx->search_param, 2);
> +    int first_step = 1;
> +    int i;
> +

> +    int square[8][2] = {{0,-1}, {0,1}, {-1,0}, {1,0}, {-1,-1}, {-1,1}, {1,-1}, {1,1}};

const

[...]
> +uint64_t ff_me_search_ds(AVMotionEstContext *me_ctx, int x_mb, int y_mb, int *mv)
> +{
> +    int x, y;
> +    int x_min = FFMAX(me_ctx->x_min, x_mb - me_ctx->search_param);
> +    int y_min = FFMAX(me_ctx->y_min, y_mb - me_ctx->search_param);
> +    int x_max = FFMIN(x_mb + me_ctx->search_param, me_ctx->x_max);
> +    int y_max = FFMIN(y_mb + me_ctx->search_param, me_ctx->y_max);
> +    uint64_t cost, cost_min;
> +    int i;
> +    int dir_x, dir_y;
> +
> +    int dia[8][2] = {{-2, 0}, {-1,-1}, { 0,-2}, { 1,-1},
> +                     { 2, 0}, { 1, 1}, { 0, 2}, {-1, 1}};
> +    int dia2[4][2] = {{-1, 0}, { 0,-1},
> +                      { 1, 0}, { 0, 1}};
> +
> +    if (!(cost_min = me_ctx->get_cost(me_ctx, x_mb, y_mb, x_mb, y_mb)))
> +        return cost_min;
> +
> +    x = x_mb; y = y_mb;
> +    dir_x = dir_y = 0;
> +
> +    do {
> +        x = mv[0];
> +        y = mv[1];
> +
> +    #if 1
> +        for (i = 0; i < 8; i++)
> +            COST_P_MV(x + dia[i][0], y + dia[i][1]);
> +    #else
> +        /* this version skips previously examined 3 or 5 locations based on prev origin */
> +        if (dir_x <= 0)
> +            COST_P_MV(x - 2, y);
> +        if (dir_x <= 0 && dir_y <= 0)
> +            COST_P_MV(x - 1, y - 1);
> +        if (dir_y <= 0)
> +            COST_P_MV(x, y - 2);
> +        if (dir_x >= 0 && dir_y <= 0)
> +            COST_P_MV(x + 1, y - 1);
> +        if (dir_x >= 0)
> +            COST_P_MV(x + 2, y);
> +        if (dir_x >= 0 && dir_y >= 0)
> +            COST_P_MV(x + 1, y + 1);
> +        if (dir_y >= 0)
> +            COST_P_MV(x, y + 2);
> +        if (dir_x <= 0 && dir_y >= 0)
> +            COST_P_MV(x - 1, y + 1);
> +
> +        dir_x = mv[0] - x;
> +        dir_y = mv[1] - y;
> +    #endif
> +
> +    } while (x != mv[0] || y != mv[1]);
> +
> +    for (i = 0; i < 4; i++)
> +        COST_P_MV(x + dia2[i][0], y + dia2[i][1]);
> +
> +    return cost_min;
> +}
> +
> +uint64_t ff_me_search_hexbs(AVMotionEstContext *me_ctx, int x_mb, int y_mb, int *mv)
> +{
> +    int x, y;
> +    int x_min = FFMAX(me_ctx->x_min, x_mb - me_ctx->search_param);
> +    int y_min = FFMAX(me_ctx->y_min, y_mb - me_ctx->search_param);
> +    int x_max = FFMIN(x_mb + me_ctx->search_param, me_ctx->x_max);
> +    int y_max = FFMIN(y_mb + me_ctx->search_param, me_ctx->y_max);
> +    uint64_t cost, cost_min;
> +    int i;
> +
> +    int hex2[6][2] = {{-2, 0}, {-1,-2}, {-1, 2},
> +                      { 1,-2}, { 1, 2}, { 2, 0}};
> +
> +    int dia2[4][2] = {{-1, 0}, { 0,-1},
> +                      { 1, 0}, { 0, 1}};
> +
> +    if (!(cost_min = me_ctx->get_cost(me_ctx, x_mb, y_mb, x_mb, y_mb)))
> +        return cost_min;
> +
> +    do {
> +        x = mv[0];
> +        y = mv[1];
> +
> +        for (i = 0; i < 6; i++)
> +            COST_P_MV(x + hex2[i][0], y + hex2[i][1]);
> +
> +    } while (x != mv[0] || y != mv[1]);
> +
> +    for (i = 0; i < 4; i++)
> +        COST_P_MV(x + dia2[i][0], y + dia2[i][1]);
> +
> +    return cost_min;
> +}

why do these not try predictors like epzs / umh ?
i guess some paper doesnt say exlpicitly it should be done
but really it should be done for all predictive zonal searches IMO


[...]
> +#define OFFSET(x) offsetof(MEContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
> +#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, FLAGS, unit }
> +
> +static const AVOption mestimate_options[] = {

> +    { "method", "motion estimation method", OFFSET(method), AV_OPT_TYPE_INT, {.i64 = AV_ME_METHOD_ESA}, AV_ME_METHOD_ESA, AV_ME_METHOD_UMH, FLAGS, "method" },
> +        CONST("esa",   "exhaustive search",                  AV_ME_METHOD_ESA,      "method"),
> +        CONST("tss",   "three step search",                  AV_ME_METHOD_TSS,      "method"),
> +        CONST("tdls",  "two dimensional logarithmic search", AV_ME_METHOD_TDLS,     "method"),
> +        CONST("ntss",  "new three step search",              AV_ME_METHOD_NTSS,     "method"),
> +        CONST("fss",   "four step search",                   AV_ME_METHOD_FSS,      "method"),
> +        CONST("ds",    "diamond search",                     AV_ME_METHOD_DS,       "method"),
> +        CONST("hexbs", "hexagon-based search",               AV_ME_METHOD_HEXBS,    "method"),
> +        CONST("epzs",  "enhanced predictive zonal search",   AV_ME_METHOD_EPZS,     "method"),
> +        CONST("umh",   "uneven multi-hexagon search",        AV_ME_METHOD_UMH,      "method"),

AVOption is not compatible with general enums, as C does not gurantee
them to be stored in an int, it just happens to work on most platforms


[...]
> +static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
> +{
> +    AVFilterContext *ctx = inlink->dst;
> +    MEContext *s = ctx->priv;
> +    AVMotionEstContext *me_ctx = &s->me_ctx;
> +    AVFrameSideData *sd;
> +    AVFrame *out;
> +    int mb_x, mb_y, dir;
> +    int32_t mv_count = 0;
> +    int ret;
> +
> +    if (frame->pts == AV_NOPTS_VALUE) {
> +        ret = ff_filter_frame(ctx->outputs[0], frame);
> +        return ret;
> +    }
> +
> +    av_frame_free(&s->prev);
> +    s->prev = s->cur;
> +    s->cur  = s->next;
> +    s->next = frame;
> +
> +    s->mv_table[2] = memcpy(s->mv_table[2], s->mv_table[1], sizeof(*s->mv_table[1]) * s->b_count);
> +    s->mv_table[1] = memcpy(s->mv_table[1], s->mv_table[0], sizeof(*s->mv_table[0]) * s->b_count);
> +
> +    if (!s->cur) {
> +        s->cur = av_frame_clone(frame);
> +        if (!s->cur)
> +            return AVERROR(ENOMEM);
> +    }
> +
> +    if (!s->prev)
> +        return 0;
> +

> +    out = av_frame_clone(s->cur);
> +    if (!out)
> +        return AVERROR(ENOMEM);
> +
> +    sd = av_frame_new_side_data(out, AV_FRAME_DATA_MOTION_VECTORS, 2 * s->b_count * sizeof(AVMotionVector));

> +    if (!sd)
> +        return AVERROR(ENOMEM);

leaks "out"


[...]
> +static uint64_t get_sbad(AVMotionEstContext *me_ctx, int x, int y, int x_mv, int y_mv)
> +{
> +    uint8_t *data_cur = me_ctx->data_cur;
> +    uint8_t *data_next = me_ctx->data_ref;
> +    int linesize = me_ctx->linesize;
> +    int mv_x1 = x_mv - x;
> +    int mv_y1 = y_mv - y;
> +    int mv_x, mv_y, i, j;
> +    uint64_t sbad = 0;
> +
> +    x = av_clip(x, me_ctx->x_min, me_ctx->x_max);
> +    y = av_clip(y, me_ctx->y_min, me_ctx->y_max);
> +    mv_x = av_clip(x_mv - x, -FFMIN(x - me_ctx->x_min, me_ctx->x_max - x), FFMIN(x - me_ctx->x_min, me_ctx->x_max - x));
> +    mv_y = av_clip(y_mv - y, -FFMIN(y - me_ctx->y_min, me_ctx->y_max - y), FFMIN(y - me_ctx->y_min, me_ctx->y_max - y));
> +
> +    data_cur += (y + mv_y) * linesize;
> +    data_next += (y - mv_y) * linesize;
> +
> +    for (j = 0; j < me_ctx->mb_size; j++)
> +        for (i = 0; i < me_ctx->mb_size; i++)
> +            sbad += FFABS(data_cur[x + mv_x + i + j * linesize] - data_next[x - mv_x + i + j * linesize]);
> +

> +    return sbad + (FFABS(mv_x1 - me_ctx->pred_x) + FFABS(mv_y1 - me_ctx->pred_y)) * COST_PRED_SCALE;

with this style of smoothness cost you likely want to make an exception
for the 0,0 vector (giving it the same "penalty" as the median or even
very slightly less)
This would normally be implemented by not adding the penalty on
the 0,0 perdictor check but as its implemented in the compare function
itself it would need a check
i think it would slighty improve quality. Of course if it does not then
ignore this suggestion

also i will apply this patchset once the issues raised here are fixed
if noone objects, its much easier and more efficient to work in main
git than on top of a growing patch

Thanks

[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Republics decline into democracies and democracies degenerate into
despotisms. -- Aristotle
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160825/9ab60352/attachment.sig>


More information about the ffmpeg-devel mailing list