2 * Copyright (c) 2002 A'rpi
3 * This file is part of Libav.
5 * Libav 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.
10 * Libav 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.
15 * You should have received a copy of the GNU General Public License along
16 * with Libav; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * border detection filter
23 * Ported from MPlayer libmpcodecs/vf_cropdetect.c.
28 #include "libavutil/imgutils.h"
29 #include "libavutil/internal.h"
44 static int query_formats(AVFilterContext
*ctx
)
46 static const enum AVPixelFormat pix_fmts
[] = {
47 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUVJ420P
,
48 AV_PIX_FMT_YUV422P
, AV_PIX_FMT_YUVJ422P
,
49 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUVJ444P
,
50 AV_PIX_FMT_YUV411P
, AV_PIX_FMT_GRAY8
,
51 AV_PIX_FMT_NV12
, AV_PIX_FMT_NV21
,
55 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
59 static int checkline(void *ctx
, const unsigned char *src
, int stride
, int len
, int bpp
)
74 total
+= src
[0] + src
[1] + src
[2];
82 av_log(ctx
, AV_LOG_DEBUG
, "total:%d\n", total
);
86 static av_cold
int init(AVFilterContext
*ctx
, const char *args
)
88 CropDetectContext
*cd
= ctx
->priv
;
96 sscanf(args
, "%d:%d:%d", &cd
->limit
, &cd
->round
, &cd
->reset_count
);
98 av_log(ctx
, AV_LOG_VERBOSE
, "limit:%d round:%d reset_count:%d\n",
99 cd
->limit
, cd
->round
, cd
->reset_count
);
104 static int config_input(AVFilterLink
*inlink
)
106 AVFilterContext
*ctx
= inlink
->dst
;
107 CropDetectContext
*cd
= ctx
->priv
;
109 av_image_fill_max_pixsteps(cd
->max_pixsteps
, NULL
,
110 av_pix_fmt_desc_get(inlink
->format
));
112 cd
->x1
= inlink
->w
- 1;
113 cd
->y1
= inlink
->h
- 1;
120 static int filter_frame(AVFilterLink
*inlink
, AVFilterBufferRef
*frame
)
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
;
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;
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
) {
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
) {
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
) {
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
) {
166 // round x and y (up), important for yuv colorspaces
167 // make sure they stay rounded!
174 // w and h must be divisible by 2 as well because of yuv
175 // colorspace problems.
181 shrink_by
= w
% cd
->round
;
183 x
+= (shrink_by
/2 + 1) & ~1;
185 shrink_by
= h
% cd
->round
;
187 y
+= (shrink_by
/2 + 1) & ~1;
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
),
196 return ff_filter_frame(inlink
->dst
->outputs
[0], frame
);
199 static const AVFilterPad avfilter_vf_cropdetect_inputs
[] = {
202 .type
= AVMEDIA_TYPE_VIDEO
,
203 .config_props
= config_input
,
204 .get_video_buffer
= ff_null_get_video_buffer
,
205 .filter_frame
= filter_frame
,
210 static const AVFilterPad avfilter_vf_cropdetect_outputs
[] = {
213 .type
= AVMEDIA_TYPE_VIDEO
218 AVFilter avfilter_vf_cropdetect
= {
219 .name
= "cropdetect",
220 .description
= NULL_IF_CONFIG_SMALL("Auto-detect crop size."),
222 .priv_size
= sizeof(CropDetectContext
),
225 .query_formats
= query_formats
,
227 .inputs
= avfilter_vf_cropdetect_inputs
,
229 .outputs
= avfilter_vf_cropdetect_outputs
,