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