[FFmpeg-devel] [PATCH] avfilter: add hqx filter (hq2x, hq3x, hq4x)

Stefano Sabatini stefasab at gmail.com
Sat Jun 21 17:48:53 CEST 2014


On date Tuesday 2014-06-17 22:05:28 +0200, Clément Bœsch encoded:
> Partially fixes Ticket #3404 (xbr filter remaining)
> ---
> We can probably make more meaningful versions of hq[234]x_interp* but I believe
> that's already a huge improvement over the original code.
> 
> [~/src/hqx/hqx-read-only/src]☭ wc -l src/*.[ch]
>    141 src/common.h
>   2809 src/hq2x.c
>   3787 src/hq3x.c
>   5241 src/hq4x.c
>    138 src/hqx.c
>     55 src/hqx.h
>     38 src/init.c
>  12209 total
> 
> [~/src/ffmpeg]☭ wc -l libavfilter/vf_hqx.c
> 557 libavfilter/vf_hqx.c
> 
> Note1: the filter is bitexact for the reference implementation, except for
> filter/pixelart1.png where the reference code hits this bug:
> https://code.google.com/p/hqx/issues/detail?id=8
> ---
>  Changelog                   |   1 +
>  MAINTAINERS                 |   1 +
>  doc/filters.texi            |  14 ++
>  libavfilter/Makefile        |   1 +
>  libavfilter/allfilters.c    |   1 +
>  libavfilter/version.h       |   2 +-
>  libavfilter/vf_hqx.c        | 557 ++++++++++++++++++++++++++++++++++++++++++++
>  tests/fate/filter-video.mak |   7 +
>  tests/ref/fate/filter-hq2x  |   3 +
>  tests/ref/fate/filter-hq3x  |   3 +
>  tests/ref/fate/filter-hq4x  |   3 +
>  11 files changed, 592 insertions(+), 1 deletion(-)
>  create mode 100644 libavfilter/vf_hqx.c
>  create mode 100644 tests/ref/fate/filter-hq2x
>  create mode 100644 tests/ref/fate/filter-hq3x
>  create mode 100644 tests/ref/fate/filter-hq4x
> 
> diff --git a/Changelog b/Changelog
> index fa443dc..0346877 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -29,6 +29,7 @@ version <next>:
>  - showcqt multimedia filter
>  - zoompan filter
>  - signalstats filter
> +- hqx filter (hq2x, hq3x, hq4x)
>  
>  
>  version 2.2:
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a61f1e5..ea474df 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -350,6 +350,7 @@ Filters:
>    vf_drawbox.c/drawgrid                 Andrey Utkin
>    vf_extractplanes.c                    Paul B Mahol
>    vf_histogram.c                        Paul B Mahol
> +  vf_hqx.c                              Clément Bœsch
>    vf_il.c                               Paul B Mahol
>    vf_mergeplanes.c                      Paul B Mahol
>    vf_psnr.c                             Paul B Mahol
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 63bd22e..c3a0d2c 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -5203,6 +5203,20 @@ A floating point number which specifies chroma temporal strength. It defaults to
>  @var{luma_tmp}*@var{chroma_spatial}/@var{luma_spatial}.
>  @end table
>  
> + at section hqx
> +

> +High-quality magnification filter designed for pixel art, originally created by
> +Maxim Stepin.

Apply high-quality magnification ... This filter was originally
created by ...

> +
> +It accepts the following option:
> +
> + at table @option
> + at item n
> +Set the scaling dimension: @code{2} for @code{hq2x}, @code{3} for
> + at code{hq3x} and @code{4} for @code{hq4x}.
> +Default is @code{3}.
> + at end table
> +
>  @section hue
>  
>  Modify the hue and/or the saturation of the input.
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 5b9fabf..08817ee 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -130,6 +130,7 @@ OBJS-$(CONFIG_HFLIP_FILTER)                  += vf_hflip.o
>  OBJS-$(CONFIG_HISTEQ_FILTER)                 += vf_histeq.o
>  OBJS-$(CONFIG_HISTOGRAM_FILTER)              += vf_histogram.o
>  OBJS-$(CONFIG_HQDN3D_FILTER)                 += vf_hqdn3d.o
> +OBJS-$(CONFIG_HQX_FILTER)                    += vf_hqx.o
>  OBJS-$(CONFIG_HUE_FILTER)                    += vf_hue.o
>  OBJS-$(CONFIG_IDET_FILTER)                   += vf_idet.o
>  OBJS-$(CONFIG_IL_FILTER)                     += vf_il.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index 1e86967..e4ac983 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -148,6 +148,7 @@ void avfilter_register_all(void)
>      REGISTER_FILTER(HISTEQ,         histeq,         vf);
>      REGISTER_FILTER(HISTOGRAM,      histogram,      vf);
>      REGISTER_FILTER(HQDN3D,         hqdn3d,         vf);
> +    REGISTER_FILTER(HQX,            hqx,            vf);
>      REGISTER_FILTER(HUE,            hue,            vf);
>      REGISTER_FILTER(IDET,           idet,           vf);
>      REGISTER_FILTER(IL,             il,             vf);
> diff --git a/libavfilter/version.h b/libavfilter/version.h
> index a518e8f..f125032 100644
> --- a/libavfilter/version.h
> +++ b/libavfilter/version.h
> @@ -30,7 +30,7 @@
>  #include "libavutil/version.h"
>  
>  #define LIBAVFILTER_VERSION_MAJOR   4
> -#define LIBAVFILTER_VERSION_MINOR   8
> +#define LIBAVFILTER_VERSION_MINOR   9
>  #define LIBAVFILTER_VERSION_MICRO 100
>  
>  #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
> diff --git a/libavfilter/vf_hqx.c b/libavfilter/vf_hqx.c
> new file mode 100644
> index 0000000..2b608b3
> --- /dev/null
> +++ b/libavfilter/vf_hqx.c
> @@ -0,0 +1,557 @@
> +/*
> + * Copyright (c) 2014 Clément Bœsch
> + *

In case you adopted the design/implementation of existing code you
should probably add the original authors here, or refer the reference.

> + * This file is part of FFmpeg.
> + *
> + * Permission to use, copy, modify, and/or distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +/**
> + * hqx magnification filters
> + *
> + * @see http://en.wikipedia.org/wiki/Hqx
> + * @see http://web.archive.org/web/20131114143602/http://www.hiend3d.com/hq3x.html
> + */
> +
> +#include "libavutil/opt.h"
> +#include "libavutil/avassert.h"
> +#include "libavutil/pixdesc.h"
> +#include "internal.h"
> +
> +typedef int (*hqxfunc_t)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
> +
> +typedef struct {
> +    const AVClass *class;
> +    int n;
> +    hqxfunc_t func;
> +    uint32_t rgbtoyuv[1<<24];
> +} HQXContext;
> +
> +typedef struct ThreadData {
> +    AVFrame *in, *out;
> +    const uint32_t *rgbtoyuv;
> +} ThreadData;
> +
> +#define OFFSET(x) offsetof(HQXContext, x)
> +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
> +static const AVOption hqx_options[] = {
> +    { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 4, .flags = FLAGS },
> +    { NULL }
> +};
> +
> +AVFILTER_DEFINE_CLASS(hqx);
> +
> +static av_always_inline uint32_t rgb2yuv(const uint32_t *r2y, uint32_t c)
> +{
> +    return r2y[c & 0xffffff];
> +}
> +
> +static av_always_inline int yuv_diff(uint32_t yuv1, uint32_t yuv2)
> +{
> +#define YMASK 0xff0000
> +#define UMASK 0x00ff00
> +#define VMASK 0x0000ff
> +    return abs((yuv1 & YMASK) - (yuv2 & YMASK)) > (48 << 16) ||
> +           abs((yuv1 & UMASK) - (yuv2 & UMASK)) > ( 7 <<  8) ||
> +           abs((yuv1 & VMASK) - (yuv2 & VMASK)) > ( 6 <<  0);
> +}
> +
> +/* (c1*w1 + c2*w2) >> s */
> +static av_always_inline uint32_t interp_2px(uint32_t c1, int w1, uint32_t c2, int w2, int s)
> +{
> +    return (((((c1 & 0xff00ff00) >> 8) * w1 + ((c2 & 0xff00ff00) >> 8) * w2) << (8 - s)) & 0xff00ff00) |
> +           (((((c1 & 0x00ff00ff)     ) * w1 + ((c2 & 0x00ff00ff)     ) * w2) >>      s ) & 0x00ff00ff);
> +}
> +
> +/* (c1*w1 + c2*w2 + c3*w3) >> s */
> +static av_always_inline uint32_t interp_3px(uint32_t c1, int w1, uint32_t c2, int w2, uint32_t c3, int w3, int s)
> +{
> +    return (((((c1 & 0xff00ff00) >> 8) * w1 + ((c2 & 0xff00ff00) >> 8) * w2 + ((c3 & 0xff00ff00) >> 8) * w3) << (8 - s)) & 0xff00ff00) |
> +           (((((c1 & 0x00ff00ff)     ) * w1 + ((c2 & 0x00ff00ff)     ) * w2 + ((c3 & 0x00ff00ff)     ) * w3) >>      s ) & 0x00ff00ff);
> +}
> +
> +/* m is the mask of diff with the center pixel that matters in the pattern, and
> + * r is the expected result (bit set to 1 if there is difference with the
> + * center, 0 otherwise */

nit++++: close parenthesis

[...]

LGTM without looking closer into the algorithm, should be good
assuming it has the same behavior as the reference code.
-- 
FFmpeg = Fantastic & Fabulous Mythic Pure Easy God


More information about the ffmpeg-devel mailing list