1 /*
2 * Copyright (c) 2008 Affine Systems, Inc (Michael Sullivan, Bobby Impollonia)
3 * Copyright (c) 2013 Andrey Utkin <andrey.krieger.utkin gmail com>
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 * Box and grid drawing filters. Also a nice template for a filter
25 * that needs to write in the input frame.
26 */
27
38
40 "dar",
41 "hsub", "vsub",
42 "in_h", "ih", ///< height of the input video
43 "in_w", "iw", ///< width of the input video
44 "sar",
45 "x",
46 "y",
47 "h", ///< height of the rendered box
48 "w", ///< width of the rendered box
49 "t",
50 NULL
51 };
52
54
67 };
68
74 unsigned char yuv_color[4];
76 int vsub, hsub;
///< chroma subsampling
77 char *x_expr, *
y_expr;
///< expression for x and y
78 char *
w_expr, *h_expr;
///< expression for width and height
79 char *
t_expr;
///< expression for thickness
81
83
85 {
88
93
99 }
100
101 return 0;
102 }
103
105 {
112 };
113
115 return 0;
116 }
117
119 {
124 char *expr;
126 int i;
127
130
142
144 /* evaluate expressions, fail on last iteration */
147 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i ==
NUM_EXPR_EVALS)
148 goto fail;
150
153 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i ==
NUM_EXPR_EVALS)
154 goto fail;
156
159 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i ==
NUM_EXPR_EVALS)
160 goto fail;
162
165 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i ==
NUM_EXPR_EVALS)
166 goto fail;
168
171 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i ==
NUM_EXPR_EVALS)
172 goto fail;
174 }
175
176 /* if w or h are zero, use the input w/h */
177 s->
w = (s->
w > 0) ? s->
w : inlink->
w;
178 s->
h = (s->
h > 0) ? s->
h : inlink->
h;
179
180 /* sanity check width and height */
181 if (s->
w < 0 || s->
h < 0) {
184 }
185
187 s->
x, s->
y, s->
w, s->
h,
189
190 return 0;
191
192 fail:
194 "Error when evaluating the expression '%s'.\n",
195 expr);
197 }
198
200 {
202 int plane, x,
y, xb = s->
x, yb = s->
y;
203 unsigned char *row[4];
204
205 for (y =
FFMAX(yb, 0); y < frame->
height && y < (yb + s->
h); y++) {
207
208 for (plane = 1; plane < 3; plane++)
209 row[plane] = frame->
data[plane] +
211
213 for (x =
FFMAX(xb, 0); x < xb + s->
w && x < frame->
width; x++)
214 if ((y - yb < s->thickness) || (yb + s->
h - 1 - y < s->
thickness) ||
215 (x - xb < s->thickness) || (xb + s->
w - 1 - x < s->
thickness))
216 row[0][x] = 0xff - row[0][x];
217 } else {
218 for (x =
FFMAX(xb, 0); x < xb + s->
w && x < frame->
width; x++) {
220
221 if ((y - yb < s->thickness) || (yb + s->
h - 1 - y < s->
thickness) ||
222 (x - xb < s->thickness) || (xb + s->
w - 1 - x < s->
thickness)) {
226 }
227 }
228 }
229 }
230
232 }
233
234 #define OFFSET(x) offsetof(DrawBoxContext, x)
235 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
236
237 #if CONFIG_DRAWBOX_FILTER
238
239 static const AVOption drawbox_options[] = {
250 { NULL }
251 };
252
254
256 {
261 .needs_writable = 1,
262 },
263 { NULL }
264 };
265
267 {
270 },
271 { NULL }
272 };
273
278 .priv_class = &drawbox_class,
284 };
285 #endif /* CONFIG_DRAWBOX_FILTER */
286
287 #if CONFIG_DRAWGRID_FILTER
289 {
290 // x is horizontal (width) coord,
291 // y is vertical (height) coord
292 int x_modulo;
293 int y_modulo;
294
295 // Abstract from the offset
298
299 x_modulo = x % drawgrid->
w;
300 y_modulo = y % drawgrid->
h;
301
302 // If x or y got negative, fix values to preserve logics
303 if (x_modulo < 0)
304 x_modulo += drawgrid->
w;
305 if (y_modulo < 0)
306 y_modulo += drawgrid->
h;
307
308 return x_modulo < drawgrid->
thickness // Belongs to vertical line
309 || y_modulo < drawgrid->
thickness;
// Belongs to horizontal line
310 }
311
313 {
317
318 for (y = 0; y < frame->
height; y++) {
320
321 for (plane = 1; plane < 3; plane++)
322 row[plane] = frame->
data[plane] +
324
326 for (x = 0; x < frame->
width; x++)
327 if (pixel_belongs_to_grid(drawgrid, x, y))
328 row[0][x] = 0xff - row[0][x];
329 } else {
330 for (x = 0; x < frame->
width; x++) {
332
333 if (pixel_belongs_to_grid(drawgrid, x, y)) {
334 row[0][x ] = (1 -
alpha) * row[0][x ] + alpha * drawgrid->
yuv_color[
Y];
335 row[1][x >> drawgrid->
hsub] = (1 - alpha) * row[1][x >> drawgrid->
hsub] + alpha * drawgrid->
yuv_color[
U];
337 }
338 }
339 }
340 }
341
343 }
344
345 static const AVOption drawgrid_options[] = {
356 { NULL }
357 };
358
360
362 {
366 .filter_frame = drawgrid_filter_frame,
367 .needs_writable = 1,
368 },
369 { NULL }
370 };
371
373 {
376 },
377 { NULL }
378 };
379
384 .priv_class = &drawgrid_class,
387 .
inputs = drawgrid_inputs,
390 };
391
392 #endif /* CONFIG_DRAWGRID_FILTER */