[FFmpeg-devel] [PATCH] Port MPlayer 2xSaI filter to libavfilter

Nielkie nielkie
Fri Nov 26 12:07:01 CET 2010


On Fri, Nov 26, 2010 at 8:16 PM, Stefano Sabatini <
stefano.sabatini-lala at poste.it> wrote:

> On date Friday 2010-11-26 18:45:38 +1000, Nielkie encoded:
> > On Fri, Nov 26, 2010 at 6:21 AM, Reimar D?ffinger
> > diff --git a/Changelog b/Changelog
> > index dc949cd..e6ed1dd 100644
> > --- a/Changelog
> > +++ b/Changelog
> > @@ -59,6 +59,7 @@ version <next>:
> >  - overlay filter added
> >  - rename aspect filter to setdar, and pixelaspect to setsar
> >  - IEC 61937 demuxer
> > +- super2xsai filter added
> >
> >
> >  version 0.6:
> > diff --git a/configure b/configure
> > index 7dcb50f..38d870e 100755
> > --- a/configure
> > +++ b/configure
> > @@ -1407,6 +1407,7 @@ blackframe_filter_deps="gpl"
> >  cropdetect_filter_deps="gpl"
> >  frei0r_filter_deps="frei0r dlopen strtok_r"
> >  ocv_smooth_filter_deps="libopencv"
> > +super2xsai_filter_deps="gpl"
> >  yadif_filter_deps="gpl"
> >
> >  # libraries
> > diff --git a/doc/filters.texi b/doc/filters.texi
> > index 1cba2d6..750dc55 100644
> > --- a/doc/filters.texi
> > +++ b/doc/filters.texi
> > @@ -635,6 +635,15 @@ not specified it will use the default value of 16.
> >  Adding this in the beginning of filter chains should make filtering
> >  faster due to better use of the memory cache.
> >
> > + at section super2xsai
> > +
> > +Scale the input by 2x using the Super2xSaI pixel art scaling algorithm.
> > +Useful for enlarging pixel or line art without introducing blur.
> > +
> > + at example
> > +./ffmpeg -i in.avi -vf "super2xsai" out.avi
> > + at end example
>
> No need for this example.
>
> > +
> >  @section transpose
> >
> >  Transpose rows with columns in the input video and optionally flip it.
> > diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> > index 210510f..cbcf3b4 100644
> > --- a/libavfilter/Makefile
> > +++ b/libavfilter/Makefile
> > @@ -39,6 +39,7 @@ OBJS-$(CONFIG_SETPTS_FILTER)                 +=
> vf_setpts.o
> >  OBJS-$(CONFIG_SETSAR_FILTER)                 += vf_aspect.o
> >  OBJS-$(CONFIG_SETTB_FILTER)                  += vf_settb.o
> >  OBJS-$(CONFIG_SLICIFY_FILTER)                += vf_slicify.o
> > +OBJS-$(CONFIG_SUPER2XSAI_FILTER)             += vf_super2xsai.o
> >  OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
> >  OBJS-$(CONFIG_UNSHARP_FILTER)                += vf_unsharp.o
> >  OBJS-$(CONFIG_VFLIP_FILTER)                  += vf_vflip.o
> > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> > index 9e3ba14..3f3c655 100644
> > --- a/libavfilter/allfilters.c
> > +++ b/libavfilter/allfilters.c
> > @@ -60,6 +60,7 @@ void avfilter_register_all(void)
> >      REGISTER_FILTER (SETSAR,      setsar,      vf);
> >      REGISTER_FILTER (SETTB,       settb,       vf);
> >      REGISTER_FILTER (SLICIFY,     slicify,     vf);
> > +    REGISTER_FILTER (SUPER2XSAI,  super2xsai,  vf);
> >      REGISTER_FILTER (TRANSPOSE,   transpose,   vf);
> >      REGISTER_FILTER (UNSHARP,     unsharp,     vf);
> >      REGISTER_FILTER (VFLIP,       vflip,       vf);
> > diff --git a/libavfilter/vf_super2xsai.c b/libavfilter/vf_super2xsai.c
> > new file mode 100644
> > index 0000000..1c73b26
> > --- /dev/null
> > +++ b/libavfilter/vf_super2xsai.c
> > @@ -0,0 +1,310 @@
> > +/*
> > + * Copyright (C) 2010 Niel van der Westhuizen
> > + * Copyright (C) 2002 A'rpi
> > + * Copyright (C) 1997-2001 ZSNES Team ( zsknight at zsnes.com / _
> demo_ at zsnes.com )
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * FFmpeg is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> along
> > + * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > +*/
> > +
> > +/**
> > + * @file
> > + * Super 2xSaI video filter
> > + * Ported from MPlayer libmpcodecs/vf_2xsai.c.
> > + */
> > +
> > +#include "libavutil/intreadwrite.h"
> > +#include "libavutil/colorspace.h"
> > +#include "libavutil/pixdesc.h"
> > +#include "libavcore/parseutils.h"
> > +#include "avfilter.h"
> > +
> > +typedef struct {
> > +    uint32_t colorMask;
> > +    uint32_t lowPixelMask;
> > +    uint32_t qcolorMask;
> > +    uint32_t qlowPixelMask;
> > +    int bytesPerPixel;
>
> > +} Super2xSaIContext;
> > +
> > +
> > +
>
> Nit+++: only one empty line.
>
> > +static uint32_t readPixel(int bytesPerPixel, uint8_t *src, int offset)
> > +{
> > +    switch(bytesPerPixel) {
> > +    case 4:
> > +        return AV_RN32A(src + 4*offset);
> > +    case 3:
> > +        return AV_RL24(src + 3*offset);
> > +    case 2:
> > +        return AV_RN16(src + 2*offset);
>
> Nit+: case N: return ... on the same line and vertical align will improve
> readability.
>
> > +    }
> > +    return 0;
> > +}
> > +
> > +
>
> Ditto
>
> > +#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D))
> > +
> > +#define INTERPOLATE(A, B) (((A & c->colorMask) >> 1) + ((B &
> c->colorMask) >> 1) + (A & B & c->lowPixelMask))
> > +
> > +/* Interpolate two rgb colors with weights 3 and 1 */
> > +#define INTERPOLATE_3_1(A, B) ((A & c->qcolorMask) >> 2)*3 + ((B &
> c->qcolorMask) >> 2) \
> > +                               + ((((A & c->qlowPixelMask)*3 + (B &
> c->qlowPixelMask)) >> 2) & c->qlowPixelMask)
> > +
> > +/* Reads from the current source color neighborhood. */
> > +#define GET_COLOR(mx, my) (readPixel(c->bytesPerPixel, src_line[my],
> FFMIN(x+mx, width-1)))
> > +
> > +static void Super2xSaI(Super2xSaIContext *c,
> > +                          uint8_t *src, uint32_t src_pitch,
> > +                          uint8_t *dst, uint32_t dst_pitch,
> > +                          uint32_t width, uint32_t height)
> > +{
> > +    unsigned int x = 0, y = 0;
> > +    uint32_t color[16];
> > +    uint8_t *src_line[4], *dst_line[2];
> > +
> > +    /* Point to the first 3 lines. */
> > +    src_line[0] = src;
> > +    src_line[1] = src;
> > +    src_line[2] = FFMIN(src + src_pitch,     src + (height-1) *
> src_pitch);
> > +    src_line[3] = FFMIN(src + src_pitch * 2, src + (height-1) *
> src_pitch);
> > +
> > +    for (y = 0; y < height; y++) {
> > +        dst_line[0] = dst + dst_pitch*2*y;
> > +        dst_line[1] = dst + dst_pitch*(2*y+1);
> > +
> > +        /* Initialise the color matrix for this row:
> > +            0  1  2  3
> > +            4  5* 6  7
> > +            8  9 10 11
> > +            12 13 14 15
> > +            (5 being the source pixel being generated)
> > +        */
> > +        x = 0;
> > +        color[0] =  GET_COLOR(0, 0); color[1] =  GET_COLOR(0, 0);
> color[2] =  GET_COLOR(1, 0); color[3] =  GET_COLOR(2, 0);
> > +        color[4] =  GET_COLOR(0, 1); color[5] =  GET_COLOR(0, 1);
> color[6] =  GET_COLOR(1, 1); color[7] =  GET_COLOR(2, 1);
> > +        color[8] =  GET_COLOR(0, 2); color[9] =  GET_COLOR(0, 2);
> color[10] = GET_COLOR(1, 2); color[11] = GET_COLOR(2, 2);
> > +        color[12] = GET_COLOR(0, 3); color[13] = GET_COLOR(0, 3);
> color[14] = GET_COLOR(1, 3); color[15] = GET_COLOR(2, 3);
> > +
> > +        for (x = 0; x < width; x++) {
> > +
> > +            /* Calculate the 4 colors for the current position using
> information from the color matrix */
> > +            uint32_t product1a, product1b, product2a, product2b;
> > +
> > +            if (color[9] == color[6] && color[5] != color[10]) {
> > +                product2b = color[9];
> > +                product1b = product2b;
> > +            } else if (color[5] == color[10] && color[9] != color[6]) {
> > +                product2b = color[5];
> > +                product1b = product2b;
> > +            } else if (color[5] == color[10] && color[9] == color[6]) {
> > +                int r = 0;
> > +
> > +                r += GET_RESULT(color[6], color[5], color[8],
> color[13]);
> > +                r += GET_RESULT(color[6], color[5], color[4], color[1]);
> > +                r += GET_RESULT(color[6], color[5], color[14],
> color[11]);
> > +                r += GET_RESULT(color[6], color[5], color[2], color[7]);
> > +
> > +                if (r > 0)
> > +                    product1b = color[6];
> > +                else if (r < 0)
> > +                    product1b = color[5];
> > +                else
> > +                    product1b = INTERPOLATE(color[5], color[6]);
> > +
> > +                product2b = product1b;
> > +
> > +            } else {
> > +                if (color[6] == color[10] && color[10] == color[13] &&
> > +                    color[9] != color[14] && color[10] != color[12])
> > +                    product2b = INTERPOLATE_3_1(color[10], color[9]);
> > +                else if (color[5] == color[9] && color[9] == color[14]
> &&
> > +                         color[13] != color[10] && color[9] !=
> color[15])
> > +                    product2b = INTERPOLATE_3_1(color[9], color[10]);
> > +                else
> > +                    product2b = INTERPOLATE(color[9], color[10]);
> > +
> > +                if (color[6] == color[10] && color[6] == color[1] &&
> > +                    color[5] != color[2] && color[6] != color[0])
> > +                    product1b = INTERPOLATE_3_1(color[6], color[5]);
> > +                else if (color[5] == color[9] && color[5] == color[2] &&
> > +                         color[1] != color[6] && color[5] != color[3])
> > +                    product1b = INTERPOLATE_3_1(color[5], color[6]);
> > +                else
> > +                    product1b = INTERPOLATE(color[5], color[6]);
> > +            }
> > +
> > +            if (color[5] == color[10] && color[9] != color[6] &&
> > +                color[4] == color[5] && color[5] != color[14])
> > +                product2a = INTERPOLATE(color[9], color[5]);
> > +            else if (color[5] == color[8] && color[6] == color[5] &&
> > +                     color[4] != color[9] && color[5] != color[12])
> > +                product2a = INTERPOLATE(color[9], color[5]);
> > +            else
> > +                product2a = color[9];
> > +
> > +            if (color[9] == color[6] && color[5] != color[10] &&
> > +                color[8] == color[9] && color[9] != color[2])
> > +                product1a = INTERPOLATE(color[9], color[5]);
> > +            else if (color[4] == color[9] && color[10] == color[9] &&
> > +                     color[8] != color[5] && color[9] != color[0])
> > +                product1a = INTERPOLATE(color[9], color[5]);
> > +            else
> > +                product1a = color[5];
> > +
> > +            /* Set the calculated pixels */
> > +            if (c->bytesPerPixel == 4) {
> > +                AV_WN32A(dst_line[0] + x * 8,     product1a);
> > +                AV_WN32A(dst_line[0] + x * 8 + 4, product1b);
> > +                AV_WN32A(dst_line[1] + x * 8,     product2a);
> > +                AV_WN32A(dst_line[1] + x * 8 + 4, product2b);
> > +            } else if (c->bytesPerPixel == 3) {
> > +                AV_WL24(dst_line[0] + x * 6,     product1a);
> > +                AV_WL24(dst_line[0] + x * 6 + 3, product1b);
> > +                AV_WL24(dst_line[1] + x * 6,     product2a);
> > +                AV_WL24(dst_line[1] + x * 6 + 3, product2b);
> > +            } else if (c->bytesPerPixel == 2) {
> > +                AV_WN32A(dst_line[0] + x * 4, product1a | (product1b <<
> 16));
> > +                AV_WN32A(dst_line[1] + x * 4, product2a | (product2b <<
> 16));
> > +            }
> > +
> > +            /* Move color matrix forward */
> > +            color[0] = color[1]; color[4] = color[5]; color[8] =
> color[9];   color[12] = color[13];
> > +            color[1] = color[2]; color[5] = color[6]; color[9] =
> color[10];  color[13] = color[14];
> > +            color[2] = color[3]; color[6] = color[7]; color[10] =
> color[11]; color[14] = color[15];
> > +            if (x < width - 3) {
> > +                color[3] =  GET_COLOR(3, 0);
> > +                color[7] =  GET_COLOR(3, 1);
> > +                color[11] = GET_COLOR(3, 2);
> > +                color[15] = GET_COLOR(3, 3);
> > +            }
> > +        }
> > +
> > +        /* We're done with one line, so we shift the source lines up */
> > +        src_line[0] = src_line[1];
> > +        src_line[1] = src_line[2];
> > +        src_line[2] = src_line[3];
> > +
> > +        /* Read next line */
> > +        src_line[3] = src_line[2];
> > +        if (y < height - 3)
> > +            src_line[3] += src_pitch;
> > +
> > +    } // y loop
> > +
>
> > +}
> > +
> > +
>
> Ditto
>
> > +static int query_formats(AVFilterContext *ctx)
> > +{
> > +    static const enum PixelFormat pix_fmts[] = {
> > +        PIX_FMT_RGBA, PIX_FMT_BGRA, PIX_FMT_ARGB, PIX_FMT_ABGR,
> > +        PIX_FMT_RGB24, PIX_FMT_BGR24,
> > +        PIX_FMT_RGB565, PIX_FMT_BGR565, PIX_FMT_RGB555, PIX_FMT_BGR555,
> > +        PIX_FMT_NONE
> > +    };
> > +
> > +    avfilter_set_common_formats(ctx,
> avfilter_make_format_list(pix_fmts));
> > +    return 0;
> > +}
> > +
> > +static int config_input(AVFilterLink *inlink)
> > +{
> > +    Super2xSaIContext *sai = inlink->dst->priv;
> > +
> > +    sai->colorMask =     0xFEFEFEFE;
> > +    sai->lowPixelMask =  0x01010101;
> > +    sai->qcolorMask =    0xFCFCFCFC;
> > +    sai->qlowPixelMask = 0x03030303;
> > +
> > +    sai->bytesPerPixel = 4;
> > +
> > +    switch(inlink->format) {
> > +    case PIX_FMT_RGB24:
> > +    case PIX_FMT_BGR24:
> > +        sai->bytesPerPixel = 3;
> > +        break;
> > +    case PIX_FMT_RGB565:
> > +    case PIX_FMT_BGR565:
> > +        sai->colorMask =     0xF7DEF7DE;
> > +        sai->lowPixelMask =  0x08210821;
> > +        sai->qcolorMask =    0xE79CE79C;
> > +        sai->qlowPixelMask = 0x18631863;
> > +        sai->bytesPerPixel = 2;
> > +        break;
> > +    case PIX_FMT_BGR555:
> > +    case PIX_FMT_RGB555:
> > +        sai->colorMask =     0x7BDE7BDE;
> > +        sai->lowPixelMask =  0x04210421;
> > +        sai->qcolorMask =    0x739C739C;
> > +        sai->qlowPixelMask = 0x0C630C63;
> > +        sai->bytesPerPixel = 2;
> > +        break;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int config_output(AVFilterLink *outlink)
> > +{
> > +    AVFilterLink *inlink = outlink->src->inputs[0];
> > +
> > +    outlink->w = inlink->w*2;
> > +    outlink->h = inlink->h*2;
> > +
> > +    return 0;
> > +}
> > +
> > +static void null_draw_slice(AVFilterLink *inlink, int y, int h, int
> slice_dir) { }
> > +
> > +static void end_frame(AVFilterLink *inlink)
> > +{
> > +    Super2xSaIContext *sai = inlink->dst->priv;
> > +    AVFilterLink *outlink = inlink->dst->outputs[0];
> > +    AVFilterBufferRef  *inpicref =  inlink->cur_buf;
> > +    AVFilterBufferRef *outpicref = outlink->out_buf;
> > +
> > +    Super2xSaI(sai, inpicref->data[0], inpicref->linesize[0],
> > +               outpicref->data[0], outpicref->linesize[0],
> > +               inlink->w, inlink->h);
> > +
> > +    avfilter_unref_buffer(inpicref);
> > +    avfilter_draw_slice(outlink, 0, outlink->h, 1);
> > +    avfilter_end_frame(outlink);
> > +    avfilter_unref_buffer(outpicref);
>
> > +}
> > +
> > +
>
> Ditto
>
> > +AVFilter avfilter_vf_super2xsai =
> > +{
>
> Nit+++: "{" on the same line
>
> > +    .name      = "super2xsai",
>
> > +    .description = NULL_IF_CONFIG_SMALL("Pixel art 2x scaler."),
>
> "Scale the input by 2x using the Super2xSaI pixel art algorithm."
>
> Description is a sentence rather than a long name.
>
> [...]
>
> Thanks for the patch.
> --
> FFmpeg = Faithless and Fanciful Mortal Pitiful Exuberant God
>
>
Thanks, fixed.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: super2xsai.diff
Type: application/octet-stream
Size: 14507 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20101126/495f28ca/attachment.obj>



More information about the ffmpeg-devel mailing list