FFmpeg
Loading...
Searching...
No Matches
vf_sab.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21/**
22 * @file
23 * Shape Adaptive Blur filter, ported from MPlayer libmpcodecs/vf_sab.c
24 */
25
26#include "libavutil/mem.h"
27#include "libavutil/opt.h"
28#include "libavutil/pixdesc.h"
29#include "libswscale/swscale.h"
30
31#include "avfilter.h"
32#include "filters.h"
33#include "video.h"
34
35typedef struct FilterParam {
36 float radius;
38 float strength;
39 float quality;
46#define COLOR_DIFF_COEFF_SIZE 512
49
50typedef struct SabContext {
51 const AVClass *class;
54 int hsub;
55 int vsub;
56 unsigned int sws_flags;
58
67
68#define RADIUS_MIN 0.1
69#define RADIUS_MAX 4.0
70
71#define PRE_FILTER_RADIUS_MIN 0.1
72#define PRE_FILTER_RADIUS_MAX 2.0
73
74#define STRENGTH_MIN 0.1
75#define STRENGTH_MAX 100.0
76
77#define OFFSET(x) offsetof(SabContext, x)
78#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
79
80static const AVOption sab_options[] = {
81 { "luma_radius", "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
82 { "lr" , "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
83 { "luma_pre_filter_radius", "set luma pre-filter radius", OFFSET(luma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, PRE_FILTER_RADIUS_MIN, PRE_FILTER_RADIUS_MAX, .flags=FLAGS },
84 { "lpfr", "set luma pre-filter radius", OFFSET(luma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, PRE_FILTER_RADIUS_MIN, PRE_FILTER_RADIUS_MAX, .flags=FLAGS },
85 { "luma_strength", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
86 { "ls", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
87
88 { "chroma_radius", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
89 { "cr", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
90 { "chroma_pre_filter_radius", "set chroma pre-filter radius", OFFSET(chroma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=PRE_FILTER_RADIUS_MIN-1},
92 { "cpfr", "set chroma pre-filter radius", OFFSET(chroma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=PRE_FILTER_RADIUS_MIN-1},
94 { "chroma_strength", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
95 { "cs", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
96
97 { NULL }
98};
99
101
103{
104 SabContext *s = ctx->priv;
105
106 /* make chroma default to luma values, if not explicitly set */
107 if (s->chroma.radius < RADIUS_MIN)
108 s->chroma.radius = s->luma.radius;
109 if (s->chroma.pre_filter_radius < PRE_FILTER_RADIUS_MIN)
110 s->chroma.pre_filter_radius = s->luma.pre_filter_radius;
111 if (s->chroma.strength < STRENGTH_MIN)
112 s->chroma.strength = s->luma.strength;
113
114 s->luma.quality = s->chroma.quality = 3.0;
115 s->sws_flags = SWS_POINT;
116
118 "luma_radius:%f luma_pre_filter_radius::%f luma_strength:%f "
119 "chroma_radius:%f chroma_pre_filter_radius:%f chroma_strength:%f\n",
120 s->luma .radius, s->luma .pre_filter_radius, s->luma .strength,
121 s->chroma.radius, s->chroma.pre_filter_radius, s->chroma.strength);
122 return 0;
123}
124
126{
127 if (f->pre_filter_context) {
128 sws_freeContext(f->pre_filter_context);
129 f->pre_filter_context = NULL;
130 }
131 av_freep(&f->pre_filter_buf);
132 av_freep(&f->dist_coeff);
133}
134
136{
137 SabContext *s = ctx->priv;
138
139 close_filter_param(&s->luma);
140 close_filter_param(&s->chroma);
141}
142
143static int open_filter_param(FilterParam *f, int width, int height, unsigned int sws_flags)
144{
145 SwsVector *vec;
146 SwsFilter sws_f;
147 int i, x, y;
148 int linesize = FFALIGN(width, 8);
149
150 f->pre_filter_buf = av_malloc(linesize * height);
151 if (!f->pre_filter_buf)
152 return AVERROR(ENOMEM);
153
154 f->pre_filter_linesize = linesize;
155 vec = sws_getGaussianVec(f->pre_filter_radius, f->quality);
156 sws_f.lumH = sws_f.lumV = vec;
157 sws_f.chrH = sws_f.chrV = NULL;
158 f->pre_filter_context = sws_getContext(width, height, AV_PIX_FMT_GRAY8,
160 sws_flags, &sws_f, NULL, NULL);
161 sws_freeVec(vec);
162
163 vec = sws_getGaussianVec(f->strength, 5.0);
164 for (i = 0; i < COLOR_DIFF_COEFF_SIZE; i++) {
165 double d;
166 int index = i-COLOR_DIFF_COEFF_SIZE/2 + vec->length/2;
167
168 if (index < 0 || index >= vec->length) d = 0.0;
169 else d = vec->coeff[index];
170
171 f->color_diff_coeff[i] = (int)(d/vec->coeff[vec->length/2]*(1<<12) + 0.5);
172 }
173 sws_freeVec(vec);
174
175 vec = sws_getGaussianVec(f->radius, f->quality);
176 f->dist_width = vec->length;
177 f->dist_linesize = FFALIGN(vec->length, 8);
178 f->dist_coeff = av_malloc_array(f->dist_width, f->dist_linesize * sizeof(*f->dist_coeff));
179 if (!f->dist_coeff) {
180 sws_freeVec(vec);
181 return AVERROR(ENOMEM);
182 }
183
184 for (y = 0; y < vec->length; y++) {
185 for (x = 0; x < vec->length; x++) {
186 double d = vec->coeff[x] * vec->coeff[y];
187 f->dist_coeff[x + y*f->dist_linesize] = (int)(d*(1<<10) + 0.5);
188 }
189 }
190 sws_freeVec(vec);
191
192 return 0;
193}
194
195static int config_props(AVFilterLink *inlink)
196{
197 SabContext *s = inlink->dst->priv;
199 int ret;
200
201 s->hsub = desc->log2_chroma_w;
202 s->vsub = desc->log2_chroma_h;
203
204 close_filter_param(&s->luma);
205 ret = open_filter_param(&s->luma, inlink->w, inlink->h, s->sws_flags);
206 if (ret < 0)
207 return ret;
208
209 close_filter_param(&s->chroma);
210 ret = open_filter_param(&s->chroma,
211 AV_CEIL_RSHIFT(inlink->w, s->hsub),
212 AV_CEIL_RSHIFT(inlink->h, s->vsub), s->sws_flags);
213 return ret;
214}
215
216#define NB_PLANES 4
217
218static void blur(uint8_t *dst, const int dst_linesize,
219 const uint8_t *src, const int src_linesize,
220 const int w, const int h, FilterParam *fp)
221{
222 int x, y;
223 FilterParam f = *fp;
224 const int radius = f.dist_width/2;
225
226 const uint8_t * const src2[NB_PLANES] = { src };
227 int src2_linesize[NB_PLANES] = { src_linesize };
228 uint8_t *dst2[NB_PLANES] = { f.pre_filter_buf };
229 int dst2_linesize[NB_PLANES] = { f.pre_filter_linesize };
230
231 sws_scale(f.pre_filter_context, src2, src2_linesize, 0, h, dst2, dst2_linesize);
232
233#define UPDATE_FACTOR do { \
234 int factor; \
235 factor = f.color_diff_coeff[COLOR_DIFF_COEFF_SIZE/2 + pre_val - \
236 f.pre_filter_buf[ix + iy*f.pre_filter_linesize]] * f.dist_coeff[dx + dy*f.dist_linesize]; \
237 sum += src[ix + iy*src_linesize] * factor; \
238 div += factor; \
239 } while (0)
240
241 for (y = 0; y < h; y++) {
242 for (x = 0; x < w; x++) {
243 int sum = 0;
244 int div = 0;
245 int dy;
246 const int pre_val = f.pre_filter_buf[x + y*f.pre_filter_linesize];
247 if (x >= radius && x < w - radius) {
248 for (dy = 0; dy < radius*2 + 1; dy++) {
249 int dx;
250 int iy = y+dy - radius;
251 iy = avpriv_mirror(iy, h-1);
252
253 for (dx = 0; dx < radius*2 + 1; dx++) {
254 const int ix = x+dx - radius;
256 }
257 }
258 } else {
259 for (dy = 0; dy < radius*2+1; dy++) {
260 int dx;
261 int iy = y+dy - radius;
262 iy = avpriv_mirror(iy, h-1);
263
264 for (dx = 0; dx < radius*2 + 1; dx++) {
265 int ix = x+dx - radius;
266 ix = avpriv_mirror(ix, w-1);
268 }
269 }
270 }
271 dst[x + y*dst_linesize] = (sum + div/2) / div;
272 }
273 }
274}
275
277{
278 SabContext *s = inlink->dst->priv;
279 AVFilterLink *outlink = inlink->dst->outputs[0];
280 AVFrame *outpic;
281
282 outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
283 if (!outpic) {
285 return AVERROR(ENOMEM);
286 }
287 av_frame_copy_props(outpic, inpic);
288
289 blur(outpic->data[0], outpic->linesize[0], inpic->data[0], inpic->linesize[0],
290 inlink->w, inlink->h, &s->luma);
291 if (inpic->data[2]) {
292 int cw = AV_CEIL_RSHIFT(inlink->w, s->hsub);
293 int ch = AV_CEIL_RSHIFT(inlink->h, s->vsub);
294 blur(outpic->data[1], outpic->linesize[1], inpic->data[1], inpic->linesize[1], cw, ch, &s->chroma);
295 blur(outpic->data[2], outpic->linesize[2], inpic->data[2], inpic->linesize[2], cw, ch, &s->chroma);
296 }
297
299 return ff_filter_frame(outlink, outpic);
300}
301
302static const AVFilterPad sab_inputs[] = {
303 {
304 .name = "default",
305 .type = AVMEDIA_TYPE_VIDEO,
306 .filter_frame = filter_frame,
307 .config_props = config_props,
308 },
309};
310
312 .p.name = "sab",
313 .p.description = NULL_IF_CONFIG_SMALL("Apply shape adaptive blur."),
314 .p.priv_class = &sab_class,
316 .priv_size = sizeof(SabContext),
317 .init = init,
318 .uninit = uninit,
322};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
const FFFilter ff_vf_sab
Definition vf_sab.c:311
static AVFormatContext * ctx
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition avfilter.h:196
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
void sws_freeVec(SwsVector *a)
Definition utils.c:2146
SwsVector * sws_getGaussianVec(double variance, double quality)
Return a normalized Gaussian curve used to filter stuff quality = 3 is high quality,...
Definition utils.c:1973
int attribute_align_arg sws_scale(SwsContext *sws, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[])
swscale wrapper, so we don't need to export the SwsContext.
Definition swscale.c:1626
SwsContext * sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param)
Allocate and return an SwsContext.
Definition utils.c:1919
void sws_freeContext(SwsContext *swsContext)
Free the swscaler context swsContext.
Definition utils.c:2250
@ SWS_POINT
nearest neighbor
Definition swscale.h:201
int index
Definition gxfenc.c:90
const pixel * src2
static av_cold void uninit(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FILTER_PIXFMTS_ARRAY(array)
Definition filters.h:244
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static av_always_inline av_const int avpriv_mirror(int x, int w)
Definition internal.h:134
static enum AVPixelFormat pix_fmts[]
Definition libkvazaar.c:296
const char * desc
Definition libsvtav1.c:83
uint8_t w
Definition llvidencdsp.c:39
#define FFALIGN(x, a)
Definition macros.h:78
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition pixfmt.h:79
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition pixfmt.h:80
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
static int config_props(AVBitStreamFilterLink *link)
Definition source.c:181
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
void * priv
private data for use by the filter
Definition avfilter.h:288
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition frame.h:517
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
int pre_filter_linesize
Definition vf_sab.c:42
float quality
Definition vf_sab.c:39
float pre_filter_radius
Definition vf_sab.c:37
int dist_width
Definition vf_sab.c:43
uint8_t * pre_filter_buf
Definition vf_sab.c:41
struct SwsContext * pre_filter_context
Definition vf_sab.c:40
int radius
Definition boxblur.h:32
int dist_linesize
Definition vf_sab.c:44
float strength
Definition vf_sab.c:38
int color_diff_coeff[COLOR_DIFF_COEFF_SIZE]
Definition vf_sab.c:47
int * dist_coeff
Definition vf_sab.c:45
unsigned int sws_flags
Definition vf_sab.c:56
int vsub
Definition vf_sab.c:55
int hsub
Definition vf_sab.c:54
FilterParam chroma
Definition vf_sab.c:53
FilterParam luma
Definition vf_sab.c:52
Main external API structure.
Definition swscale.h:227
SwsVector * chrV
Definition swscale.h:488
SwsVector * lumH
Definition swscale.h:485
SwsVector * lumV
Definition swscale.h:486
SwsVector * chrH
Definition swscale.h:487
double * coeff
pointer to the list of coefficients
Definition swscale.h:479
int length
number of coefficients in the vector
Definition swscale.h:480
external API header
#define av_malloc_array(a, b)
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
#define NB_PLANES
Definition vf_geq.c:41
av_frame_free & inpic
Definition vf_mcdeint.c:297
static void blur(uint8_t *dst, const int dst_linesize, const uint8_t *src, const int src_linesize, const int w, const int h, FilterParam *fp)
Definition vf_sab.c:218
#define RADIUS_MAX
Definition vf_sab.c:69
#define STRENGTH_MAX
Definition vf_sab.c:75
static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
Definition vf_sab.c:276
#define PRE_FILTER_RADIUS_MAX
Definition vf_sab.c:72
#define PRE_FILTER_RADIUS_MIN
Definition vf_sab.c:71
#define COLOR_DIFF_COEFF_SIZE
Definition vf_sab.c:46
#define RADIUS_MIN
Definition vf_sab.c:68
#define UPDATE_FACTOR
static void close_filter_param(FilterParam *f)
Definition vf_sab.c:125
static int config_props(AVFilterLink *inlink)
Definition vf_sab.c:195
#define STRENGTH_MIN
Definition vf_sab.c:74
static av_cold void uninit(AVFilterContext *ctx)
Definition vf_sab.c:135
static int open_filter_param(FilterParam *f, int width, int height, unsigned int sws_flags)
Definition vf_sab.c:143
#define OFFSET(x)
Definition vf_sab.c:77
static const AVOption sab_options[]
Definition vf_sab.c:80
static const AVFilterPad sab_inputs[]
Definition vf_sab.c:302
static av_always_inline void chroma(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, int column, int mirror, int jobnr, int nb_jobs)
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition video.c:37
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89