FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <stdio.h>
27 
28 #include "libavutil/imgutils.h"
29 #include "libavutil/internal.h"
30 #include "avfilter.h"
31 #include "formats.h"
32 #include "internal.h"
33 #include "video.h"
34 
35 typedef struct {
36  int x1, y1, x2, y2;
37  int limit;
38  int round;
40  int frame_nb;
41  int max_pixsteps[4];
43 
45 {
46  static const enum AVPixelFormat pix_fmts[] = {
53  };
54 
56  return 0;
57 }
58 
59 static int checkline(void *ctx, const unsigned char *src, int stride, int len, int bpp)
60 {
61  int total = 0;
62  int div = len;
63 
64  switch (bpp) {
65  case 1:
66  while (--len >= 0) {
67  total += src[0];
68  src += stride;
69  }
70  break;
71  case 3:
72  case 4:
73  while (--len >= 0) {
74  total += src[0] + src[1] + src[2];
75  src += stride;
76  }
77  div *= 3;
78  break;
79  }
80  total /= div;
81 
82  av_log(ctx, AV_LOG_DEBUG, "total:%d\n", total);
83  return total;
84 }
85 
86 static av_cold int init(AVFilterContext *ctx, const char *args)
87 {
88  CropDetectContext *cd = ctx->priv;
89 
90  cd->limit = 24;
91  cd->round = 0;
92  cd->reset_count = 0;
93  cd->frame_nb = -2;
94 
95  if (args)
96  sscanf(args, "%d:%d:%d", &cd->limit, &cd->round, &cd->reset_count);
97 
98  av_log(ctx, AV_LOG_VERBOSE, "limit:%d round:%d reset_count:%d\n",
99  cd->limit, cd->round, cd->reset_count);
100 
101  return 0;
102 }
103 
104 static int config_input(AVFilterLink *inlink)
105 {
106  AVFilterContext *ctx = inlink->dst;
107  CropDetectContext *cd = ctx->priv;
108 
110  av_pix_fmt_desc_get(inlink->format));
111 
112  cd->x1 = inlink->w - 1;
113  cd->y1 = inlink->h - 1;
114  cd->x2 = 0;
115  cd->y2 = 0;
116 
117  return 0;
118 }
119 
121 {
122  AVFilterContext *ctx = inlink->dst;
123  CropDetectContext *cd = ctx->priv;
124  int bpp = cd->max_pixsteps[0];
125  int w, h, x, y, shrink_by;
126 
127  // ignore first 2 frames - they may be empty
128  if (++cd->frame_nb > 0) {
129  // Reset the crop area every reset_count frames, if reset_count is > 0
130  if (cd->reset_count > 0 && cd->frame_nb > cd->reset_count) {
131  cd->x1 = frame->video->w-1;
132  cd->y1 = frame->video->h-1;
133  cd->x2 = 0;
134  cd->y2 = 0;
135  cd->frame_nb = 1;
136  }
137 
138  for (y = 0; y < cd->y1; y++) {
139  if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->video->w, bpp) > cd->limit) {
140  cd->y1 = y;
141  break;
142  }
143  }
144 
145  for (y = frame->video->h-1; y > cd->y2; y--) {
146  if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->video->w, bpp) > cd->limit) {
147  cd->y2 = y;
148  break;
149  }
150  }
151 
152  for (y = 0; y < cd->x1; y++) {
153  if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->video->h, bpp) > cd->limit) {
154  cd->x1 = y;
155  break;
156  }
157  }
158 
159  for (y = frame->video->w-1; y > cd->x2; y--) {
160  if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->video->h, bpp) > cd->limit) {
161  cd->x2 = y;
162  break;
163  }
164  }
165 
166  // round x and y (up), important for yuv colorspaces
167  // make sure they stay rounded!
168  x = (cd->x1+1) & ~1;
169  y = (cd->y1+1) & ~1;
170 
171  w = cd->x2 - x + 1;
172  h = cd->y2 - y + 1;
173 
174  // w and h must be divisible by 2 as well because of yuv
175  // colorspace problems.
176  if (cd->round <= 1)
177  cd->round = 16;
178  if (cd->round % 2)
179  cd->round *= 2;
180 
181  shrink_by = w % cd->round;
182  w -= shrink_by;
183  x += (shrink_by/2 + 1) & ~1;
184 
185  shrink_by = h % cd->round;
186  h -= shrink_by;
187  y += (shrink_by/2 + 1) & ~1;
188 
189  av_log(ctx, AV_LOG_INFO,
190  "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pos:%"PRId64" pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
191  cd->x1, cd->x2, cd->y1, cd->y2, w, h, x, y, frame->pos, frame->pts,
192  frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base),
193  w, h, x, y);
194  }
195 
196  return ff_filter_frame(inlink->dst->outputs[0], frame);
197 }
198 
200  {
201  .name = "default",
202  .type = AVMEDIA_TYPE_VIDEO,
203  .config_props = config_input,
204  .get_video_buffer = ff_null_get_video_buffer,
205  .filter_frame = filter_frame,
206  },
207  { NULL }
208 };
209 
211  {
212  .name = "default",
213  .type = AVMEDIA_TYPE_VIDEO
214  },
215  { NULL }
216 };
217 
219  .name = "cropdetect",
220  .description = NULL_IF_CONFIG_SMALL("Auto-detect crop size."),
221 
222  .priv_size = sizeof(CropDetectContext),
223  .init = init,
224 
226 
227  .inputs = avfilter_vf_cropdetect_inputs,
228 
229  .outputs = avfilter_vf_cropdetect_outputs,
230 };