FFmpeg  4.4.6
vf_cropdetect.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2002 A'rpi
3  * This file is part of FFmpeg.
4  *
5  * FFmpeg is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 /**
21  * @file
22  * border detection filter
23  * Ported from MPlayer libmpcodecs/vf_cropdetect.c.
24  */
25 
26 #include "libavutil/imgutils.h"
27 #include "libavutil/internal.h"
28 #include "libavutil/opt.h"
29 
30 #include "avfilter.h"
31 #include "formats.h"
32 #include "internal.h"
33 #include "video.h"
34 
35 typedef struct CropDetectContext {
36  const AVClass *class;
37  int x1, y1, x2, y2;
38  float limit;
39  int round;
40  int skip;
42  int frame_nb;
43  int max_pixsteps[4];
46 
48 {
49  static const enum AVPixelFormat pix_fmts[] = {
64  };
65 
67  if (!fmts_list)
68  return AVERROR(ENOMEM);
69  return ff_set_common_formats(ctx, fmts_list);
70 }
71 
72 static int checkline(void *ctx, const unsigned char *src, int stride, int len, int bpp)
73 {
74  int total = 0;
75  int div = len;
76  const uint16_t *src16 = (const uint16_t *)src;
77 
78  switch (bpp) {
79  case 1:
80  while (len >= 8) {
81  total += src[ 0] + src[ stride] + src[2*stride] + src[3*stride]
82  + src[4*stride] + src[5*stride] + src[6*stride] + src[7*stride];
83  src += 8*stride;
84  len -= 8;
85  }
86  while (--len >= 0) {
87  total += src[0];
88  src += stride;
89  }
90  break;
91  case 2:
92  stride >>= 1;
93  while (len >= 8) {
94  total += src16[ 0] + src16[ stride] + src16[2*stride] + src16[3*stride]
95  + src16[4*stride] + src16[5*stride] + src16[6*stride] + src16[7*stride];
96  src16 += 8*stride;
97  len -= 8;
98  }
99  while (--len >= 0) {
100  total += src16[0];
101  src16 += stride;
102  }
103  break;
104  case 3:
105  case 4:
106  while (len >= 4) {
107  total += src[0] + src[1 ] + src[2 ]
108  + src[ stride] + src[1+ stride] + src[2+ stride]
109  + src[2*stride] + src[1+2*stride] + src[2+2*stride]
110  + src[3*stride] + src[1+3*stride] + src[2+3*stride];
111  src += 4*stride;
112  len -= 4;
113  }
114  while (--len >= 0) {
115  total += src[0] + src[1] + src[2];
116  src += stride;
117  }
118  div *= 3;
119  break;
120  }
121  total /= div;
122 
123  av_log(ctx, AV_LOG_DEBUG, "total:%d\n", total);
124  return total;
125 }
126 
128 {
129  CropDetectContext *s = ctx->priv;
130 
131  s->frame_nb = -1 * s->skip;
132 
133  av_log(ctx, AV_LOG_VERBOSE, "limit:%f round:%d skip:%d reset_count:%d\n",
134  s->limit, s->round, s->skip, s->reset_count);
135 
136  return 0;
137 }
138 
139 static int config_input(AVFilterLink *inlink)
140 {
141  AVFilterContext *ctx = inlink->dst;
142  CropDetectContext *s = ctx->priv;
144 
145  av_image_fill_max_pixsteps(s->max_pixsteps, NULL, desc);
146 
147  if (s->limit < 1.0)
148  s->limit *= (1 << desc->comp[0].depth) - 1;
149 
150  s->x1 = inlink->w - 1;
151  s->y1 = inlink->h - 1;
152  s->x2 = 0;
153  s->y2 = 0;
154 
155  return 0;
156 }
157 
158 #define SET_META(key, value) \
159  av_dict_set_int(metadata, key, value, 0)
160 
161 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
162 {
163  AVFilterContext *ctx = inlink->dst;
164  CropDetectContext *s = ctx->priv;
165  int bpp = s->max_pixsteps[0];
166  int w, h, x, y, shrink_by;
167  AVDictionary **metadata;
168  int outliers, last_y;
169  int limit = lrint(s->limit);
170 
171  // ignore first s->skip frames
172  if (++s->frame_nb > 0) {
173  metadata = &frame->metadata;
174 
175  // Reset the crop area every reset_count frames, if reset_count is > 0
176  if (s->reset_count > 0 && s->frame_nb > s->reset_count) {
177  s->x1 = frame->width - 1;
178  s->y1 = frame->height - 1;
179  s->x2 = 0;
180  s->y2 = 0;
181  s->frame_nb = 1;
182  }
183 
184 #define FIND(DST, FROM, NOEND, INC, STEP0, STEP1, LEN) \
185  outliers = 0;\
186  for (last_y = y = FROM; NOEND; y = y INC) {\
187  if (checkline(ctx, frame->data[0] + STEP0 * y, STEP1, LEN, bpp) > limit) {\
188  if (++outliers > s->max_outliers) { \
189  DST = last_y;\
190  break;\
191  }\
192  } else\
193  last_y = y INC;\
194  }
195 
196  FIND(s->y1, 0, y < s->y1, +1, frame->linesize[0], bpp, frame->width);
197  FIND(s->y2, frame->height - 1, y > FFMAX(s->y2, s->y1), -1, frame->linesize[0], bpp, frame->width);
198  FIND(s->x1, 0, y < s->x1, +1, bpp, frame->linesize[0], frame->height);
199  FIND(s->x2, frame->width - 1, y > FFMAX(s->x2, s->x1), -1, bpp, frame->linesize[0], frame->height);
200 
201 
202  // round x and y (up), important for yuv colorspaces
203  // make sure they stay rounded!
204  x = (s->x1+1) & ~1;
205  y = (s->y1+1) & ~1;
206 
207  w = s->x2 - x + 1;
208  h = s->y2 - y + 1;
209 
210  // w and h must be divisible by 2 as well because of yuv
211  // colorspace problems.
212  if (s->round <= 1)
213  s->round = 16;
214  if (s->round % 2)
215  s->round *= 2;
216 
217  shrink_by = w % s->round;
218  w -= shrink_by;
219  x += (shrink_by/2 + 1) & ~1;
220 
221  shrink_by = h % s->round;
222  h -= shrink_by;
223  y += (shrink_by/2 + 1) & ~1;
224 
225  SET_META("lavfi.cropdetect.x1", s->x1);
226  SET_META("lavfi.cropdetect.x2", s->x2);
227  SET_META("lavfi.cropdetect.y1", s->y1);
228  SET_META("lavfi.cropdetect.y2", s->y2);
229  SET_META("lavfi.cropdetect.w", w);
230  SET_META("lavfi.cropdetect.h", h);
231  SET_META("lavfi.cropdetect.x", x);
232  SET_META("lavfi.cropdetect.y", y);
233 
235  "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
236  s->x1, s->x2, s->y1, s->y2, w, h, x, y, frame->pts,
237  frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base),
238  w, h, x, y);
239  }
240 
241  return ff_filter_frame(inlink->dst->outputs[0], frame);
242 }
243 
244 #define OFFSET(x) offsetof(CropDetectContext, x)
245 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
246 
247 static const AVOption cropdetect_options[] = {
248  { "limit", "Threshold below which the pixel is considered black", OFFSET(limit), AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, FLAGS },
249  { "round", "Value by which the width/height should be divisible", OFFSET(round), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, FLAGS },
250  { "reset", "Recalculate the crop area after this many frames", OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
251  { "skip", "Number of initial frames to skip", OFFSET(skip), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, FLAGS },
252  { "reset_count", "Recalculate the crop area after this many frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, INT_MAX, FLAGS },
253  { "max_outliers", "Threshold count of outliers", OFFSET(max_outliers),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
254  { NULL }
255 };
256 
258 
260  {
261  .name = "default",
262  .type = AVMEDIA_TYPE_VIDEO,
263  .config_props = config_input,
264  .filter_frame = filter_frame,
265  },
266  { NULL }
267 };
268 
270  {
271  .name = "default",
272  .type = AVMEDIA_TYPE_VIDEO
273  },
274  { NULL }
275 };
276 
278  .name = "cropdetect",
279  .description = NULL_IF_CONFIG_SMALL("Auto-detect crop size."),
280  .priv_size = sizeof(CropDetectContext),
281  .priv_class = &cropdetect_class,
282  .init = init,
287 };
static const AVFilterPad inputs[]
Definition: af_acontrast.c:193
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
#define av_cold
Definition: attributes.h:88
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1096
Main libavfilter public API header.
#define flags(name, subs,...)
Definition: cbs_av1.c:572
#define s(width, name)
Definition: cbs_vp9.c:257
#define FFMAX(a, b)
Definition: common.h:103
#define NULL
Definition: coverity.c:32
static AVFrame * frame
int 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:587
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:286
@ AV_OPT_TYPE_INT
Definition: opt.h:225
@ AV_OPT_TYPE_FLOAT
Definition: opt.h:228
#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:126
#define AVERROR(e)
Definition: error.h:43
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], const AVPixFmtDescriptor *pixdesc)
Compute the max pixel step for each plane of an image with a format described by pixdesc.
Definition: imgutils.c:35
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
misc image utilities
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:309
static av_always_inline av_const double round(double x)
Definition: libm.h:444
const char * desc
Definition: libsvtav1.c:79
uint8_t w
Definition: llviddspenc.c:39
int stride
Definition: mace.c:144
AVOptions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2573
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:410
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:406
#define AV_PIX_FMT_YUV444P9
Definition: pixfmt.h:398
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:399
#define AV_PIX_FMT_YUV422P9
Definition: pixfmt.h:397
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:403
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:404
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:400
#define AV_PIX_FMT_YUV420P9
Definition: pixfmt.h:396
#define AV_PIX_FMT_YUV420P14
Definition: pixfmt.h:407
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:89
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
@ AV_PIX_FMT_NV21
as above, but U and V bytes are swapped
Definition: pixfmt.h:90
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition: pixfmt.h:79
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition: pixfmt.h:80
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition: pixfmt.h:78
#define AV_PIX_FMT_YUV422P14
Definition: pixfmt.h:408
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:411
#define AV_PIX_FMT_YUV444P14
Definition: pixfmt.h:409
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:412
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:402
Describe the class of an AVClass context structure.
Definition: log.h:67
An instance of a filter.
Definition: avfilter.h:341
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:353
A list of supported formats for one end of a filter link.
Definition: formats.h:65
A filter pad used for either input or output.
Definition: internal.h:54
const char * name
Pad name.
Definition: internal.h:60
Filter definition.
Definition: avfilter.h:145
const char * name
Filter name.
Definition: avfilter.h:149
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:411
int width
Definition: frame.h:376
int height
Definition: frame.h:376
AVDictionary * metadata
metadata.
Definition: frame.h:604
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:349
AVOption.
Definition: opt.h:248
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
#define lrint
Definition: tablegen.h:53
#define av_log(a,...)
#define src
Definition: vp8dsp.c:255
AVFormatContext * ctx
Definition: movenc.c:48
static int checkline(void *ctx, const unsigned char *src, int stride, int len, int bpp)
Definition: vf_cropdetect.c:72
#define FIND(DST, FROM, NOEND, INC, STEP0, STEP1, LEN)
AVFilter ff_vf_cropdetect
static const AVOption cropdetect_options[]
static int query_formats(AVFilterContext *ctx)
Definition: vf_cropdetect.c:47
static int config_input(AVFilterLink *inlink)
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
#define FLAGS
static const AVFilterPad avfilter_vf_cropdetect_inputs[]
static av_cold int init(AVFilterContext *ctx)
#define SET_META(key, value)
#define OFFSET(x)
AVFILTER_DEFINE_CLASS(cropdetect)
static const AVFilterPad avfilter_vf_cropdetect_outputs[]
int len