2 * copyright (c) 2007 Bobby Bingham
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavutil/pixdesc.h"
30 int x
; ///< x offset of the non-cropped area with respect to the input area
31 int y
; ///< y offset of the non-cropped area with respect to the input area
32 int w
; ///< width of the cropped area
33 int h
; ///< height of the cropped area
35 int max_step
[4]; ///< max pixel step for each plane, expressed as a number of bytes
36 int hsub
, vsub
; ///< chroma subsampling
39 static int query_formats(AVFilterContext
*ctx
)
41 static const enum PixelFormat pix_fmts
[] = {
42 PIX_FMT_RGB48BE
, PIX_FMT_RGB48LE
,
43 PIX_FMT_ARGB
, PIX_FMT_RGBA
,
44 PIX_FMT_ABGR
, PIX_FMT_BGRA
,
45 PIX_FMT_RGB24
, PIX_FMT_BGR24
,
46 PIX_FMT_RGB565BE
, PIX_FMT_RGB565LE
,
47 PIX_FMT_RGB555BE
, PIX_FMT_RGB555LE
,
48 PIX_FMT_BGR565BE
, PIX_FMT_BGR565LE
,
49 PIX_FMT_BGR555BE
, PIX_FMT_BGR555LE
,
50 PIX_FMT_GRAY16BE
, PIX_FMT_GRAY16LE
,
51 PIX_FMT_YUV420P16LE
, PIX_FMT_YUV420P16BE
,
52 PIX_FMT_YUV422P16LE
, PIX_FMT_YUV422P16BE
,
53 PIX_FMT_YUV444P16LE
, PIX_FMT_YUV444P16BE
,
54 PIX_FMT_YUV444P
, PIX_FMT_YUV422P
,
55 PIX_FMT_YUV420P
, PIX_FMT_YUV411P
,
56 PIX_FMT_YUV410P
, PIX_FMT_YUV440P
,
57 PIX_FMT_YUVJ444P
, PIX_FMT_YUVJ422P
,
58 PIX_FMT_YUVJ420P
, PIX_FMT_YUVJ440P
,
60 PIX_FMT_RGB8
, PIX_FMT_BGR8
,
61 PIX_FMT_RGB4_BYTE
, PIX_FMT_BGR4_BYTE
,
62 PIX_FMT_PAL8
, PIX_FMT_GRAY8
,
66 avfilter_set_common_formats(ctx
, avfilter_make_format_list(pix_fmts
));
71 static av_cold
int init(AVFilterContext
*ctx
, const char *args
, void *opaque
)
73 CropContext
*crop
= ctx
->priv
;
76 sscanf(args
, "%d:%d:%d:%d", &crop
->x
, &crop
->y
, &crop
->w
, &crop
->h
);
81 static int config_input(AVFilterLink
*link
)
83 AVFilterContext
*ctx
= link
->dst
;
84 CropContext
*crop
= ctx
->priv
;
85 const AVPixFmtDescriptor
*pix_desc
= &av_pix_fmt_descriptors
[link
->format
];
88 memset(crop
->max_step
, 0, sizeof(crop
->max_step
));
89 for (i
= 0; i
< 4; i
++) {
90 const AVComponentDescriptor
*comp
= &(pix_desc
->comp
[i
]);
91 if ((comp
->step_minus1
+1) > crop
->max_step
[comp
->plane
])
92 crop
->max_step
[comp
->plane
] = comp
->step_minus1
+1;
95 crop
->hsub
= av_pix_fmt_descriptors
[link
->format
].log2_chroma_w
;
96 crop
->vsub
= av_pix_fmt_descriptors
[link
->format
].log2_chroma_h
;
99 crop
->w
= link
->w
- crop
->x
;
101 crop
->h
= link
->h
- crop
->y
;
103 crop
->x
&= ~((1 << crop
->hsub
) - 1);
104 crop
->y
&= ~((1 << crop
->vsub
) - 1);
106 av_log(link
->dst
, AV_LOG_INFO
, "x:%d y:%d w:%d h:%d\n",
107 crop
->x
, crop
->y
, crop
->w
, crop
->h
);
109 if (crop
->x
< 0 || crop
->y
< 0 ||
110 crop
->w
<= 0 || crop
->h
<= 0 ||
111 (unsigned)crop
->x
+ (unsigned)crop
->w
> link
->w
||
112 (unsigned)crop
->y
+ (unsigned)crop
->h
> link
->h
) {
113 av_log(ctx
, AV_LOG_ERROR
,
114 "Output area %d:%d:%d:%d not within the input area 0:0:%d:%d or zero-sized\n",
115 crop
->x
, crop
->y
, crop
->w
, crop
->h
, link
->w
, link
->h
);
122 static int config_output(AVFilterLink
*link
)
124 CropContext
*crop
= link
->src
->priv
;
132 static void start_frame(AVFilterLink
*link
, AVFilterPicRef
*picref
)
134 CropContext
*crop
= link
->dst
->priv
;
135 AVFilterPicRef
*ref2
= avfilter_ref_pic(picref
, ~0);
141 ref2
->data
[0] += crop
->y
* ref2
->linesize
[0];
142 ref2
->data
[0] += (crop
->x
* crop
->max_step
[0]);
144 if (!(av_pix_fmt_descriptors
[link
->format
].flags
& PIX_FMT_PAL
)) {
145 for (i
= 1; i
< 3; i
++) {
147 ref2
->data
[i
] += (crop
->y
>> crop
->vsub
) * ref2
->linesize
[i
];
148 ref2
->data
[i
] += (crop
->x
* crop
->max_step
[i
]) >> crop
->hsub
;
155 ref2
->data
[3] += crop
->y
* ref2
->linesize
[3];
156 ref2
->data
[3] += (crop
->x
* crop
->max_step
[3]);
159 avfilter_start_frame(link
->dst
->outputs
[0], ref2
);
162 static void draw_slice(AVFilterLink
*link
, int y
, int h
, int slice_dir
)
164 AVFilterContext
*ctx
= link
->dst
;
165 CropContext
*crop
= ctx
->priv
;
167 if (y
>= crop
->y
+ crop
->h
|| y
+ h
<= crop
->y
)
174 if (y
+ h
> crop
->y
+ crop
->h
)
175 h
= crop
->y
+ crop
->h
- y
;
177 avfilter_draw_slice(ctx
->outputs
[0], y
- crop
->y
, h
, slice_dir
);
180 AVFilter avfilter_vf_crop
= {
182 .description
= NULL_IF_CONFIG_SMALL("Crop the input video to x:y:width:height."),
184 .priv_size
= sizeof(CropContext
),
186 .query_formats
= query_formats
,
189 .inputs
= (AVFilterPad
[]) {{ .name
= "default",
190 .type
= AVMEDIA_TYPE_VIDEO
,
191 .start_frame
= start_frame
,
192 .draw_slice
= draw_slice
,
193 .get_video_buffer
= avfilter_null_get_video_buffer
,
194 .config_props
= config_input
, },
196 .outputs
= (AVFilterPad
[]) {{ .name
= "default",
197 .type
= AVMEDIA_TYPE_VIDEO
,
198 .config_props
= config_output
, },