1 /*
2 * Copyright (c) 2008 vmrsss
3 * Copyright (c) 2009 Stefano Sabatini
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * video padding filter
25 */
26
41
43
45 "in_w", "iw",
46 "in_h", "ih",
47 "out_w", "ow",
48 "out_h", "oh",
49 "x",
50 "y",
51 "a",
52 "sar",
53 "dar",
54 "hsub",
55 "vsub",
56 NULL
57 };
58
72 };
73
75 {
77 return 0;
78 }
79
82 int w, h;
///< output dimensions, a value of 0 will result in the input size
83 int x,
y;
///< offsets of the input area with respect to the padded area
84 int in_w, in_h;
///< width and height for the padded input video, which has to be aligned to the chroma values in order to avoid chroma issues
85
86 char *
w_expr;
///< width expression string
87 char *
h_expr;
///< height expression string
88 char *
x_expr;
///< width expression string
89 char *
y_expr;
///< height expression string
90 uint8_t rgba_color[4];
///< color for the padding area
94
96 {
101 char *expr;
102
105
110 var_values[
VAR_A] = (double) inlink->
w / inlink->
h;
116
117 /* evaluate width and height */
120 NULL, NULL, NULL, NULL, NULL, 0, ctx);
124 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
125 goto eval_fail;
127 /* evaluate the width again, as it may depend on the evaluated output height */
130 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
131 goto eval_fail;
133
134 /* evaluate x and y */
137 NULL, NULL, NULL, NULL, NULL, 0, ctx);
141 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
142 goto eval_fail;
144 /* evaluate x again, as it may depend on the evaluated y value */
147 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
148 goto eval_fail;
150
151 /* sanity check params */
152 if (s->
w < 0 || s->
h < 0 || s->
x < 0 || s->
y < 0) {
155 }
156
161
168
170 inlink->
w, inlink->
h, s->
w, s->
h, s->
x, s->
y,
172
173 if (s->
x < 0 || s->
y < 0 ||
174 s->
w <= 0 || s->
h <= 0 ||
175 (
unsigned)s->
x + (
unsigned)inlink->
w > s->
w ||
176 (
unsigned)s->
y + (
unsigned)inlink->
h > s->
h) {
178 "Input area %d:%d:%d:%d not within the padded area 0:0:%d:%d or zero-sized\n",
179 s->
x, s->
y, s->
x + inlink->
w, s->
y + inlink->
h, s->
w, s->
h);
181 }
182
183 return 0;
184
185 eval_fail:
187 "Error when evaluating the expression '%s'\n", expr);
189
190 }
191
193 {
195
198 return 0;
199 }
200
202 {
204
206 w + (s->
w - s->
in_w),
207 h + (s->
h - s->
in_h));
208 int plane;
209
210 if (!frame)
211 return NULL;
212
215
216 for (plane = 0; plane < 4 && frame->
data[plane] && frame->
linesize[plane]; plane++) {
221 }
222
224 }
225
226 /* check whether each plane in this buffer can be padded without copying */
228 {
229 int planes[4] = { -1, -1, -1, -1}, *p = planes;
230 int i, j;
231
232 /* get all planes in this buffer */
235 *p++ = i;
236 }
237
238 /* for each plane in this buffer, check that it can be padded without
239 * going over buffer bounds or other planes */
240 for (i = 0; i < FF_ARRAY_ELEMS(planes) && planes[i] >= 0; i++) {
243
247
248 /* amount of free space needed before the start and after the end
249 * of the plane */
250 ptrdiff_t req_start = (s->
x >> hsub) * s->
draw.
pixelstep[planes[i]] +
251 (s->
y >> vsub) * frame->
linesize[planes[i]];
252 ptrdiff_t req_end = ((s->
w - s->
x - frame->
width) >> hsub) *
255
257 return 1;
258 if (start - buf->
data < req_start ||
259 (buf->
data + buf->
size) - end < req_end)
260 return 1;
261
262 for (j = 0; j < FF_ARRAY_ELEMS(planes) && planes[j] >= 0; j++) {
263 int vsub1 = s->
draw.
vsub[planes[j]];
268 continue;
269
270 if (
FFSIGN(start - end1) !=
FFSIGN(start - end1 - req_start) ||
272 return 1;
273 }
274 }
275
276 return 0;
277 }
278
280 {
281 int i;
282
284 return 1;
285
286 for (i = 0; i < 4 && frame->
buf[i]; i++)
288 return 1;
289 return 0;
290 }
291
293 {
297
298 if (needs_copy) {
303 if (!out) {
306 }
307
309 } else {
310 int i;
311
313 for (i = 0; i < 4 && out->
data[i] && out->
linesize[i]; i++) {
318 }
319 }
320
321 /* top bar */
326 }
327
328 /* bottom bar */
329 if (s->
h > s->
y + s->
in_h) {
333 }
334
335 /* left border */
338
339 if (needs_copy) {
343 }
344
345 /* right border */
349
352
353 if (in != out)
356 }
357
358 #define OFFSET(x) offsetof(PadContext, x)
359 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
360
366 {
"x",
"set the x offset expression for the input image position",
OFFSET(x_expr),
AV_OPT_TYPE_STRING, {.str =
"0"}, CHAR_MIN, CHAR_MAX,
FLAGS },
367 {
"y",
"set the y offset expression for the input image position",
OFFSET(y_expr),
AV_OPT_TYPE_STRING, {.str =
"0"}, CHAR_MIN, CHAR_MAX,
FLAGS },
369 { NULL }
370 };
371
373
375 {
381 },
382 { NULL }
383 };
384
386 {
390 },
391 { NULL }
392 };
393
398 .priv_class = &pad_class,
400 .
inputs = avfilter_vf_pad_inputs,
401 .
outputs = avfilter_vf_pad_outputs,
402 };