[FFmpeg-devel] avfilter: add deblock filter

Submitted by Paul B Mahol on April 18, 2018, 11:08 a.m.

Details

Message ID 20180418110807.14156-1-onemda@gmail.com
State New
Headers show

Commit Message

Paul B Mahol April 18, 2018, 11:08 a.m.
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 doc/filters.texi         |  59 +++++++
 libavfilter/Makefile     |   1 +
 libavfilter/allfilters.c |   1 +
 libavfilter/vf_deblock.c | 409 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 470 insertions(+)
 create mode 100644 libavfilter/vf_deblock.c

Comments

Gyan April 18, 2018, 12:24 p.m.
On 4/18/2018 4:38 PM, Paul B Mahol wrote:

> +@item alpha
> +@item beta
> +@item gamma
> +@item delta
> +Set blocking detection thresholds. Allowed range is 0 to 1.
> +Defaults are: @var{0.098} for @var{alpha} and @var{0.05} for the rest.
> +Using higher threshold gives more deblocking strength.
> +Setting @var{alpha} controls threshold detection at exact edge of block.
> +Remaining options controls threshold detection near the edge. Each one for
> +bellow/above or left/right. Setting any of those to @var{0} disables
> +deblocking.

s/bellow/below

It would be helpful if you can provide more details on how beta, gamma, 
delta affect operation. But if not, that's fine. I'll play with the 
filter once applied and update docs.

Rest docs LGTM.

Regards,
Gyan
Michael Niedermayer April 18, 2018, 8:59 p.m.
On Wed, Apr 18, 2018 at 01:08:07PM +0200, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  doc/filters.texi         |  59 +++++++
>  libavfilter/Makefile     |   1 +
>  libavfilter/allfilters.c |   1 +
>  libavfilter/vf_deblock.c | 409 +++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 470 insertions(+)
>  create mode 100644 libavfilter/vf_deblock.c

Iam not sure the name is a good choice. We have many deblock filters already
The documentation should under the heading of "deblock" refer to all these
filters if such heading is added

Also please list what specification or paper or your own design this is
based on.

I may have more comments if i find the time, as i had worked with similar
filters long ago and this looks a bit familiar but dont wait for me if
i dont find the time

thx

[...]
Paul B Mahol April 18, 2018, 9:11 p.m.
On 4/18/18, Michael Niedermayer <michael@niedermayer.cc> wrote:
> On Wed, Apr 18, 2018 at 01:08:07PM +0200, Paul B Mahol wrote:
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>>  doc/filters.texi         |  59 +++++++
>>  libavfilter/Makefile     |   1 +
>>  libavfilter/allfilters.c |   1 +
>>  libavfilter/vf_deblock.c | 409
>> +++++++++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 470 insertions(+)
>>  create mode 100644 libavfilter/vf_deblock.c
>
> Iam not sure the name is a good choice. We have many deblock filters
> already
> The documentation should under the heading of "deblock" refer to all these
> filters if such heading is added
>
> Also please list what specification or paper or your own design this is
> based on.

It is modified:

A Simple and Efficient Deblocking Algorithm for Low Bit-Rate Video Coding

Looks like pdf is gone from web, but i have it locally.
Michael Niedermayer April 18, 2018, 9:22 p.m.
On Wed, Apr 18, 2018 at 11:11:30PM +0200, Paul B Mahol wrote:
> On 4/18/18, Michael Niedermayer <michael@niedermayer.cc> wrote:
> > On Wed, Apr 18, 2018 at 01:08:07PM +0200, Paul B Mahol wrote:
> >> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> >> ---
> >>  doc/filters.texi         |  59 +++++++
> >>  libavfilter/Makefile     |   1 +
> >>  libavfilter/allfilters.c |   1 +
> >>  libavfilter/vf_deblock.c | 409
> >> +++++++++++++++++++++++++++++++++++++++++++++++
> >>  4 files changed, 470 insertions(+)
> >>  create mode 100644 libavfilter/vf_deblock.c
> >
> > Iam not sure the name is a good choice. We have many deblock filters
> > already
> > The documentation should under the heading of "deblock" refer to all these
> > filters if such heading is added
> >
> > Also please list what specification or paper or your own design this is
> > based on.
> 

> It is modified:
> 
> A Simple and Efficient Deblocking Algorithm for Low Bit-Rate Video Coding

please add this to the file, could be interresting to a reader

thx

[...]

Patch hide | download patch | download mbox

diff --git a/doc/filters.texi b/doc/filters.texi
index 77a1d49520..53e2d70076 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -7078,6 +7078,65 @@  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}.
+This controls what kind of deblocking is applied.
+
+@item block
+Set size of block, allowed range is from 4 to 512. Default is @var{8}.
+
+@item alpha
+@item beta
+@item gamma
+@item delta
+Set blocking detection thresholds. Allowed range is 0 to 1.
+Defaults are: @var{0.098} for @var{alpha} and @var{0.05} for the rest.
+Using higher threshold gives more deblocking strength.
+Setting @var{alpha} controls threshold detection at exact edge of block.
+Remaining options controls threshold detection near the edge. Each one for
+bellow/above or left/right. Setting any of those to @var{0} disables
+deblocking.
+
+@item planes
+Set planes to filter. Default is to filter all available planes.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Deblock using weak filter and block size of 4 pixels.
+@example
+deblock=filter=weak:block=4
+@end example
+
+@item
+Deblock using strong filter, block size of 4 pixels and custom thresholds for
+deblocking more edges.
+@example
+deblock=filter=strong:block=4:alpha=0.12:beta=0.07:gamma=0.06:delta=0.05
+@end example
+
+@item
+Similar as above, but filter only first plane.
+@example
+deblock=filter=strong:block=4:alpha=0.12:beta=0.07:gamma=0.06:delta=0.05:planes=1
+@end example
+
+@item
+Similar as above, but filter only second and third plane.
+@example
+deblock=filter=strong:block=4:alpha=0.12:beta=0.07:gamma=0.06:delta=0.05:planes=6
+@end example
+@end itemize
+
 @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..0c2627370e
--- /dev/null
+++ b/libavfilter/vf_deblock.c
@@ -0,0 +1,409 @@ 
+/*
+ * 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 bpc;
+    int nb_planes;
+    int planewidth[4];
+    int planeheight[4];
+
+    void (*deblockh)(uint8_t *dst, ptrdiff_t dst_linesize, int block,
+                     int ath, int bth, int gth, int dth, int max);
+    void (*deblockv)(uint8_t *dst, ptrdiff_t dst_linesize, 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, ldiv)                                              \
+static void deblockh##name##_weak(uint8_t *dstp, ptrdiff_t dst_linesize, int block, \
+                                  int ath, int bth, int gth, int dth, int max)      \
+{                                                                                   \
+    type *dst;                                                                      \
+    int x;                                                                          \
+                                                                                    \
+    dst = (type *)dstp;                                                             \
+    dst_linesize /= ldiv;                                                           \
+                                                                                    \
+    for (x = 0; x < block; x++) {                                                   \
+        int delta = dst[x] - dst[x - dst_linesize];                                 \
+        int A, B, C, D, a, b, c, d;                                                 \
+                                                                                    \
+        if (FFABS(delta) >= ath ||                                                  \
+            FFABS(dst[x - 1 * dst_linesize] - dst[x - 2 * dst_linesize]) >= bth ||  \
+            FFABS(dst[x + 0 * dst_linesize] - dst[x + 1 * dst_linesize]) >= gth)    \
+            continue;                                                               \
+                                                                                    \
+        A = dst[x - 2 * dst_linesize];                                              \
+        B = dst[x - 1 * dst_linesize];                                              \
+        C = dst[x + 0 * dst_linesize];                                              \
+        D = dst[x + 1 * dst_linesize];                                              \
+                                                                                    \
+        a = A + delta / 8;                                                          \
+        b = B + delta / 2;                                                          \
+        c = C - delta / 2;                                                          \
+        d = D - delta / 8;                                                          \
+                                                                                    \
+        dst[x - 2 * dst_linesize] = av_clip(a, 0, max);                             \
+        dst[x - 1 * dst_linesize] = av_clip(b, 0, max);                             \
+        dst[x + 0 * dst_linesize] = av_clip(c, 0, max);                             \
+        dst[x + 1 * dst_linesize] = av_clip(d, 0, max);                             \
+    }                                                                               \
+}
+
+WEAK_HFILTER(8, uint8_t, 1)
+WEAK_HFILTER(16, uint16_t, 2)
+
+#define WEAK_VFILTER(name, type, ldiv)                                              \
+static void deblockv##name##_weak(uint8_t *dstp, ptrdiff_t dst_linesize, int block, \
+                                  int ath, int bth, int gth, int dth, int max)      \
+{                                                                                   \
+    type *dst;                                                                      \
+    int y;                                                                          \
+                                                                                    \
+    dst = (type *)dstp;                                                             \
+    dst_linesize /= ldiv;                                                           \
+                                                                                    \
+    for (y = 0; y < block; y++) {                                                   \
+        int delta = dst[0] - dst[-1];                                               \
+        int A, B, C, D, a, b, c, d;                                                 \
+                                                                                    \
+        if (FFABS(delta) >= ath ||                                                  \
+            FFABS(dst[-1] - dst[-2]) >= bth ||                                      \
+            FFABS(dst[0] - dst[1]) >= gth)                                          \
+            continue;                                                               \
+                                                                                    \
+        A = dst[-2];                                                                \
+        B = dst[-1];                                                                \
+        C = dst[+0];                                                                \
+        D = dst[+1];                                                                \
+                                                                                    \
+        a = A + delta / 8;                                                          \
+        b = B + delta / 2;                                                          \
+        c = C - delta / 2;                                                          \
+        d = D - delta / 8;                                                          \
+                                                                                    \
+        dst[-2] = av_clip(a, 0, max);                                               \
+        dst[-1] = av_clip(b, 0, max);                                               \
+        dst[+0] = av_clip(c, 0, max);                                               \
+        dst[+1] = av_clip(d, 0, max);                                               \
+                                                                                    \
+        dst += dst_linesize;                                                        \
+    }                                                                               \
+}
+
+WEAK_VFILTER(8, uint8_t, 1)
+WEAK_VFILTER(16, uint16_t, 2)
+
+#define STRONG_HFILTER(name, type, ldiv)                                           \
+static void deblockh##name##_strong(uint8_t *dstp, ptrdiff_t dst_linesize, int block,\
+                                    int ath, int bth, int gth, int dth, int max)   \
+{                                                                                  \
+    type *dst;                                                                     \
+    int x;                                                                         \
+                                                                                   \
+    dst = (type *)dstp;                                                            \
+    dst_linesize /= ldiv;                                                          \
+                                                                                   \
+    for (x = 0; x < block; x++) {                                                  \
+        int A, B, C, D, E, F, a, b, c, d, e, f;                                    \
+        int delta = dst[x] - dst[x - dst_linesize];                                \
+                                                                                   \
+        if (FFABS(delta) >= ath ||                                                 \
+            FFABS(dst[x - 1 * dst_linesize] - dst[x - 2 * dst_linesize]) >= bth || \
+            FFABS(dst[x + 1 * dst_linesize] - dst[x + 2 * dst_linesize]) >= gth || \
+            FFABS(dst[x + 0 * dst_linesize] - dst[x + 1 * dst_linesize]) >= dth)   \
+            continue;                                                              \
+                                                                                   \
+        A = dst[x - 3 * dst_linesize];                                             \
+        B = dst[x - 2 * dst_linesize];                                             \
+        C = dst[x - 1 * dst_linesize];                                             \
+        D = dst[x + 0 * dst_linesize];                                             \
+        E = dst[x + 1 * dst_linesize];                                             \
+        F = dst[x + 2 * dst_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 * dst_linesize] = av_clip(a, 0, max);                            \
+        dst[x - 2 * dst_linesize] = av_clip(b, 0, max);                            \
+        dst[x - 1 * dst_linesize] = av_clip(c, 0, max);                            \
+        dst[x + 0 * dst_linesize] = av_clip(d, 0, max);                            \
+        dst[x + 1 * dst_linesize] = av_clip(e, 0, max);                            \
+        dst[x + 2 * dst_linesize] = av_clip(f, 0, max);                            \
+    }                                                                              \
+}
+
+STRONG_HFILTER(8, uint8_t, 1)
+STRONG_HFILTER(16, uint16_t, 2)
+
+#define STRONG_VFILTER(name, type, ldiv)                                           \
+static void deblockv##name##_strong(uint8_t *dstp, ptrdiff_t dst_linesize, int block,\
+                                    int ath, int bth, int gth, int dth, int max)   \
+{                                                                                  \
+    type *dst;                                                                     \
+    int y;                                                                         \
+                                                                                   \
+    dst = (type *)dstp;                                                            \
+    dst_linesize /= ldiv;                                                          \
+                                                                                   \
+    for (y = 0; y < block; y++) {                                                  \
+        int A, B, C, D, E, F, a, b, c, d, e, f;                                    \
+        int delta = dst[0] - dst[-1];                                              \
+                                                                                   \
+        if (FFABS(delta) >= ath ||                                                 \
+            FFABS(dst[-1] - dst[-2]) >= bth ||                                     \
+            FFABS(dst[+1] - dst[+2]) >= gth ||                                     \
+            FFABS(dst[+0] - dst[+1]) >= dth)                                       \
+            continue;                                                              \
+                                                                                   \
+        A = dst[-3];                                                               \
+        B = dst[-2];                                                               \
+        C = dst[-1];                                                               \
+        D = dst[+0];                                                               \
+        E = dst[+1];                                                               \
+        F = dst[+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[-3] = av_clip(a, 0, max);                                              \
+        dst[-2] = av_clip(b, 0, max);                                              \
+        dst[-1] = av_clip(c, 0, max);                                              \
+        dst[+0] = av_clip(d, 0, max);                                              \
+        dst[+1] = av_clip(e, 0, max);                                              \
+        dst[+2] = av_clip(f, 0, max);                                              \
+                                                                                   \
+        dst += dst_linesize;                                                       \
+    }                                                                              \
+}
+
+STRONG_VFILTER(8, uint8_t, 1)
+STRONG_VFILTER(16, uint16_t, 2)
+
+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->bpc = (s->depth + 7) / 8;
+    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->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, s->desc->log2_chroma_w);
+    s->planewidth[0] = s->planewidth[3] = inlink->w;
+
+    s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h);
+    s->planeheight[0] = s->planeheight[3] = inlink->h;
+
+    return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+    AVFilterContext *ctx = inlink->dst;
+    AVFilterLink *outlink = ctx->outputs[0];
+    DeblockContext *s = ctx->priv;
+    const int block = s->block;
+    AVFrame *out;
+    int plane, x, y;
+
+    if (av_frame_is_writable(in)) {
+        out = in;
+    } else {
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+        if (!out) {
+            av_frame_free(&in);
+            return AVERROR(ENOMEM);
+        }
+        av_frame_copy_props(out, in);
+    }
+
+    for (plane = 0; plane < s->nb_planes; plane++) {
+        const int width = s->planewidth[plane];
+        const int height = s->planeheight[plane];
+        const uint8_t *src = (const uint8_t *)in->data[plane];
+        uint8_t *dst = (uint8_t *)out->data[plane];
+
+        if (in != out)
+            av_image_copy_plane(dst, out->linesize[plane],
+                                src, in->linesize[plane],
+                                width * s->bpc, height);
+
+        if (!((1 << plane) & s->planes))
+            continue;
+
+        for (x = block; x < width; x += block)
+            s->deblockv(dst + x * s->bpc, out->linesize[plane],
+                        FFMIN(block, height), s->ath, s->bth, s->gth, s->dth, s->max);
+
+        for (y = block; y < height; y += block) {
+            dst += out->linesize[plane] * block;
+
+            s->deblockh(dst, out->linesize[plane],
+                        FFMIN(block, width),
+                        s->ath, s->bth, s->gth, s->dth, s->max);
+
+            for (x = block; x < width; x += block) {
+                s->deblockh(dst + x * s->bpc, out->linesize[plane],
+                            FFMIN(block, width - x),
+                            s->ath, s->bth, s->gth, s->dth, s->max);
+                s->deblockv(dst + x * s->bpc, out->linesize[plane],
+                            FFMIN(block, height - y),
+                            s->ath, s->bth, s->gth, s->dth, s->max);
+            }
+        }
+    }
+
+    if (in != out)
+        av_frame_free(&in);
+    return ff_filter_frame(outlink, out);
+}
+
+#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,
+    },
+    { 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,
+};