vf_smartblur.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
3  * Copyright (c) 2012 Jeremy Tran
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 /**
23  * @file
24  * Apply a smartblur filter to the input video
25  * Ported from MPlayer libmpcodecs/vf_smartblur.c by Michael Niedermayer.
26  */
27 
28 #include "libavutil/opt.h"
29 #include "libavutil/pixdesc.h"
30 #include "libswscale/swscale.h"
31 
32 #include "avfilter.h"
33 #include "formats.h"
34 #include "internal.h"
35 
36 #define RADIUS_MIN 0.1
37 #define RADIUS_MAX 5.0
38 
39 #define STRENGTH_MIN -1.0
40 #define STRENGTH_MAX 1.0
41 
42 #define THRESHOLD_MIN -30
43 #define THRESHOLD_MAX 30
44 
45 typedef struct {
46  float radius;
47  float strength;
48  int threshold;
49  float quality;
51 } FilterParam;
52 
53 typedef struct {
54  const AVClass *class;
57  int hsub;
58  int vsub;
59  unsigned int sws_flags;
61 
62 #define OFFSET(x) offsetof(SmartblurContext, x)
63 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
64 
65 static const AVOption smartblur_options[] = {
66  { "luma_radius", "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
67  { "lr" , "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
68  { "luma_strength", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
69  { "ls", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
70  { "luma_threshold", "set luma threshold", OFFSET(luma.threshold), AV_OPT_TYPE_INT, {.i64=0}, THRESHOLD_MIN, THRESHOLD_MAX, .flags=FLAGS },
71  { "lt", "set luma threshold", OFFSET(luma.threshold), AV_OPT_TYPE_INT, {.i64=0}, THRESHOLD_MIN, THRESHOLD_MAX, .flags=FLAGS },
72 
73  { "chroma_radius", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
74  { "cr", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
75  { "chroma_strength", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
76  { "cs", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
77  { "chroma_threshold", "set chroma threshold", OFFSET(chroma.threshold), AV_OPT_TYPE_INT, {.i64=THRESHOLD_MIN-1}, THRESHOLD_MIN-1, THRESHOLD_MAX, .flags=FLAGS },
78  { "ct", "set chroma threshold", OFFSET(chroma.threshold), AV_OPT_TYPE_INT, {.i64=THRESHOLD_MIN-1}, THRESHOLD_MIN-1, THRESHOLD_MAX, .flags=FLAGS },
79 
80  { NULL }
81 };
82 
83 AVFILTER_DEFINE_CLASS(smartblur);
84 
85 static av_cold int init(AVFilterContext *ctx)
86 {
87  SmartblurContext *sblur = ctx->priv;
88 
89  /* make chroma default to luma values, if not explicitly set */
90  if (sblur->chroma.radius < RADIUS_MIN)
91  sblur->chroma.radius = sblur->luma.radius;
92  if (sblur->chroma.strength < STRENGTH_MIN)
93  sblur->chroma.strength = sblur->luma.strength;
94  if (sblur->chroma.threshold < THRESHOLD_MIN)
95  sblur->chroma.threshold = sblur->luma.threshold;
96 
97  sblur->luma.quality = sblur->chroma.quality = 3.0;
98  sblur->sws_flags = SWS_BICUBIC;
99 
100  av_log(ctx, AV_LOG_VERBOSE,
101  "luma_radius:%f luma_strength:%f luma_threshold:%d "
102  "chroma_radius:%f chroma_strength:%f chroma_threshold:%d\n",
103  sblur->luma.radius, sblur->luma.strength, sblur->luma.threshold,
104  sblur->chroma.radius, sblur->chroma.strength, sblur->chroma.threshold);
105 
106  return 0;
107 }
108 
109 static av_cold void uninit(AVFilterContext *ctx)
110 {
111  SmartblurContext *sblur = ctx->priv;
112 
115 }
116 
118 {
119  static const enum AVPixelFormat pix_fmts[] = {
125  };
126 
128 
129  return 0;
130 }
131 
132 static int alloc_sws_context(FilterParam *f, int width, int height, unsigned int flags)
133 {
134  SwsVector *vec;
135  SwsFilter sws_filter;
136 
137  vec = sws_getGaussianVec(f->radius, f->quality);
138 
139  if (!vec)
140  return AVERROR(EINVAL);
141 
142  sws_scaleVec(vec, f->strength);
143  vec->coeff[vec->length / 2] += 1.0 - f->strength;
144  sws_filter.lumH = sws_filter.lumV = vec;
145  sws_filter.chrH = sws_filter.chrV = NULL;
147  width, height, AV_PIX_FMT_GRAY8,
148  width, height, AV_PIX_FMT_GRAY8,
149  flags, &sws_filter, NULL, NULL);
150 
151  sws_freeVec(vec);
152 
153  if (!f->filter_context)
154  return AVERROR(EINVAL);
155 
156  return 0;
157 }
158 
159 static int config_props(AVFilterLink *inlink)
160 {
161  SmartblurContext *sblur = inlink->dst->priv;
162  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
163 
164  sblur->hsub = desc->log2_chroma_w;
165  sblur->vsub = desc->log2_chroma_h;
166 
167  alloc_sws_context(&sblur->luma, inlink->w, inlink->h, sblur->sws_flags);
168  alloc_sws_context(&sblur->chroma,
169  inlink->w >> sblur->hsub, inlink->h >> sblur->vsub,
170  sblur->sws_flags);
171 
172  return 0;
173 }
174 
175 static void blur(uint8_t *dst, const int dst_linesize,
176  const uint8_t *src, const int src_linesize,
177  const int w, const int h, const int threshold,
178  struct SwsContext *filter_context)
179 {
180  int x, y;
181  int orig, filtered;
182  int diff;
183  /* Declare arrays of 4 to get aligned data */
184  const uint8_t* const src_array[4] = {src};
185  uint8_t *dst_array[4] = {dst};
186  int src_linesize_array[4] = {src_linesize};
187  int dst_linesize_array[4] = {dst_linesize};
188 
189  sws_scale(filter_context, src_array, src_linesize_array,
190  0, h, dst_array, dst_linesize_array);
191 
192  if (threshold > 0) {
193  for (y = 0; y < h; ++y) {
194  for (x = 0; x < w; ++x) {
195  orig = src[x + y * src_linesize];
196  filtered = dst[x + y * dst_linesize];
197  diff = orig - filtered;
198 
199  if (diff > 0) {
200  if (diff > 2 * threshold)
201  dst[x + y * dst_linesize] = orig;
202  else if (diff > threshold)
203  /* add 'diff' and substract 'threshold' from 'filtered' */
204  dst[x + y * dst_linesize] = orig - threshold;
205  } else {
206  if (-diff > 2 * threshold)
207  dst[x + y * dst_linesize] = orig;
208  else if (-diff > threshold)
209  /* add 'diff' and 'threshold' to 'filtered' */
210  dst[x + y * dst_linesize] = orig + threshold;
211  }
212  }
213  }
214  } else if (threshold < 0) {
215  for (y = 0; y < h; ++y) {
216  for (x = 0; x < w; ++x) {
217  orig = src[x + y * src_linesize];
218  filtered = dst[x + y * dst_linesize];
219  diff = orig - filtered;
220 
221  if (diff > 0) {
222  if (diff <= -threshold)
223  dst[x + y * dst_linesize] = orig;
224  else if (diff <= -2 * threshold)
225  /* substract 'diff' and 'threshold' from 'orig' */
226  dst[x + y * dst_linesize] = filtered - threshold;
227  } else {
228  if (diff >= threshold)
229  dst[x + y * dst_linesize] = orig;
230  else if (diff >= 2 * threshold)
231  /* add 'threshold' and substract 'diff' from 'orig' */
232  dst[x + y * dst_linesize] = filtered + threshold;
233  }
234  }
235  }
236  }
237 }
238 
239 static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
240 {
241  SmartblurContext *sblur = inlink->dst->priv;
242  AVFilterLink *outlink = inlink->dst->outputs[0];
243  AVFrame *outpic;
244  int cw = inlink->w >> sblur->hsub;
245  int ch = inlink->h >> sblur->vsub;
246 
247  outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
248  if (!outpic) {
249  av_frame_free(&inpic);
250  return AVERROR(ENOMEM);
251  }
252  av_frame_copy_props(outpic, inpic);
253 
254  blur(outpic->data[0], outpic->linesize[0],
255  inpic->data[0], inpic->linesize[0],
256  inlink->w, inlink->h, sblur->luma.threshold,
257  sblur->luma.filter_context);
258 
259  if (inpic->data[2]) {
260  blur(outpic->data[1], outpic->linesize[1],
261  inpic->data[1], inpic->linesize[1],
262  cw, ch, sblur->chroma.threshold,
263  sblur->chroma.filter_context);
264  blur(outpic->data[2], outpic->linesize[2],
265  inpic->data[2], inpic->linesize[2],
266  cw, ch, sblur->chroma.threshold,
267  sblur->chroma.filter_context);
268  }
269 
270  av_frame_free(&inpic);
271  return ff_filter_frame(outlink, outpic);
272 }
273 
274 static const AVFilterPad smartblur_inputs[] = {
275  {
276  .name = "default",
277  .type = AVMEDIA_TYPE_VIDEO,
278  .filter_frame = filter_frame,
279  .config_props = config_props,
280  },
281  { NULL }
282 };
283 
284 static const AVFilterPad smartblur_outputs[] = {
285  {
286  .name = "default",
287  .type = AVMEDIA_TYPE_VIDEO,
288  },
289  { NULL }
290 };
291 
293  .name = "smartblur",
294  .description = NULL_IF_CONFIG_SMALL("Blur the input video without impacting the outlines."),
295 
296  .priv_size = sizeof(SmartblurContext),
297 
298  .init = init,
299  .uninit = uninit,
301  .inputs = smartblur_inputs,
302  .outputs = smartblur_outputs,
303  .priv_class = &smartblur_class,
304 };
#define OFFSET(x)
Definition: vf_smartblur.c:62
SwsVector * chrV
Definition: swscale.h:132
void sws_freeVec(SwsVector *a)
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:424
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:1778
float radius
Definition: vf_sab.c:46
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
AVOption.
Definition: opt.h:251
AVFILTER_DEFINE_CLASS(smartblur)
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:73
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:117
SwsVector * lumV
Definition: swscale.h:130
external API header
#define SWS_BICUBIC
Definition: swscale.h:60
Sinusoidal phase f
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:143
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:66
output residual component w
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:308
float strength
Definition: vf_sab.c:48
#define FLAGS
Definition: vf_smartblur.c:63
const char * name
Pad name.
FilterParam chroma
Definition: vf_smartblur.c:56
uint8_t
it can be given away to ff_start_frame *A reference passed to ff_filter_frame(or the deprecated ff_start_frame) is given away and must no longer be used.*A reference created with avfilter_ref_buffer belongs to the code that created it.*A reference obtained with ff_get_video_buffer or ff_get_audio_buffer belongs to the code that requested it.*A reference given as return value by the get_video_buffer or get_audio_buffer method is given away and must no longer be used.Link reference fields---------------------The AVFilterLink structure has a few AVFilterBufferRef fields.The cur_buf and out_buf were used with the deprecated start_frame/draw_slice/end_frame API and should no longer be used.src_buf
#define av_cold
Definition: attributes.h:78
int length
number of coefficients in the vector
Definition: swscale.h:124
AVOptions.
int attribute_align_arg sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[])
swscale wrapper, so we don&#39;t need to export the SwsContext.
Definition: swscale.c:798
#define THRESHOLD_MIN
Definition: vf_smartblur.c:42
void sws_scaleVec(SwsVector *a, double scalar)
Scale all the coefficients of a by the scalar value.
external API header
void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:545
unsigned int sws_flags
Definition: vf_smartblur.c:59
struct SwsContext * filter_context
Definition: vf_smartblur.c:50
A filter pad used for either input or output.
Discrete Time axis x
SwsVector * sws_getGaussianVec(double variance, double quality)
Return a normalized Gaussian curve used to filter stuff quality = 3 is high quality, lower is lower quality.
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:75
static int config_props(AVFilterLink *inlink)
Definition: vf_smartblur.c:159
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void * priv
private data for use by the filter
Definition: avfilter.h:545
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
SwsVector * lumH
Definition: swscale.h:129
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:72
static int alloc_sws_context(FilterParam *f, int width, int height, unsigned int flags)
Definition: vf_smartblur.c:132
#define AV_LOG_VERBOSE
Definition: log.h:157
#define STRENGTH_MAX
Definition: vf_smartblur.c:40
float quality
Definition: vf_sab.c:49
SwsVector * chrH
Definition: swscale.h:131
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But a word about quality
static int query_formats(AVFilterContext *ctx)
Definition: vf_smartblur.c:117
static const AVOption smartblur_options[]
Definition: vf_smartblur.c:65
#define diff(a, as, b, bs)
Definition: vf_phase.c:80
#define RADIUS_MIN
Definition: vf_smartblur.c:36
FilterParam luma
Definition: vf_smartblur.c:55
NULL
Definition: eval.c:55
double * coeff
pointer to the list of coefficients
Definition: swscale.h:123
static int width
Definition: tests/utils.c:158
AVS_Value src
Definition: avisynth_c.h:523
#define THRESHOLD_MAX
Definition: vf_smartblur.c:43
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
AVFilter avfilter_vf_smartblur
Definition: vf_smartblur.c:292
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:55
static const AVFilterPad smartblur_inputs[]
Definition: vf_smartblur.c:274
struct FilterParam FilterParam
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_smartblur.c:109
BYTE int const BYTE int int int height
Definition: avisynth_c.h:713
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:74
Describe the class of an AVClass context structure.
Definition: log.h:50
Filter definition.
Definition: avfilter.h:436
const char * name
filter name
Definition: avfilter.h:437
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:539
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
#define RADIUS_MAX
Definition: vf_smartblur.c:37
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:68
Y , 8bpp.
Definition: pixfmt.h:76
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:75
function y
Definition: D.m:1
static void blur(uint8_t *dst, const int dst_linesize, const uint8_t *src, const int src_linesize, const int w, const int h, const int threshold, struct SwsContext *filter_context)
Definition: vf_smartblur.c:175
struct SwsContext * sws_getCachedContext(struct SwsContext *context, int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param)
Check if context can be reused, otherwise reallocate a new one.
else dst[i][x+y *dst_stride[i]]
Definition: vf_mcdeint.c:160
#define STRENGTH_MIN
Definition: vf_smartblur.c:39
An instance of a filter.
Definition: avfilter.h:524
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:103
static const AVFilterPad smartblur_outputs[]
Definition: vf_smartblur.c:284
void sws_freeContext(struct SwsContext *swsContext)
Free the swscaler context swsContext.
static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
Definition: vf_smartblur.c:239
internal API functions
int flags
Flags passed by the user to select scaler algorithm, optimizations, subsampling, etc...
AVPixelFormat
Pixel format.
Definition: pixfmt.h:66
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
static av_cold int init(AVFilterContext *ctx)
Definition: vf_smartblur.c:85