Browse code

avfilter: add limiter filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2017/07/04 00:42:03
Showing 10 changed files
... ...
@@ -26,6 +26,7 @@ version <next>:
26 26
   --x86asmexe=yasm to configure to restore the old behavior.
27 27
 - additional frame format support for Interplay MVE movies
28 28
 - support for decoding through D3D11VA in ffmpeg
29
+- limiter video filter
29 30
 
30 31
 version 3.3:
31 32
 - CrystalHD decoder moved to new decode API
... ...
@@ -9639,6 +9639,23 @@ The formula that generates the correction is:
9639 9639
 where @var{r_0} is halve of the image diagonal and @var{r_src} and @var{r_tgt} are the
9640 9640
 distances from the focal point in the source and target images, respectively.
9641 9641
 
9642
+@section limiter
9643
+
9644
+Limits the pixel components values to the specified range [min, max].
9645
+
9646
+The filter accepts the following options:
9647
+
9648
+@table @option
9649
+@item min
9650
+Lower bound. Defaults to the lowest allowed value for the input.
9651
+
9652
+@item max
9653
+Upper bound. Defaults to the highest allowed value for the input.
9654
+
9655
+@item planes
9656
+Specify which planes will be processed. Defaults to all available.
9657
+@end table
9658
+
9642 9659
 @section loop
9643 9660
 
9644 9661
 Loop video frames.
... ...
@@ -216,6 +216,7 @@ OBJS-$(CONFIG_INTERLACE_FILTER)              += vf_interlace.o
216 216
 OBJS-$(CONFIG_INTERLEAVE_FILTER)             += f_interleave.o
217 217
 OBJS-$(CONFIG_KERNDEINT_FILTER)              += vf_kerndeint.o
218 218
 OBJS-$(CONFIG_LENSCORRECTION_FILTER)         += vf_lenscorrection.o
219
+OBJS-$(CONFIG_LIMITER_FILTER)                += vf_limiter.o
219 220
 OBJS-$(CONFIG_LOOP_FILTER)                   += f_loop.o
220 221
 OBJS-$(CONFIG_LUMAKEY_FILTER)                += vf_lumakey.o
221 222
 OBJS-$(CONFIG_LUT_FILTER)                    += vf_lut.o
... ...
@@ -228,6 +228,7 @@ static void register_all(void)
228 228
     REGISTER_FILTER(INTERLEAVE,     interleave,     vf);
229 229
     REGISTER_FILTER(KERNDEINT,      kerndeint,      vf);
230 230
     REGISTER_FILTER(LENSCORRECTION, lenscorrection, vf);
231
+    REGISTER_FILTER(LIMITER,        limiter,        vf);
231 232
     REGISTER_FILTER(LOOP,           loop,           vf);
232 233
     REGISTER_FILTER(LUMAKEY,        lumakey,        vf);
233 234
     REGISTER_FILTER(LUT,            lut,            vf);
234 235
new file mode 100644
... ...
@@ -0,0 +1,33 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#ifndef AVFILTER_LIMITER_H
19
+#define AVFILTER_LIMITER_H
20
+
21
+#include <stddef.h>
22
+#include <stdint.h>
23
+
24
+typedef struct LimiterDSPContext {
25
+    void (*limiter)(const uint8_t *src, uint8_t *dst,
26
+                    ptrdiff_t slinesize, ptrdiff_t dlinesize,
27
+                    int w, int h, int min, int max);
28
+} LimiterDSPContext;
29
+
30
+void ff_limiter_init_x86(LimiterDSPContext *dsp, int bpp);
31
+
32
+#endif /* AVFILTER_LIMITER_H */
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR   6
33
-#define LIBAVFILTER_VERSION_MINOR  94
33
+#define LIBAVFILTER_VERSION_MINOR  95
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
37 37
new file mode 100644
... ...
@@ -0,0 +1,231 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include "libavutil/attributes.h"
19
+#include "libavutil/common.h"
20
+#include "libavutil/eval.h"
21
+#include "libavutil/imgutils.h"
22
+#include "libavutil/opt.h"
23
+#include "libavutil/pixdesc.h"
24
+#include "avfilter.h"
25
+#include "formats.h"
26
+#include "internal.h"
27
+#include "limiter.h"
28
+#include "video.h"
29
+
30
+typedef struct LimiterContext {
31
+    const AVClass *class;
32
+    int min;
33
+    int max;
34
+    int planes;
35
+    int nb_planes;
36
+    int linesize[4];
37
+    int width[4];
38
+    int height[4];
39
+
40
+    LimiterDSPContext dsp;
41
+} LimiterContext;
42
+
43
+#define OFFSET(x) offsetof(LimiterContext, x)
44
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
45
+
46
+static const AVOption limiter_options[] = {
47
+    { "min",    "set min value", OFFSET(min),    AV_OPT_TYPE_INT, {.i64=0},     0, 65535, .flags = FLAGS },
48
+    { "max",    "set max value", OFFSET(max),    AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, .flags = FLAGS },
49
+    { "planes", "set planes",    OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15},    0,    15, .flags = FLAGS },
50
+    { NULL }
51
+};
52
+
53
+AVFILTER_DEFINE_CLASS(limiter);
54
+
55
+static av_cold int init(AVFilterContext *ctx)
56
+{
57
+    LimiterContext *s = ctx->priv;
58
+
59
+    if (s->min > s->max)
60
+        return AVERROR(EINVAL);
61
+    return 0;
62
+}
63
+
64
+static int query_formats(AVFilterContext *ctx)
65
+{
66
+    static const enum AVPixelFormat pix_fmts[] = {
67
+        AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
68
+        AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
69
+        AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
70
+        AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
71
+        AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
72
+        AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
73
+        AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
74
+        AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
75
+        AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
76
+        AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
77
+        AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
78
+        AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
79
+        AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
80
+        AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
81
+        AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
82
+        AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
83
+        AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16,
84
+        AV_PIX_FMT_NONE
85
+    };
86
+
87
+    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
88
+    if (!fmts_list)
89
+        return AVERROR(ENOMEM);
90
+    return ff_set_common_formats(ctx, fmts_list);
91
+}
92
+
93
+static void limiter8(const uint8_t *src, uint8_t *dst,
94
+                     ptrdiff_t slinesize, ptrdiff_t dlinesize,
95
+                     int w, int h, int min, int max)
96
+{
97
+    int x, y;
98
+
99
+    for (y = 0; y < h; y++) {
100
+        for (x = 0; x < w; x++) {
101
+            dst[x] = av_clip(src[x], min, max);
102
+        }
103
+
104
+        dst += dlinesize;
105
+        src += slinesize;
106
+    }
107
+}
108
+
109
+static void limiter16(const uint8_t *ssrc, uint8_t *ddst,
110
+                      ptrdiff_t slinesize, ptrdiff_t dlinesize,
111
+                      int w, int h, int min, int max)
112
+{
113
+    const uint16_t *src = (const uint16_t *)ssrc;
114
+    uint16_t *dst = (uint16_t *)ddst;
115
+    int x, y;
116
+
117
+    dlinesize /= 2;
118
+    slinesize /= 2;
119
+
120
+    for (y = 0; y < h; y++) {
121
+        for (x = 0; x < w; x++) {
122
+            dst[x] = av_clip(src[x], min, max);
123
+        }
124
+
125
+        dst += dlinesize;
126
+        src += slinesize;
127
+    }
128
+}
129
+
130
+static int config_props(AVFilterLink *inlink)
131
+{
132
+    AVFilterContext *ctx = inlink->dst;
133
+    LimiterContext *s = ctx->priv;
134
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
135
+    int vsub, hsub, ret;
136
+
137
+    s->nb_planes = av_pix_fmt_count_planes(inlink->format);
138
+
139
+    if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
140
+        return ret;
141
+
142
+    hsub = desc->log2_chroma_w;
143
+    vsub = desc->log2_chroma_h;
144
+    s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, vsub);
145
+    s->height[0] = s->height[3] = inlink->h;
146
+    s->width[1]  = s->width[2]  = AV_CEIL_RSHIFT(inlink->w, hsub);
147
+    s->width[0]  = s->width[3]  = inlink->w;
148
+
149
+    if (desc->comp[0].depth == 8) {
150
+        s->dsp.limiter = limiter8;
151
+        s->max = FFMIN(s->max, 255);
152
+        s->min = FFMIN(s->min, 255);
153
+    } else {
154
+        s->dsp.limiter = limiter16;
155
+    }
156
+
157
+    if (ARCH_X86)
158
+        ff_limiter_init_x86(&s->dsp, desc->comp[0].depth);
159
+
160
+    return 0;
161
+}
162
+
163
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
164
+{
165
+    AVFilterContext *ctx = inlink->dst;
166
+    LimiterContext *s = ctx->priv;
167
+    AVFilterLink *outlink = ctx->outputs[0];
168
+    AVFrame *out;
169
+    int p;
170
+
171
+    if (av_frame_is_writable(in)) {
172
+        out = in;
173
+    } else {
174
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
175
+        if (!out) {
176
+            av_frame_free(&in);
177
+            return AVERROR(ENOMEM);
178
+        }
179
+        av_frame_copy_props(out, in);
180
+    }
181
+
182
+    for (p = 0; p < s->nb_planes; p++) {
183
+        if (!((1 << p) & s->planes)) {
184
+            if (out != in)
185
+                av_image_copy_plane(out->data[p], out->linesize[p], in->data[p], in->linesize[p],
186
+                                    s->linesize[p], s->height[p]);
187
+            continue;
188
+        }
189
+
190
+        s->dsp.limiter(in->data[p], out->data[p],
191
+                       in->linesize[p], out->linesize[p],
192
+                       s->width[p], s->height[p],
193
+                       s->min, s->max);
194
+    }
195
+
196
+    if (out != in)
197
+        av_frame_free(&in);
198
+
199
+    return ff_filter_frame(outlink, out);
200
+}
201
+
202
+static const AVFilterPad inputs[] = {
203
+    {
204
+        .name         = "default",
205
+        .type         = AVMEDIA_TYPE_VIDEO,
206
+        .filter_frame = filter_frame,
207
+        .config_props = config_props,
208
+    },
209
+    { NULL }
210
+};
211
+
212
+static const AVFilterPad outputs[] = {
213
+    {
214
+        .name = "default",
215
+        .type = AVMEDIA_TYPE_VIDEO,
216
+    },
217
+    { NULL }
218
+};
219
+
220
+AVFilter ff_vf_limiter = {
221
+    .name          = "limiter",
222
+    .description   = NULL_IF_CONFIG_SMALL("Limit pixels components to the specified range."),
223
+    .priv_size     = sizeof(LimiterContext),
224
+    .priv_class    = &limiter_class,
225
+    .init          = init,
226
+    .query_formats = query_formats,
227
+    .inputs        = inputs,
228
+    .outputs       = outputs,
229
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
230
+};
... ...
@@ -8,6 +8,7 @@ OBJS-$(CONFIG_GRADFUN_FILTER)                += x86/vf_gradfun_init.o
8 8
 OBJS-$(CONFIG_HQDN3D_FILTER)                 += x86/vf_hqdn3d_init.o
9 9
 OBJS-$(CONFIG_IDET_FILTER)                   += x86/vf_idet_init.o
10 10
 OBJS-$(CONFIG_INTERLACE_FILTER)              += x86/vf_interlace_init.o
11
+OBJS-$(CONFIG_LIMITER_FILTER)                += x86/vf_limiter_init.o
11 12
 OBJS-$(CONFIG_MASKEDMERGE_FILTER)            += x86/vf_maskedmerge_init.o
12 13
 OBJS-$(CONFIG_NOISE_FILTER)                  += x86/vf_noise.o
13 14
 OBJS-$(CONFIG_PP7_FILTER)                    += x86/vf_pp7_init.o
... ...
@@ -33,6 +34,7 @@ X86ASM-OBJS-$(CONFIG_GRADFUN_FILTER)         += x86/vf_gradfun.o
33 33
 X86ASM-OBJS-$(CONFIG_HQDN3D_FILTER)          += x86/vf_hqdn3d.o
34 34
 X86ASM-OBJS-$(CONFIG_IDET_FILTER)            += x86/vf_idet.o
35 35
 X86ASM-OBJS-$(CONFIG_INTERLACE_FILTER)       += x86/vf_interlace.o
36
+X86ASM-OBJS-$(CONFIG_LIMITER_FILTER)         += x86/vf_limiter.o
36 37
 X86ASM-OBJS-$(CONFIG_MASKEDMERGE_FILTER)     += x86/vf_maskedmerge.o
37 38
 X86ASM-OBJS-$(CONFIG_PP7_FILTER)             += x86/vf_pp7.o
38 39
 X86ASM-OBJS-$(CONFIG_PSNR_FILTER)            += x86/vf_psnr.o
39 40
new file mode 100644
... ...
@@ -0,0 +1,84 @@
0
+;*****************************************************************************
1
+;* x86-optimized functions for limiter filter
2
+;*
3
+;* This file is part of FFmpeg.
4
+;*
5
+;* FFmpeg is free software; you can redistribute it and/or
6
+;* modify it under the terms of the GNU Lesser General Public
7
+;* License as published by the Free Software Foundation; either
8
+;* version 2.1 of the License, or (at your option) any later version.
9
+;*
10
+;* FFmpeg is distributed in the hope that it will be useful,
11
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+;* Lesser General Public License for more details.
14
+;*
15
+;* You should have received a copy of the GNU Lesser General Public
16
+;* License along with FFmpeg; if not, write to the Free Software
17
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+;******************************************************************************
19
+
20
+%include "libavutil/x86/x86util.asm"
21
+
22
+%if ARCH_X86_64
23
+
24
+SECTION_RODATA
25
+
26
+pb_0: times 16 db 0
27
+
28
+SECTION .text
29
+
30
+INIT_XMM sse2
31
+
32
+cglobal limiter_8bit, 8, 9, 3, src, dst, slinesize, dlinesize, w, h, min, max, x
33
+    movsxdifnidn wq, wd
34
+    add        srcq, wq
35
+    add        dstq, wq
36
+    neg          wq
37
+    SPLATB_REG   m1, min, [pb_0]
38
+    SPLATB_REG   m2, max, [pb_0]
39
+.nextrow:
40
+    mov          xq, wq
41
+
42
+    .loop:
43
+        movu           m0, [srcq + xq]
44
+        CLIPUB         m0, m1, m2
45
+        mova    [dstq+xq], m0
46
+        add            xq, mmsize
47
+    jl .loop
48
+
49
+    add        srcq, slinesizeq
50
+    add        dstq, dlinesizeq
51
+    sub        hd, 1
52
+    jg .nextrow
53
+    ret
54
+
55
+INIT_XMM sse4
56
+
57
+cglobal limiter_16bit, 8, 9, 3, src, dst, slinesize, dlinesize, w, h, min, max, x
58
+    shl          wd, 1
59
+    add        srcq, wq
60
+    add        dstq, wq
61
+    neg          wq
62
+    movd         m1, mind
63
+    SPLATW       m1, m1
64
+    movd         m2, maxd
65
+    SPLATW       m2, m2
66
+.nextrow:
67
+    mov          xq, wq
68
+
69
+    .loop:
70
+        movu           m0, [srcq + xq]
71
+        pmaxuw         m0, m1
72
+        pminuw         m0, m2
73
+        mova    [dstq+xq], m0
74
+        add            xq, mmsize
75
+    jl .loop
76
+
77
+    add        srcq, slinesizeq
78
+    add        dstq, dlinesizeq
79
+    sub        hd, 1
80
+    jg .nextrow
81
+    ret
82
+
83
+%endif
0 84
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include "libavutil/x86/cpu.h"
19
+
20
+#include "libavfilter/limiter.h"
21
+
22
+void ff_limiter_8bit_sse2(const uint8_t *src, uint8_t *dst,
23
+                          ptrdiff_t slinesize, ptrdiff_t dlinesize,
24
+                          int w, int h, int min, int max);
25
+void ff_limiter_16bit_sse4(const uint8_t *src, uint8_t *dst,
26
+                           ptrdiff_t slinesize, ptrdiff_t dlinesize,
27
+                           int w, int h, int min, int max);
28
+
29
+void ff_limiter_init_x86(LimiterDSPContext *dsp, int bpp)
30
+{
31
+    int cpu_flags = av_get_cpu_flags();
32
+
33
+    if (ARCH_X86_64 && EXTERNAL_SSE2(cpu_flags)) {
34
+        if (bpp <= 8) {
35
+            dsp->limiter = ff_limiter_8bit_sse2;
36
+        }
37
+    }
38
+    if (ARCH_X86_64 && EXTERNAL_SSE4(cpu_flags)) {
39
+        if (bpp > 8) {
40
+            dsp->limiter = ff_limiter_16bit_sse4;
41
+        }
42
+    }
43
+}