[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