Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
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 Libav.
5
*
6
* Libav 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
* Libav 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 Libav; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
26
/* #define DEBUG */
27
28
#include <stdio.h>
29
30
#include "
avfilter.h
"
31
#include "
formats.h
"
32
#include "
internal.h
"
33
#include "
video.h
"
34
#include "
libavutil/eval.h
"
35
#include "
libavutil/avstring.h
"
36
#include "
libavutil/internal.h
"
37
#include "
libavutil/libm.h
"
38
#include "
libavutil/imgutils.h
"
39
#include "
libavutil/mathematics.h
"
40
41
static
const
char
*
const
var_names
[] = {
42
"E"
,
43
"PHI"
,
44
"PI"
,
45
"in_w"
,
"iw"
,
46
"in_h"
,
"ih"
,
47
"out_w"
,
"ow"
,
48
"out_h"
,
"oh"
,
49
"x"
,
50
"y"
,
51
"n"
,
52
"pos"
,
53
"t"
,
54
NULL
55
};
56
57
enum
var_name
{
58
VAR_E
,
59
VAR_PHI
,
60
VAR_PI
,
61
VAR_IN_W
,
VAR_IW
,
62
VAR_IN_H
,
VAR_IH
,
63
VAR_OUT_W
,
VAR_OW
,
64
VAR_OUT_H
,
VAR_OH
,
65
VAR_X
,
66
VAR_Y
,
67
VAR_N
,
68
VAR_POS
,
69
VAR_T
,
70
VAR_VARS_NB
71
};
72
73
typedef
struct
{
74
int
x
;
75
int
y
;
76
int
w
;
77
int
h
;
78
79
int
max_step[4];
80
int
hsub,
vsub
;
81
char
x_expr[256], y_expr[256], ow_expr[256], oh_expr[256];
82
AVExpr
*x_pexpr, *
y_pexpr
;
/* parsed expressions for x and y */
83
double
var_values[
VAR_VARS_NB
];
84
}
CropContext
;
85
86
static
int
query_formats
(
AVFilterContext
*ctx)
87
{
88
static
const
enum
AVPixelFormat
pix_fmts[] = {
89
AV_PIX_FMT_RGB48BE
,
AV_PIX_FMT_RGB48LE
,
90
AV_PIX_FMT_BGR48BE
,
AV_PIX_FMT_BGR48LE
,
91
AV_PIX_FMT_ARGB
,
AV_PIX_FMT_RGBA
,
92
AV_PIX_FMT_ABGR
,
AV_PIX_FMT_BGRA
,
93
AV_PIX_FMT_RGB24
,
AV_PIX_FMT_BGR24
,
94
AV_PIX_FMT_RGB565BE
,
AV_PIX_FMT_RGB565LE
,
95
AV_PIX_FMT_RGB555BE
,
AV_PIX_FMT_RGB555LE
,
96
AV_PIX_FMT_BGR565BE
,
AV_PIX_FMT_BGR565LE
,
97
AV_PIX_FMT_BGR555BE
,
AV_PIX_FMT_BGR555LE
,
98
AV_PIX_FMT_GRAY16BE
,
AV_PIX_FMT_GRAY16LE
,
99
AV_PIX_FMT_YUV420P16LE
,
AV_PIX_FMT_YUV420P16BE
,
100
AV_PIX_FMT_YUV422P16LE
,
AV_PIX_FMT_YUV422P16BE
,
101
AV_PIX_FMT_YUV444P16LE
,
AV_PIX_FMT_YUV444P16BE
,
102
AV_PIX_FMT_YUV444P
,
AV_PIX_FMT_YUV422P
,
103
AV_PIX_FMT_YUV420P
,
AV_PIX_FMT_YUV411P
,
104
AV_PIX_FMT_YUV410P
,
AV_PIX_FMT_YUV440P
,
105
AV_PIX_FMT_YUVJ444P
,
AV_PIX_FMT_YUVJ422P
,
106
AV_PIX_FMT_YUVJ420P
,
AV_PIX_FMT_YUVJ440P
,
107
AV_PIX_FMT_YUVA420P
,
108
AV_PIX_FMT_RGB8
,
AV_PIX_FMT_BGR8
,
109
AV_PIX_FMT_RGB4_BYTE
,
AV_PIX_FMT_BGR4_BYTE
,
110
AV_PIX_FMT_PAL8
,
AV_PIX_FMT_GRAY8
,
111
AV_PIX_FMT_NONE
112
};
113
114
ff_set_common_formats
(ctx,
ff_make_format_list
(pix_fmts));
115
116
return
0;
117
}
118
119
static
av_cold
int
init
(
AVFilterContext
*ctx,
const
char
*args)
120
{
121
CropContext
*crop = ctx->
priv
;
122
123
av_strlcpy
(crop->
ow_expr
,
"iw"
,
sizeof
(crop->
ow_expr
));
124
av_strlcpy
(crop->
oh_expr
,
"ih"
,
sizeof
(crop->
oh_expr
));
125
av_strlcpy
(crop->
x_expr
,
"(in_w-out_w)/2"
,
sizeof
(crop->
x_expr
));
126
av_strlcpy
(crop->
y_expr
,
"(in_h-out_h)/2"
,
sizeof
(crop->
y_expr
));
127
128
if
(args)
129
sscanf(args,
"%255[^:]:%255[^:]:%255[^:]:%255[^:]"
, crop->
ow_expr
, crop->
oh_expr
, crop->
x_expr
, crop->
y_expr
);
130
131
return
0;
132
}
133
134
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
135
{
136
CropContext
*crop = ctx->
priv
;
137
138
av_expr_free
(crop->
x_pexpr
); crop->
x_pexpr
=
NULL
;
139
av_expr_free
(crop->
y_pexpr
); crop->
y_pexpr
=
NULL
;
140
}
141
142
static
inline
int
normalize_double
(
int
*n,
double
d)
143
{
144
int
ret = 0;
145
146
if
(
isnan
(d)) {
147
ret =
AVERROR
(EINVAL);
148
}
else
if
(d > INT_MAX || d < INT_MIN) {
149
*n = d > INT_MAX ? INT_MAX : INT_MIN;
150
ret =
AVERROR
(EINVAL);
151
}
else
152
*n =
round
(d);
153
154
return
ret;
155
}
156
157
static
int
config_input
(
AVFilterLink
*link)
158
{
159
AVFilterContext
*ctx = link->
dst
;
160
CropContext
*crop = ctx->
priv
;
161
const
AVPixFmtDescriptor
*pix_desc =
av_pix_fmt_desc_get
(link->
format
);
162
int
ret;
163
const
char
*expr;
164
double
res;
165
166
crop->
var_values
[
VAR_E
] =
M_E
;
167
crop->
var_values
[
VAR_PHI
] =
M_PHI
;
168
crop->
var_values
[
VAR_PI
] = M_PI;
169
crop->
var_values
[
VAR_IN_W
] = crop->
var_values
[
VAR_IW
] = ctx->
inputs
[0]->
w
;
170
crop->
var_values
[
VAR_IN_H
] = crop->
var_values
[
VAR_IH
] = ctx->
inputs
[0]->
h
;
171
crop->
var_values
[
VAR_X
] =
NAN
;
172
crop->
var_values
[
VAR_Y
] =
NAN
;
173
crop->
var_values
[
VAR_OUT_W
] = crop->
var_values
[
VAR_OW
] =
NAN
;
174
crop->
var_values
[
VAR_OUT_H
] = crop->
var_values
[
VAR_OH
] =
NAN
;
175
crop->
var_values
[
VAR_N
] = 0;
176
crop->
var_values
[
VAR_T
] =
NAN
;
177
crop->
var_values
[
VAR_POS
] =
NAN
;
178
179
av_image_fill_max_pixsteps
(crop->
max_step
,
NULL
, pix_desc);
180
crop->
hsub
= pix_desc->
log2_chroma_w
;
181
crop->
vsub
= pix_desc->
log2_chroma_h
;
182
183
if
((ret =
av_expr_parse_and_eval
(&res, (expr = crop->
ow_expr
),
184
var_names
, crop->
var_values
,
185
NULL
,
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
goto
fail_expr;
186
crop->
var_values
[
VAR_OUT_W
] = crop->
var_values
[
VAR_OW
] = res;
187
if
((ret =
av_expr_parse_and_eval
(&res, (expr = crop->
oh_expr
),
188
var_names
, crop->
var_values
,
189
NULL
,
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
goto
fail_expr;
190
crop->
var_values
[
VAR_OUT_H
] = crop->
var_values
[
VAR_OH
] = res;
191
/* evaluate again ow as it may depend on oh */
192
if
((ret =
av_expr_parse_and_eval
(&res, (expr = crop->
ow_expr
),
193
var_names
, crop->
var_values
,
194
NULL
,
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
goto
fail_expr;
195
crop->
var_values
[
VAR_OUT_W
] = crop->
var_values
[
VAR_OW
] = res;
196
if
(
normalize_double
(&crop->
w
, crop->
var_values
[
VAR_OUT_W
]) < 0 ||
197
normalize_double
(&crop->
h
, crop->
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
crop->
ow_expr
, crop->
oh_expr
);
202
return
AVERROR
(EINVAL);
203
}
204
crop->
w
&= ~((1 << crop->
hsub
) - 1);
205
crop->
h
&= ~((1 << crop->
vsub
) - 1);
206
207
if
((ret =
av_expr_parse
(&crop->
x_pexpr
, crop->
x_expr
,
var_names
,
208
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0 ||
209
(ret =
av_expr_parse
(&crop->
y_pexpr
, crop->
y_expr
,
var_names
,
210
NULL
,
NULL
,
NULL
,
NULL
, 0, ctx)) < 0)
211
return
AVERROR
(EINVAL);
212
213
av_log
(ctx,
AV_LOG_VERBOSE
,
"w:%d h:%d -> w:%d h:%d\n"
,
214
link->
w
, link->
h
, crop->
w
, crop->
h
);
215
216
if
(crop->
w
<= 0 || crop->
h
<= 0 ||
217
crop->
w
> link->
w
|| crop->
h
> link->
h
) {
218
av_log
(ctx,
AV_LOG_ERROR
,
219
"Invalid too big or non positive size for width '%d' or height '%d'\n"
,
220
crop->
w
, crop->
h
);
221
return
AVERROR
(EINVAL);
222
}
223
224
/* set default, required in the case the first computed value for x/y is NAN */
225
crop->
x
= (link->
w
- crop->
w
) / 2;
226
crop->
y
= (link->
h
- crop->
h
) / 2;
227
crop->
x
&= ~((1 << crop->
hsub
) - 1);
228
crop->
y
&= ~((1 << crop->
vsub
) - 1);
229
return
0;
230
231
fail_expr:
232
av_log
(
NULL
,
AV_LOG_ERROR
,
"Error when evaluating the expression '%s'\n"
, expr);
233
return
ret;
234
}
235
236
static
int
config_output
(
AVFilterLink
*link)
237
{
238
CropContext
*crop = link->
src
->
priv
;
239
240
link->
w
= crop->
w
;
241
link->
h
= crop->
h
;
242
243
return
0;
244
}
245
246
static
int
filter_frame
(
AVFilterLink
*link,
AVFilterBufferRef
*frame)
247
{
248
AVFilterContext
*ctx = link->
dst
;
249
CropContext
*crop = ctx->
priv
;
250
const
AVPixFmtDescriptor
*desc =
av_pix_fmt_desc_get
(link->
format
);
251
int
i;
252
253
frame->
video
->
w
= crop->
w
;
254
frame->
video
->
h
= crop->
h
;
255
256
crop->
var_values
[
VAR_T
] = frame->
pts
==
AV_NOPTS_VALUE
?
257
NAN
: frame->
pts
*
av_q2d
(link->
time_base
);
258
crop->
var_values
[
VAR_POS
] = frame->
pos
== -1 ?
NAN
: frame->
pos
;
259
crop->
var_values
[
VAR_X
] =
av_expr_eval
(crop->
x_pexpr
, crop->
var_values
,
NULL
);
260
crop->
var_values
[
VAR_Y
] =
av_expr_eval
(crop->
y_pexpr
, crop->
var_values
,
NULL
);
261
crop->
var_values
[
VAR_X
] =
av_expr_eval
(crop->
x_pexpr
, crop->
var_values
,
NULL
);
262
263
normalize_double
(&crop->
x
, crop->
var_values
[
VAR_X
]);
264
normalize_double
(&crop->
y
, crop->
var_values
[
VAR_Y
]);
265
266
if
(crop->
x
< 0) crop->
x
= 0;
267
if
(crop->
y
< 0) crop->
y
= 0;
268
if
((
unsigned
)crop->
x
+ (
unsigned
)crop->
w
> link->
w
) crop->
x
= link->
w
- crop->
w
;
269
if
((
unsigned
)crop->
y
+ (
unsigned
)crop->
h
> link->
h
) crop->
y
= link->
h
- crop->
h
;
270
crop->
x
&= ~((1 << crop->
hsub
) - 1);
271
crop->
y
&= ~((1 << crop->
vsub
) - 1);
272
273
av_dlog
(ctx,
"n:%d t:%f x:%d y:%d x+w:%d y+h:%d\n"
,
274
(
int
)crop->
var_values
[
VAR_N
], crop->
var_values
[
VAR_T
], crop->
x
,
275
crop->
y
, crop->
x
+crop->
w
, crop->
y
+crop->
h
);
276
277
frame->
data
[0] += crop->
y
* frame->
linesize
[0];
278
frame->
data
[0] += crop->
x
* crop->
max_step
[0];
279
280
if
(!(desc->
flags
&
PIX_FMT_PAL
|| desc->
flags
&
PIX_FMT_PSEUDOPAL
)) {
281
for
(i = 1; i < 3; i ++) {
282
if
(frame->
data
[i]) {
283
frame->
data
[i] += (crop->
y
>> crop->
vsub
) * frame->
linesize
[i];
284
frame->
data
[i] += (crop->
x
* crop->
max_step
[i]) >> crop->
hsub
;
285
}
286
}
287
}
288
289
/* alpha plane */
290
if
(frame->
data
[3]) {
291
frame->
data
[3] += crop->
y
* frame->
linesize
[3];
292
frame->
data
[3] += crop->
x
* crop->
max_step
[3];
293
}
294
295
crop->
var_values
[
VAR_N
] += 1.0;
296
297
return
ff_filter_frame
(link->
dst
->
outputs
[0], frame);
298
}
299
300
static
const
AVFilterPad
avfilter_vf_crop_inputs
[] = {
301
{
302
.
name
=
"default"
,
303
.type =
AVMEDIA_TYPE_VIDEO
,
304
.filter_frame =
filter_frame
,
305
.get_video_buffer =
ff_null_get_video_buffer
,
306
.config_props =
config_input
,
307
},
308
{
NULL
}
309
};
310
311
static
const
AVFilterPad
avfilter_vf_crop_outputs
[] = {
312
{
313
.
name
=
"default"
,
314
.type =
AVMEDIA_TYPE_VIDEO
,
315
.config_props =
config_output
,
316
},
317
{
NULL
}
318
};
319
320
AVFilter
avfilter_vf_crop
= {
321
.
name
=
"crop"
,
322
.description =
NULL_IF_CONFIG_SMALL
(
"Crop the input video to width:height:x:y."
),
323
324
.priv_size =
sizeof
(
CropContext
),
325
326
.
query_formats
=
query_formats
,
327
.
init
=
init
,
328
.
uninit
=
uninit
,
329
330
.
inputs
= avfilter_vf_crop_inputs,
331
.
outputs
= avfilter_vf_crop_outputs,
332
};