diff mbox

[FFmpeg-devel] avfilter: add deblock filter

Message ID 20180417205551.19151-1-onemda@gmail.com
State Superseded
Headers show

Commit Message

Paul B Mahol April 17, 2018, 8:55 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 doc/filters.texi         |  23 +++
 libavfilter/Makefile     |   1 +
 libavfilter/allfilters.c |   1 +
 libavfilter/vf_deblock.c | 366 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 391 insertions(+)
 create mode 100644 libavfilter/vf_deblock.c

Comments

Gyan April 18, 2018, 4:51 a.m. UTC | #1
On 4/18/2018 2:25 AM, Paul B Mahol wrote:

> +@item block
> +Set size of block, allowed range is from 4 to 512.

Is this along each dimension? What happens if value is greater than 
width or height? Please indicate default value.

> +@item alpha
> +@item beta
> +@item gamma
> +@item delta
> +Set blocking detection thresholds.

What do these mean? What's the range? Please indicate default values.



Can you add an one or two examples, showing the various options in use?

Thanks,
Gyan
diff mbox

Patch

diff --git a/doc/filters.texi b/doc/filters.texi
index 77a1d49520..2ec6e85e81 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -7078,6 +7078,29 @@  e.g. banding detection threshold is triggered for all color components.
 The default is disabled.
 @end table
 
+@section deblock
+
+Remove blocking artifacts from input video.
+
+The filter accepts the following options:
+
+@table @option
+@item filter
+Set filter type, can be @var{weak} or @var{strong}. Default is @var{strong}.
+
+@item block
+Set size of block, allowed range is from 4 to 512.
+
+@item alpha
+@item beta
+@item gamma
+@item delta
+Set blocking detection thresholds.
+
+@item planes
+Set planes to filter. Default is to filter all available planes.
+@end table
+
 @anchor{decimate}
 @section decimate
 
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 7fc3de3bb2..0cd964ee6f 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -173,6 +173,7 @@  OBJS-$(CONFIG_CURVES_FILTER)                 += vf_curves.o
 OBJS-$(CONFIG_DATASCOPE_FILTER)              += vf_datascope.o
 OBJS-$(CONFIG_DCTDNOIZ_FILTER)               += vf_dctdnoiz.o
 OBJS-$(CONFIG_DEBAND_FILTER)                 += vf_deband.o
+OBJS-$(CONFIG_DEBLOCK_FILTER)                += vf_deblock.o
 OBJS-$(CONFIG_DECIMATE_FILTER)               += vf_decimate.o
 OBJS-$(CONFIG_DECONVOLVE_FILTER)             += vf_convolve.o framesync.o
 OBJS-$(CONFIG_DEFLATE_FILTER)                += vf_neighbor.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index bd55463bfc..643eec287d 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -165,6 +165,7 @@  extern AVFilter ff_vf_curves;
 extern AVFilter ff_vf_datascope;
 extern AVFilter ff_vf_dctdnoiz;
 extern AVFilter ff_vf_deband;
+extern AVFilter ff_vf_deblock;
 extern AVFilter ff_vf_decimate;
 extern AVFilter ff_vf_deconvolve;
 extern AVFilter ff_vf_deflate;
diff --git a/libavfilter/vf_deblock.c b/libavfilter/vf_deblock.c
new file mode 100644
index 0000000000..f40550437f
--- /dev/null
+++ b/libavfilter/vf_deblock.c
@@ -0,0 +1,366 @@ 
+/*
+ * Copyright (c) 2018 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum FilterType { WEAK, STRONG, NB_FILTER };
+
+typedef struct DeblockContext {
+    const AVClass *class;
+    const AVPixFmtDescriptor *desc;
+    int filter;
+    int block;
+    int planes;
+    float alpha;
+    float beta;
+    float gamma;
+    float delta;
+
+    int ath;
+    int bth;
+    int gth;
+    int dth;
+    int max;
+    int depth;
+    int nb_planes;
+    int width[4];
+    int height[4];
+
+    void (*deblockh)(uint8_t *dst, ptrdiff_t linesize, int width, int height,
+                     int block, int ath, int bth, int gth, int dth, int max);
+    void (*deblockv)(uint8_t *dst, ptrdiff_t linesize, int width, int height,
+                     int block, int ath, int bth, int gth, int dth, int max);
+} DeblockContext;
+
+static int query_formats(AVFilterContext *ctx)
+{
+    static const enum AVPixelFormat pixel_fmts[] = {
+        AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
+        AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
+        AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
+        AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
+        AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
+        AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
+        AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
+        AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
+        AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
+        AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
+        AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
+        AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
+        AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
+        AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
+        AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
+        AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
+        AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16,
+        AV_PIX_FMT_NONE
+    };
+    AVFilterFormats *formats = ff_make_format_list(pixel_fmts);
+    if (!formats)
+        return AVERROR(ENOMEM);
+    return ff_set_common_formats(ctx, formats);
+}
+
+#define WEAK_HFILTER(name, type)                                                            \
+static void deblockh##name##_weak(uint8_t *dstp, ptrdiff_t linesize, int width, int height, \
+                                  int block, int ath, int bth, int gth, int dth, int max)   \
+{                                                                                           \
+    type *dst;                                                                              \
+    int x, y;                                                                               \
+                                                                                            \
+    for (y = block; y < height - 2; y += block) {                                           \
+        dst = (type *)(dstp + y * linesize);                                                \
+        for (x = 0; x < width; x++) {                                                       \
+            int delta = dst[x] - dst[x - linesize];                                         \
+            int A, B, C, D, a, b, c, d;                                                     \
+                                                                                            \
+            if (FFABS(delta) >= ath ||                                                      \
+                FFABS(dst[x - 1 * linesize] - dst[x - 2 * linesize]) >= bth ||              \
+                FFABS(dst[x + 0 * linesize] - dst[x + 1 * linesize]) >= gth)                \
+                continue;                                                                   \
+                                                                                            \
+            A = dst[x - 2 * linesize];                                                      \
+            B = dst[x - 1 * linesize];                                                      \
+            C = dst[x + 0 * linesize];                                                      \
+            D = dst[x + 1 * linesize];                                                      \
+                                                                                            \
+            a = A + delta / 8;                                                              \
+            b = B + delta / 2;                                                              \
+            c = C - delta / 2;                                                              \
+            d = D - delta / 8;                                                              \
+                                                                                            \
+            dst[x - 2 * linesize] = av_clip(a, 0, max);                                     \
+            dst[x - 1 * linesize] = av_clip(b, 0, max);                                     \
+            dst[x + 0 * linesize] = av_clip(c, 0, max);                                     \
+            dst[x + 1 * linesize] = av_clip(d, 0, max);                                     \
+        }                                                                                   \
+    }                                                                                       \
+}
+
+WEAK_HFILTER(8, uint8_t)
+WEAK_HFILTER(16, uint16_t)
+
+#define WEAK_VFILTER(name, type)                                                            \
+static void deblockv##name##_weak(uint8_t *dstp, ptrdiff_t linesize, int width, int height, \
+                                  int block, int ath, int bth, int gth, int dth, int max)   \
+{                                                                                           \
+    type *dst;                                                                              \
+    int x, y;                                                                               \
+                                                                                            \
+    for (y = 0; y < height; y++) {                                                          \
+        dst = (type *)(dstp + y * linesize);                                                \
+        for (x = block; x < width - 2; x += block) {                                        \
+            int delta = dst[x] - dst[x - 1];                                                \
+            int A, B, C, D, a, b, c, d;                                                     \
+                                                                                            \
+            if (FFABS(delta) >= ath ||                                                      \
+                FFABS(dst[x - 1] - dst[x - 2]) >= bth ||                                    \
+                FFABS(dst[x + 0] - dst[x + 1]) >= gth)                                      \
+                continue;                                                                   \
+                                                                                            \
+            A = dst[x - 2];                                                                 \
+            B = dst[x - 1];                                                                 \
+            C = dst[x + 0];                                                                 \
+            D = dst[x + 1];                                                                 \
+                                                                                            \
+            a = A + delta / 8;                                                              \
+            b = B + delta / 2;                                                              \
+            c = C - delta / 2;                                                              \
+            d = D - delta / 8;                                                              \
+                                                                                            \
+            dst[x - 2] = av_clip(a, 0, max);                                                \
+            dst[x - 1] = av_clip(b, 0, max);                                                \
+            dst[x + 0] = av_clip(c, 0, max);                                                \
+            dst[x + 1] = av_clip(d, 0, max);                                                \
+        }                                                                                   \
+    }                                                                                       \
+}
+
+WEAK_VFILTER(8, uint8_t)
+WEAK_VFILTER(16, uint16_t)
+
+#define STRONG_HFILTER(name, type)                                                     \
+static void deblockh##name##_strong(uint8_t *dstp, ptrdiff_t linesize,                 \
+                                    int width, int height, int block,                  \
+                                    int ath, int bth, int gth, int dth, int max)       \
+{                                                                                      \
+    type *dst;                                                                         \
+    int x, y;                                                                          \
+                                                                                       \
+    for (y = block; y < height - 3; y += block) {                                      \
+        dst = (type *)(dstp + y * linesize);                                           \
+        for (x = 0; x < width; x++) {                                                  \
+            int A, B, C, D, E, F, a, b, c, d, e, f;                                    \
+            int delta = dst[x] - dst[x - linesize];                                    \
+                                                                                       \
+            if (FFABS(delta) >= ath ||                                                 \
+                FFABS(dst[x - 1 * linesize] - dst[x - 2 * linesize]) >= bth ||         \
+                FFABS(dst[x + 1 * linesize] - dst[x + 2 * linesize]) >= gth ||         \
+                FFABS(dst[x + 0 * linesize] - dst[x + 1 * linesize]) >= dth)           \
+                continue;                                                              \
+                                                                                       \
+            A = dst[x - 3 * linesize];                                                 \
+            B = dst[x - 2 * linesize];                                                 \
+            C = dst[x - 1 * linesize];                                                 \
+            D = dst[x + 0 * linesize];                                                 \
+            E = dst[x + 1 * linesize];                                                 \
+            F = dst[x + 2 * linesize];                                                 \
+                                                                                       \
+            a = A + delta / 8;                                                         \
+            b = B + delta / 4;                                                         \
+            c = C + delta / 2;                                                         \
+            d = D - delta / 2;                                                         \
+            e = E - delta / 4;                                                         \
+            f = F - delta / 8;                                                         \
+                                                                                       \
+            dst[x - 3 * linesize] = av_clip(a, 0, max);                                \
+            dst[x - 2 * linesize] = av_clip(b, 0, max);                                \
+            dst[x - 1 * linesize] = av_clip(c, 0, max);                                \
+            dst[x + 0 * linesize] = av_clip(d, 0, max);                                \
+            dst[x + 1 * linesize] = av_clip(e, 0, max);                                \
+            dst[x + 2 * linesize] = av_clip(f, 0, max);                                \
+        }                                                                              \
+    }                                                                                  \
+}
+
+STRONG_HFILTER(8, uint8_t)
+STRONG_HFILTER(16, uint16_t)
+
+#define STRONG_VFILTER(name, type)                                                     \
+static void deblockv##name##_strong(uint8_t *dstp, ptrdiff_t linesize,                 \
+                                    int width, int height, int block,                  \
+                                    int ath, int bth, int gth, int dth, int max)       \
+{                                                                                      \
+    type *dst;                                                                         \
+    int x, y;                                                                          \
+                                                                                       \
+    for (y = 0; y < height; y++) {                                                     \
+        dst = (type *)(dstp + y * linesize);                                           \
+        for (x = block; x < width - 3; x += block) {                                   \
+            int A, B, C, D, E, F, a, b, c, d, e, f;                                    \
+            int delta = dst[x] - dst[x - 1];                                           \
+                                                                                       \
+            if (FFABS(delta) >= ath ||                                                 \
+                FFABS(dst[x - 1] - dst[x - 2]) >= bth ||                               \
+                FFABS(dst[x + 1] - dst[x + 2]) >= gth ||                               \
+                FFABS(dst[x + 0] - dst[x + 1]) >= dth)                                 \
+                continue;                                                              \
+                                                                                       \
+            A = dst[x - 3];                                                            \
+            B = dst[x - 2];                                                            \
+            C = dst[x - 1];                                                            \
+            D = dst[x + 0];                                                            \
+            E = dst[x + 1];                                                            \
+            F = dst[x + 2];                                                            \
+                                                                                       \
+            a = A + delta / 8;                                                         \
+            b = B + delta / 4;                                                         \
+            c = C + delta / 2;                                                         \
+            d = D - delta / 2;                                                         \
+            e = E - delta / 4;                                                         \
+            f = F - delta / 8;                                                         \
+                                                                                       \
+            dst[x - 3] = av_clip(a, 0, max);                                           \
+            dst[x - 2] = av_clip(b, 0, max);                                           \
+            dst[x - 1] = av_clip(c, 0, max);                                           \
+            dst[x + 0] = av_clip(d, 0, max);                                           \
+            dst[x + 1] = av_clip(e, 0, max);                                           \
+            dst[x + 2] = av_clip(f, 0, max);                                           \
+        }                                                                              \
+    }                                                                                  \
+}
+
+STRONG_VFILTER(8, uint8_t)
+STRONG_VFILTER(16, uint16_t)
+
+static int config_output(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    DeblockContext *s = ctx->priv;
+    AVFilterLink *inlink = ctx->inputs[0];
+
+    s->desc = av_pix_fmt_desc_get(outlink->format);
+    if (!s->desc)
+        return AVERROR_BUG;
+    s->nb_planes = av_pix_fmt_count_planes(outlink->format);
+    s->depth = s->desc->comp[0].depth;
+    s->max = (1 << s->depth) - 1;
+    s->ath = s->alpha * s->max;
+    s->bth = s->beta  * s->max;
+    s->gth = s->gamma * s->max;
+    s->dth = s->delta * s->max;
+
+    if (s->depth <= 8 && s->filter == WEAK) {
+        s->deblockh = deblockh8_weak;
+        s->deblockv = deblockv8_weak;
+    } else if (s->depth >= 8 && s->filter == WEAK) {
+        s->deblockh = deblockh16_weak;
+        s->deblockv = deblockv16_weak;
+    }
+    if (s->depth <= 8 && s->filter == STRONG) {
+        s->deblockh = deblockh8_strong;
+        s->deblockv = deblockv8_strong;
+    } else if (s->depth >= 8 && s->filter == STRONG) {
+        s->deblockh = deblockh16_strong;
+        s->deblockv = deblockv16_strong;
+    }
+
+    s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, s->desc->log2_chroma_w);
+    s->width[0] = s->width[3] = inlink->w;
+
+    s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h);
+    s->height[0] = s->height[3] = inlink->h;
+
+    return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+    AVFilterContext *ctx = inlink->dst;
+    AVFilterLink *outlink = ctx->outputs[0];
+    DeblockContext *s = ctx->priv;
+    int plane;
+
+    for (plane = 0; plane < s->nb_planes; plane++) {
+        if (!((1 << plane) & s->planes))
+            continue;
+        s->deblockh(frame->data[plane], frame->linesize[plane],
+                    s->width[plane], s->height[plane], s->block,
+                    s->ath, s->bth, s->gth, s->dth, s->max);
+        s->deblockv(frame->data[plane], frame->linesize[plane],
+                    s->width[plane], s->height[plane], s->block,
+                    s->ath, s->bth, s->gth, s->dth, s->max);
+    }
+
+    return ff_filter_frame(outlink, frame);
+}
+
+#define OFFSET(x) offsetof(DeblockContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption deblock_options[] = {
+    { "filter",    "set type of filter",          OFFSET(filter),    AV_OPT_TYPE_INT,   {.i64=STRONG},0, 1,  FLAGS, "filter" },
+    { "weak",      0,                             0,                 AV_OPT_TYPE_CONST, {.i64=WEAK},  0, 0,  FLAGS, "filter" },
+    { "strong",    0,                             0,                 AV_OPT_TYPE_CONST, {.i64=STRONG},0, 0,  FLAGS, "filter" },
+    { "block",     "set size of block",           OFFSET(block),     AV_OPT_TYPE_INT,   {.i64=8},    4, 512, FLAGS },
+    { "alpha",     "set 1st detection threshold", OFFSET(alpha),     AV_OPT_TYPE_FLOAT, {.dbl=.098}, 0,  1,  FLAGS },
+    { "beta",      "set 2nd detection threshold", OFFSET(beta),      AV_OPT_TYPE_FLOAT, {.dbl=.05},  0,  1,  FLAGS },
+    { "gamma",     "set 3rd detection threshold", OFFSET(gamma),     AV_OPT_TYPE_FLOAT, {.dbl=.05},  0,  1,  FLAGS },
+    { "delta",     "set 4th detection threshold", OFFSET(delta),     AV_OPT_TYPE_FLOAT, {.dbl=.05},  0,  1,  FLAGS },
+    { "planes",    "set planes to filter",        OFFSET(planes),    AV_OPT_TYPE_INT,   {.i64=15},   0, 15,  FLAGS },
+    { NULL },
+};
+
+static const AVFilterPad inputs[] = {
+    {
+        .name           = "default",
+        .type           = AVMEDIA_TYPE_VIDEO,
+        .filter_frame   = filter_frame,
+        .needs_writable = 1,
+    },
+    { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .config_props  = config_output,
+    },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(deblock);
+
+AVFilter ff_vf_deblock = {
+    .name          = "deblock",
+    .description   = NULL_IF_CONFIG_SMALL("Deblock video."),
+    .priv_size     = sizeof(DeblockContext),
+    .priv_class    = &deblock_class,
+    .query_formats = query_formats,
+    .inputs        = inputs,
+    .outputs       = outputs,
+};