FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavfilter
vf_crop.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2007 Bobby Bingham
3
*
4
* This file is part of FFmpeg.
5
*
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.
10
*
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.
15
*
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
19
*/
20
21
/**
22
* @file
23
* video crop filter
24
*/
25
26
#include <stdio.h>
27
28
#include "
avfilter.h
"
29
#include "
formats.h
"
30
#include "
internal.h
"
31
#include "
video.h
"
32
#include "
libavutil/eval.h
"
33
#include "
libavutil/avstring.h
"
34
#include "
libavutil/internal.h
"
35
#include "
libavutil/libm.h
"
36
#include "
libavutil/imgutils.h
"
37
#include "
libavutil/mathematics.h
"
38
#include "
libavutil/opt.h
"
39
40
static
const
char
*
const
var_names
[] = {
41
"in_w"
,
"iw"
,
///< width of the input video
42
"in_h"
,
"ih"
,
///< height of the input video
43
"out_w"
,
"ow"
,
///< width of the cropped video
44
"out_h"
,
"oh"
,
///< height of the cropped video
45
"a"
,
46
"sar"
,
47
"dar"
,
48
"hsub"
,
49
"vsub"
,
50
"x"
,
51
"y"
,
52
"n"
,
///< number of frame
53
"pos"
,
///< position in the file
54
"t"
,
///< timestamp expressed in seconds
55
NULL
56
};
57
58
enum
var_name
{
59
VAR_IN_W
,
VAR_IW
,
60
VAR_IN_H
,
VAR_IH
,
61
VAR_OUT_W
,
VAR_OW
,
62
VAR_OUT_H
,
VAR_OH
,
63
VAR_A
,
64
VAR_SAR
,
65
VAR_DAR
,
66
VAR_HSUB
,
67
VAR_VSUB
,
68
VAR_X
,
69
VAR_Y
,
70
VAR_N
,
71
VAR_POS
,
72
VAR_T
,
73
VAR_VARS_NB
74
};
75
76
typedef
struct
{
77
const
AVClass
*
class
;
78
int
x
;
///< x offset of the non-cropped area with respect to the input area
79
int
y
;
///< y offset of the non-cropped area with respect to the input area
80
int
w
;
///< width of the cropped area
81
int
h
;
///< height of the cropped area
82
83
AVRational
out_sar
;
///< output sample aspect ratio
84
int
keep_aspect
;
///< keep display aspect ratio when cropping
85
86
int
max_step[4];
///< max pixel step for each plane, expressed as a number of bytes
87
int
hsub,
vsub
;
///< chroma subsampling
88
char
*x_expr, *
y_expr
, *w_expr, *h_expr;
89
AVExpr
*x_pexpr, *
y_pexpr
;
/* parsed expressions for x and y */
90
double
var_values[
VAR_VARS_NB
];
91
}
CropContext
;
92
93
static
int
query_formats
(
AVFilterContext
*ctx)
94
{
95
static
const
enum
AVPixelFormat
pix_fmts[] = {
96
AV_PIX_FMT_RGB48BE
,
AV_PIX_FMT_RGB48LE
,
97
AV_PIX_FMT_BGR48BE
,
AV_PIX_FMT_BGR48LE
,
98
AV_PIX_FMT_ARGB
,
AV_PIX_FMT_RGBA
,
99
AV_PIX_FMT_ABGR
,
AV_PIX_FMT_BGRA
,
100
AV_PIX_FMT_RGB24
,
AV_PIX_FMT_BGR24
,
101
AV_PIX_FMT_RGB565BE
,
AV_PIX_FMT_RGB565LE
,
102
AV_PIX_FMT_RGB555BE
,
AV_PIX_FMT_RGB555LE
,
103
AV_PIX_FMT_BGR565BE
,
AV_PIX_FMT_BGR565LE
,
104
AV_PIX_FMT_BGR555BE
,
AV_PIX_FMT_BGR555LE
,
105
AV_PIX_FMT_GRAY16BE
,
AV_PIX_FMT_GRAY16LE
,
106
AV_PIX_FMT_YUV420P16LE
,
AV_PIX_FMT_YUV420P16BE
,
107
AV_PIX_FMT_YUV422P16LE
,
AV_PIX_FMT_YUV422P16BE
,
108
AV_PIX_FMT_YUV444P16LE
,
AV_PIX_FMT_YUV444P16BE
,
109
AV_PIX_FMT_YUV444P
,
AV_PIX_FMT_YUV422P
,
110
AV_PIX_FMT_YUV420P
,
AV_PIX_FMT_YUV411P
,
111
AV_PIX_FMT_YUV410P
,
AV_PIX_FMT_YUV440P
,
112
AV_PIX_FMT_YUVJ444P
,
AV_PIX_FMT_YUVJ422P
,
113
AV_PIX_FMT_YUVJ420P
,
AV_PIX_FMT_YUVJ440P
,
114
AV_PIX_FMT_YUVA420P
,
115
AV_PIX_FMT_RGB8
,
AV_PIX_FMT_BGR8
,
116
AV_PIX_FMT_RGB4_BYTE
,
AV_PIX_FMT_BGR4_BYTE
,
117
AV_PIX_FMT_PAL8
,
AV_PIX_FMT_GRAY8
,
118
AV_PIX_FMT_NONE
119
};
120
121
ff_set_common_formats
(ctx,
ff_make_format_list
(pix_fmts));
122
123
return
0;
124
}
125
126
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
127
{
128
CropContext
*
s
= ctx->
priv
;
129
130
av_expr_free
(s->
x_pexpr
);
131
s->
x_pexpr
=
NULL
;
132
av_expr_free
(s->
y_pexpr
);
133
s->
y_pexpr
=
NULL
;
134
}
135
136
static
inline
int
normalize_double
(
int
*
n
,
double
d)
137
{
138
int
ret
= 0;
139
140
if
(
isnan
(d)) {
141
ret =
AVERROR
(EINVAL);
142
}
else
if
(d > INT_MAX || d < INT_MIN) {
143
*n = d > INT_MAX ? INT_MAX : INT_MIN;
144
ret =
AVERROR
(EINVAL);
145
}
else
146
*n =
round
(d);
147
148
return
ret
;
149
}
150
151
static
int
config_input
(
AVFilterLink
*link)
152
{
153
AVFilterContext
*ctx = link->
dst
;
154
CropContext
*
s
= ctx->
priv
;
155
const
AVPixFmtDescriptor
*pix_desc =
av_pix_fmt_desc_get
(link->
format
);
156
int
ret
;
157
const
char
*expr;
158
double
res
;
159
160
s->
var_values
[
VAR_IN_W
] = s->
var_values
[
VAR_IW
] = ctx->
inputs
[0]->
w
;
161
s->
var_values
[
VAR_IN_H
] = s->
var_values
[
VAR_IH
] = ctx->
inputs
[0]->
h
;
162
s->
var_values
[
VAR_A
] = (float) link->
w
/ link->
h
;
163
s->
var_values
[
VAR_SAR
] = link->
sample_aspect_ratio
.
num
?
av_q2d
(link->
sample_aspect_ratio
) : 1;
164
s->
var_values
[
VAR_DAR
] = s->
var_values
[
VAR_A
] * s->
var_values
[
VAR_SAR
];
165
s->
var_values
[
VAR_HSUB
] = 1<<pix_desc->
log2_chroma_w
;
166
s->
var_values
[
VAR_VSUB
] = 1<<pix_desc->
log2_chroma_h
;
167
s->
var_values
[
VAR_X
] =
NAN
;
168
s->
var_values
[
VAR_Y
] =
NAN
;
169
s->
var_values
[
VAR_OUT_W
] = s->
var_values
[
VAR_OW
] =
NAN
;
170
s->
var_values
[
VAR_OUT_H
] = s->
var_values
[
VAR_OH
] =
NAN
;
171
s->
var_values
[
VAR_N
] = 0;
172
s->
var_values
[
VAR_T
] =
NAN
;
173
s->
var_values
[
VAR_POS
] =
NAN
;
174
175
av_image_fill_max_pixsteps
(s->
max_step
,
NULL
, pix_desc);
176
s->
hsub
= pix_desc->
log2_chroma_w
;
177
s->
vsub
= pix_desc->
log2_chroma_h
;
178
179
if
((ret =
av_expr_parse_and_eval
(&res, (expr = s->
w_expr
),
180
var_names
, s->
var_values
,
181
NULL
,
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
182
goto
fail_expr;
183
s->
var_values
[
VAR_OUT_W
] = s->
var_values
[
VAR_OW
] =
res
;
184
if
((ret =
av_expr_parse_and_eval
(&res, (expr = s->
h_expr
),
185
var_names
, s->
var_values
,
186
NULL
,
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
187
goto
fail_expr;
188
s->
var_values
[
VAR_OUT_H
] = s->
var_values
[
VAR_OH
] =
res
;
189
/* evaluate again ow as it may depend on oh */
190
if
((ret =
av_expr_parse_and_eval
(&res, (expr = s->
w_expr
),
191
var_names
, s->
var_values
,
192
NULL
,
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
193
goto
fail_expr;
194
195
s->
var_values
[
VAR_OUT_W
] = s->
var_values
[
VAR_OW
] =
res
;
196
if
(
normalize_double
(&s->
w
, s->
var_values
[
VAR_OUT_W
]) < 0 ||
197
normalize_double
(&s->
h
, s->
var_values
[
VAR_OUT_H
]) < 0) {
198
av_log
(ctx,
AV_LOG_ERROR
,
199
"Too big value or invalid expression for out_w/ow or out_h/oh. "
200
"Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n"
,
201
s->
w_expr
, s->
h_expr
);
202
return
AVERROR
(EINVAL);
203
}
204
s->
w
&= ~((1 << s->
hsub
) - 1);
205
s->
h
&= ~((1 << s->
vsub
) - 1);
206
207
av_expr_free
(s->
x_pexpr
);
208
av_expr_free
(s->
y_pexpr
);
209
s->
x_pexpr
= s->
y_pexpr
=
NULL
;
210
if
((ret =
av_expr_parse
(&s->
x_pexpr
, s->
x_expr
,
var_names
,
211
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0 ||
212
(ret =
av_expr_parse
(&s->
y_pexpr
, s->
y_expr
,
var_names
,
213
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
214
return
AVERROR
(EINVAL);
215
216
if
(s->
keep_aspect
) {
217
AVRational
dar =
av_mul_q
(link->
sample_aspect_ratio
,
218
(
AVRational
){ link->
w
, link->
h
});
219
av_reduce
(&s->
out_sar
.
num
, &s->
out_sar
.
den
,
220
dar.num * s->
h
, dar.den * s->
w
, INT_MAX);
221
}
else
222
s
->out_sar = link->sample_aspect_ratio;
223
224
av_log
(ctx,
AV_LOG_VERBOSE
,
"w:%d h:%d sar:%d/%d -> w:%d h:%d sar:%d/%d\n"
,
225
link->w, link->h, link->sample_aspect_ratio.num, link->sample_aspect_ratio.den,
226
s
->w,
s
->h,
s
->out_sar.num,
s
->out_sar.den);
227
228
if
(
s
->w <= 0 ||
s
->h <= 0 ||
229
s
->w > link->w ||
s
->h > link->h) {
230
av_log
(ctx,
AV_LOG_ERROR
,
231
"Invalid too big or non positive size for width '%d' or height '%d'\n"
,
232
s
->w,
s
->h);
233
return
AVERROR
(EINVAL);
234
}
235
236
/* set default, required in the case the first computed value for x/y is NAN */
237
s
->x = (link->w -
s
->w) / 2;
238
s
->y = (link->h -
s
->h) / 2;
239
s
->x &= ~((1 <<
s
->hsub) - 1);
240
s
->y &= ~((1 <<
s
->vsub) - 1);
241
return
0;
242
243
fail_expr:
244
av_log
(
NULL
,
AV_LOG_ERROR
,
"Error when evaluating the expression '%s'\n"
, expr);
245
return
ret
;
246
}
247
248
static
int
config_output
(
AVFilterLink
*link)
249
{
250
CropContext
*
s
= link->
src
->
priv
;
251
252
link->
w
= s->
w
;
253
link->
h
= s->
h
;
254
link->
sample_aspect_ratio
= s->
out_sar
;
255
256
return
0;
257
}
258
259
static
int
filter_frame
(
AVFilterLink
*link,
AVFrame
*
frame
)
260
{
261
AVFilterContext
*ctx = link->
dst
;
262
CropContext
*
s
= ctx->
priv
;
263
const
AVPixFmtDescriptor
*desc =
av_pix_fmt_desc_get
(link->
format
);
264
int
i;
265
266
frame->
width
= s->
w
;
267
frame->
height
= s->
h
;
268
269
s->
var_values
[
VAR_N
] = link->
frame_count
;
270
s->
var_values
[
VAR_T
] = frame->
pts
==
AV_NOPTS_VALUE
?
271
NAN
: frame->
pts
*
av_q2d
(link->
time_base
);
272
s->
var_values
[
VAR_POS
] =
av_frame_get_pkt_pos
(frame) == -1 ?
273
NAN
:
av_frame_get_pkt_pos
(frame);
274
s->
var_values
[
VAR_X
] =
av_expr_eval
(s->
x_pexpr
, s->
var_values
,
NULL
);
275
s->
var_values
[
VAR_Y
] =
av_expr_eval
(s->
y_pexpr
, s->
var_values
,
NULL
);
276
s->
var_values
[
VAR_X
] =
av_expr_eval
(s->
x_pexpr
, s->
var_values
,
NULL
);
277
278
normalize_double
(&s->
x
, s->
var_values
[
VAR_X
]);
279
normalize_double
(&s->
y
, s->
var_values
[
VAR_Y
]);
280
281
if
(s->
x
< 0)
282
s->
x
= 0;
283
if
(s->
y
< 0)
284
s->
y
= 0;
285
if
((
unsigned
)s->
x
+ (
unsigned
)s->
w
> link->
w
)
286
s->
x
= link->
w
- s->
w
;
287
if
((
unsigned
)s->
y
+ (
unsigned
)s->
h
> link->
h
)
288
s->
y
= link->
h
- s->
h
;
289
s->
x
&= ~((1 << s->
hsub
) - 1);
290
s->
y
&= ~((1 << s->
vsub
) - 1);
291
292
av_dlog
(ctx,
"n:%d t:%f pos:%f x:%d y:%d x+w:%d y+h:%d\n"
,
293
(
int
)s->
var_values
[
VAR_N
], s->
var_values
[
VAR_T
], s->
var_values
[
VAR_POS
],
294
s->
x
, s->
y
, s->
x
+s->
w
, s->
y
+s->
h
);
295
296
frame->
data
[0] += s->
y
* frame->
linesize
[0];
297
frame->
data
[0] += s->
x
* s->
max_step
[0];
298
299
if
(!(desc->
flags
&
AV_PIX_FMT_FLAG_PAL
|| desc->
flags
&
AV_PIX_FMT_FLAG_PSEUDOPAL
)) {
300
for
(i = 1; i < 3; i ++) {
301
if
(frame->
data
[i]) {
302
frame->
data
[i] += (s->
y
>> s->
vsub
) * frame->
linesize
[i];
303
frame->
data
[i] += (s->
x
* s->
max_step
[i]) >> s->
hsub
;
304
}
305
}
306
}
307
308
/* alpha plane */
309
if
(frame->
data
[3]) {
310
frame->
data
[3] += s->
y
* frame->
linesize
[3];
311
frame->
data
[3] += s->
x
* s->
max_step
[3];
312
}
313
314
return
ff_filter_frame
(link->
dst
->
outputs
[0], frame);
315
}
316
317
#define OFFSET(x) offsetof(CropContext, x)
318
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
319
320
static
const
AVOption
crop_options
[] = {
321
{
"out_w"
,
"set the width crop area expression"
,
OFFSET
(w_expr),
AV_OPT_TYPE_STRING
, {.str =
"iw"
}, CHAR_MIN, CHAR_MAX,
FLAGS
},
322
{
"w"
,
"set the width crop area expression"
,
OFFSET
(w_expr),
AV_OPT_TYPE_STRING
, {.str =
"iw"
}, CHAR_MIN, CHAR_MAX,
FLAGS
},
323
{
"out_h"
,
"set the height crop area expression"
,
OFFSET
(h_expr),
AV_OPT_TYPE_STRING
, {.str =
"ih"
}, CHAR_MIN, CHAR_MAX,
FLAGS
},
324
{
"h"
,
"set the height crop area expression"
,
OFFSET
(h_expr),
AV_OPT_TYPE_STRING
, {.str =
"ih"
}, CHAR_MIN, CHAR_MAX,
FLAGS
},
325
{
"x"
,
"set the x crop area expression"
,
OFFSET
(x_expr),
AV_OPT_TYPE_STRING
, {.str =
"(in_w-out_w)/2"
}, CHAR_MIN, CHAR_MAX,
FLAGS
},
326
{
"y"
,
"set the y crop area expression"
,
OFFSET
(y_expr),
AV_OPT_TYPE_STRING
, {.str =
"(in_h-out_h)/2"
}, CHAR_MIN, CHAR_MAX,
FLAGS
},
327
{
"keep_aspect"
,
"keep aspect ratio"
,
OFFSET
(keep_aspect),
AV_OPT_TYPE_INT
, {.i64=0}, 0, 1,
FLAGS
},
328
{
NULL
}
329
};
330
331
AVFILTER_DEFINE_CLASS
(crop);
332
333
static
const
AVFilterPad
avfilter_vf_crop_inputs
[] = {
334
{
335
.
name
=
"default"
,
336
.type =
AVMEDIA_TYPE_VIDEO
,
337
.filter_frame =
filter_frame
,
338
.get_video_buffer =
ff_null_get_video_buffer
,
339
.config_props =
config_input
,
340
},
341
{
NULL
}
342
};
343
344
static
const
AVFilterPad
avfilter_vf_crop_outputs
[] = {
345
{
346
.
name
=
"default"
,
347
.type =
AVMEDIA_TYPE_VIDEO
,
348
.config_props =
config_output
,
349
},
350
{
NULL
}
351
};
352
353
AVFilter
avfilter_vf_crop
= {
354
.
name
=
"crop"
,
355
.description =
NULL_IF_CONFIG_SMALL
(
"Crop the input video to width:height:x:y."
),
356
357
.priv_size =
sizeof
(
CropContext
),
358
.priv_class = &crop_class,
359
360
.
query_formats
=
query_formats
,
361
.
uninit
=
uninit
,
362
363
.
inputs
= avfilter_vf_crop_inputs,
364
.
outputs
= avfilter_vf_crop_outputs,
365
};
Generated on Fri May 24 2013 19:21:02 for FFmpeg by
1.8.2