FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_fillborders.c
Date: 2022-12-09 07:38:14
Exec Total Coverage
Lines: 0 347 0.0%
Functions: 0 19 0.0%
Branches: 0 224 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2017 Paul B Mahol
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 #include "libavutil/avassert.h"
22 #include "libavutil/colorspace.h"
23 #include "libavutil/common.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/pixdesc.h"
26 #include "avfilter.h"
27 #include "drawutils.h"
28 #include "formats.h"
29 #include "internal.h"
30 #include "video.h"
31
32 enum { Y, U, V, A };
33 enum { R, G, B };
34
35 enum FillMode { FM_SMEAR, FM_MIRROR, FM_FIXED, FM_REFLECT, FM_WRAP, FM_FADE, FM_MARGINS, FM_NB_MODES };
36
37 typedef struct Borders {
38 int left, right, top, bottom;
39 } Borders;
40
41 typedef struct FillBordersContext {
42 const AVClass *class;
43 int left, right, top, bottom;
44 int mode;
45
46 int nb_planes;
47 int depth;
48 Borders borders[4];
49 int planewidth[4];
50 int planeheight[4];
51 uint8_t fill[4];
52 uint8_t yuv_color[4];
53 uint8_t rgba_color[4];
54
55 void (*fillborders)(struct FillBordersContext *s, AVFrame *frame);
56 } FillBordersContext;
57
58 static const enum AVPixelFormat pix_fmts[] = {
59 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
60 AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
61 AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
62 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
63 AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
64 AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
65 AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
66 AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
67 AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
68 AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
69 AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
70 AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
71 AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA444P12,
72 AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
73 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
74 AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
75 AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
76 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
77 AV_PIX_FMT_NONE
78 };
79
80 static void smear_borders8(FillBordersContext *s, AVFrame *frame)
81 {
82 int p, y;
83
84 for (p = 0; p < s->nb_planes; p++) {
85 uint8_t *ptr = frame->data[p];
86 int linesize = frame->linesize[p];
87
88 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
89 memset(ptr + y * linesize,
90 *(ptr + y * linesize + s->borders[p].left),
91 s->borders[p].left);
92 memset(ptr + y * linesize + s->planewidth[p] - s->borders[p].right,
93 *(ptr + y * linesize + s->planewidth[p] - s->borders[p].right - 1),
94 s->borders[p].right);
95 }
96
97 for (y = 0; y < s->borders[p].top; y++) {
98 memcpy(ptr + y * linesize,
99 ptr + s->borders[p].top * linesize, s->planewidth[p]);
100 }
101
102 for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) {
103 memcpy(ptr + y * linesize,
104 ptr + (s->planeheight[p] - s->borders[p].bottom - 1) * linesize,
105 s->planewidth[p]);
106 }
107 }
108 }
109
110 static void smear_borders16(FillBordersContext *s, AVFrame *frame)
111 {
112 int p, y, x;
113
114 for (p = 0; p < s->nb_planes; p++) {
115 uint16_t *ptr = (uint16_t *)frame->data[p];
116 int linesize = frame->linesize[p] / 2;
117
118 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
119 for (x = 0; x < s->borders[p].left; x++) {
120 ptr[y * linesize + x] = *(ptr + y * linesize + s->borders[p].left);
121 }
122
123 for (x = 0; x < s->borders[p].right; x++) {
124 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] =
125 *(ptr + y * linesize + s->planewidth[p] - s->borders[p].right - 1);
126 }
127 }
128
129 for (y = 0; y < s->borders[p].top; y++) {
130 memcpy(ptr + y * linesize,
131 ptr + s->borders[p].top * linesize, s->planewidth[p] * 2);
132 }
133
134 for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) {
135 memcpy(ptr + y * linesize,
136 ptr + (s->planeheight[p] - s->borders[p].bottom - 1) * linesize,
137 s->planewidth[p] * 2);
138 }
139 }
140 }
141
142 static void mirror_borders8(FillBordersContext *s, AVFrame *frame)
143 {
144 int p, y, x;
145
146 for (p = 0; p < s->nb_planes; p++) {
147 uint8_t *ptr = frame->data[p];
148 int linesize = frame->linesize[p];
149
150 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
151 for (x = 0; x < s->borders[p].left; x++) {
152 ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - 1 - x];
153 }
154
155 for (x = 0; x < s->borders[p].right; x++) {
156 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] =
157 ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 1 - x];
158 }
159 }
160
161 for (y = 0; y < s->borders[p].top; y++) {
162 memcpy(ptr + y * linesize,
163 ptr + (s->borders[p].top * 2 - 1 - y) * linesize,
164 s->planewidth[p]);
165 }
166
167 for (y = 0; y < s->borders[p].bottom; y++) {
168 memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize,
169 ptr + (s->planeheight[p] - s->borders[p].bottom - 1 - y) * linesize,
170 s->planewidth[p]);
171 }
172 }
173 }
174
175 static void mirror_borders16(FillBordersContext *s, AVFrame *frame)
176 {
177 int p, y, x;
178
179 for (p = 0; p < s->nb_planes; p++) {
180 uint16_t *ptr = (uint16_t *)frame->data[p];
181 int linesize = frame->linesize[p] / 2;
182
183 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
184 for (x = 0; x < s->borders[p].left; x++) {
185 ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - 1 - x];
186 }
187
188 for (x = 0; x < s->borders[p].right; x++) {
189 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] =
190 ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 1 - x];
191 }
192 }
193
194 for (y = 0; y < s->borders[p].top; y++) {
195 memcpy(ptr + y * linesize,
196 ptr + (s->borders[p].top * 2 - 1 - y) * linesize,
197 s->planewidth[p] * 2);
198 }
199
200 for (y = 0; y < s->borders[p].bottom; y++) {
201 memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize,
202 ptr + (s->planeheight[p] - s->borders[p].bottom - 1 - y) * linesize,
203 s->planewidth[p] * 2);
204 }
205 }
206 }
207
208 static void fixed_borders8(FillBordersContext *s, AVFrame *frame)
209 {
210 int p, y;
211
212 for (p = 0; p < s->nb_planes; p++) {
213 uint8_t *ptr = frame->data[p];
214 uint8_t fill = s->fill[p];
215 int linesize = frame->linesize[p];
216
217 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
218 memset(ptr + y * linesize, fill, s->borders[p].left);
219 memset(ptr + y * linesize + s->planewidth[p] - s->borders[p].right, fill,
220 s->borders[p].right);
221 }
222
223 for (y = 0; y < s->borders[p].top; y++) {
224 memset(ptr + y * linesize, fill, s->planewidth[p]);
225 }
226
227 for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) {
228 memset(ptr + y * linesize, fill, s->planewidth[p]);
229 }
230 }
231 }
232
233 static void fixed_borders16(FillBordersContext *s, AVFrame *frame)
234 {
235 int p, y, x;
236
237 for (p = 0; p < s->nb_planes; p++) {
238 uint16_t *ptr = (uint16_t *)frame->data[p];
239 uint16_t fill = s->fill[p] << (s->depth - 8);
240 int linesize = frame->linesize[p] / 2;
241
242 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
243 for (x = 0; x < s->borders[p].left; x++) {
244 ptr[y * linesize + x] = fill;
245 }
246
247 for (x = 0; x < s->borders[p].right; x++) {
248 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = fill;
249 }
250 }
251
252 for (y = 0; y < s->borders[p].top; y++) {
253 for (x = 0; x < s->planewidth[p]; x++) {
254 ptr[y * linesize + x] = fill;
255 }
256 }
257
258 for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) {
259 for (x = 0; x < s->planewidth[p]; x++) {
260 ptr[y * linesize + x] = fill;
261 }
262 }
263 }
264 }
265
266 static void reflect_borders8(FillBordersContext *s, AVFrame *frame)
267 {
268 int p, y, x;
269
270 for (p = 0; p < s->nb_planes; p++) {
271 uint8_t *ptr = frame->data[p];
272 int linesize = frame->linesize[p];
273
274 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
275 for (x = 0; x < s->borders[p].left; x++) {
276 ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - x];
277 }
278
279 for (x = 0; x < s->borders[p].right; x++) {
280 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] =
281 ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 2 - x];
282 }
283 }
284
285 for (y = 0; y < s->borders[p].top; y++) {
286 memcpy(ptr + y * linesize,
287 ptr + (s->borders[p].top * 2 - y) * linesize,
288 s->planewidth[p]);
289 }
290
291 for (y = 0; y < s->borders[p].bottom; y++) {
292 memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize,
293 ptr + (s->planeheight[p] - s->borders[p].bottom - 2 - y) * linesize,
294 s->planewidth[p]);
295 }
296 }
297 }
298
299 static void reflect_borders16(FillBordersContext *s, AVFrame *frame)
300 {
301 int p, y, x;
302
303 for (p = 0; p < s->nb_planes; p++) {
304 uint16_t *ptr = (uint16_t *)frame->data[p];
305 int linesize = frame->linesize[p] / 2;
306
307 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
308 for (x = 0; x < s->borders[p].left; x++) {
309 ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - x];
310 }
311
312 for (x = 0; x < s->borders[p].right; x++) {
313 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] =
314 ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 2 - x];
315 }
316 }
317
318 for (y = 0; y < s->borders[p].top; y++) {
319 memcpy(ptr + y * linesize,
320 ptr + (s->borders[p].top * 2 - y) * linesize,
321 s->planewidth[p] * 2);
322 }
323
324 for (y = 0; y < s->borders[p].bottom; y++) {
325 memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize,
326 ptr + (s->planeheight[p] - s->borders[p].bottom - 2 - y) * linesize,
327 s->planewidth[p] * 2);
328 }
329 }
330 }
331
332 static void wrap_borders8(FillBordersContext *s, AVFrame *frame)
333 {
334 int p, y, x;
335
336 for (p = 0; p < s->nb_planes; p++) {
337 uint8_t *ptr = frame->data[p];
338 int linesize = frame->linesize[p];
339
340 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
341 for (x = 0; x < s->borders[p].left; x++) {
342 ptr[y * linesize + x] = ptr[y * linesize + s->planewidth[p] - s->borders[p].right - s->borders[p].left + x];
343 }
344
345 for (x = 0; x < s->borders[p].right; x++) {
346 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] =
347 ptr[y * linesize + s->borders[p].left + x];
348 }
349 }
350
351 for (y = 0; y < s->borders[p].top; y++) {
352 memcpy(ptr + y * linesize,
353 ptr + (s->planeheight[p] - s->borders[p].bottom - s->borders[p].top + y) * linesize,
354 s->planewidth[p]);
355 }
356
357 for (y = 0; y < s->borders[p].bottom; y++) {
358 memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize,
359 ptr + (s->borders[p].top + y) * linesize,
360 s->planewidth[p]);
361 }
362 }
363 }
364
365 static void wrap_borders16(FillBordersContext *s, AVFrame *frame)
366 {
367 int p, y, x;
368
369 for (p = 0; p < s->nb_planes; p++) {
370 uint16_t *ptr = (uint16_t *)frame->data[p];
371 int linesize = frame->linesize[p] / 2;
372
373 for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) {
374 for (x = 0; x < s->borders[p].left; x++) {
375 ptr[y * linesize + x] = ptr[y * linesize + s->planewidth[p] - s->borders[p].right - s->borders[p].left + x];
376 }
377
378 for (x = 0; x < s->borders[p].right; x++) {
379 ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] =
380 ptr[y * linesize + s->borders[p].left + x];
381 }
382 }
383
384 for (y = 0; y < s->borders[p].top; y++) {
385 memcpy(ptr + y * linesize,
386 ptr + (s->planeheight[p] - s->borders[p].bottom - s->borders[p].top + y) * linesize,
387 s->planewidth[p] * 2);
388 }
389
390 for (y = 0; y < s->borders[p].bottom; y++) {
391 memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize,
392 ptr + (s->borders[p].top + y) * linesize,
393 s->planewidth[p] * 2);
394 }
395 }
396 }
397
398 static int lerp8(int fill, int src, int pos, int size)
399 {
400 return av_clip_uint8(((fill * 256 * pos / size) + (src * 256 * (size - pos) / size)) >> 8);
401 }
402
403 static int lerp16(int fill, int src, int pos, int size, int depth)
404 {
405 return av_clip_uintp2_c(((fill * (1LL << depth) * pos / size) + (src * (1LL << depth) * (size - pos) / size)) >> depth, depth);
406 }
407
408 static void fade_borders8(FillBordersContext *s, AVFrame *frame)
409 {
410 int p, y, x;
411
412 for (p = 0; p < s->nb_planes; p++) {
413 uint8_t *ptr = frame->data[p];
414 const uint8_t fill = s->fill[p];
415 const int linesize = frame->linesize[p];
416 const int start_left = s->borders[p].left;
417 const int start_right = s->planewidth[p] - s->borders[p].right;
418 const int start_top = s->borders[p].top;
419 const int start_bottom = s->planeheight[p] - s->borders[p].bottom;
420
421 for (y = 0; y < start_top; y++) {
422 for (x = 0; x < s->planewidth[p]; x++) {
423 int src = ptr[y * linesize + x];
424 ptr[y * linesize + x] = lerp8(fill, src, start_top - y, start_top);
425 }
426 }
427
428 for (y = start_bottom; y < s->planeheight[p]; y++) {
429 for (x = 0; x < s->planewidth[p]; x++) {
430 int src = ptr[y * linesize + x];
431 ptr[y * linesize + x] = lerp8(fill, src, y - start_bottom, s->borders[p].bottom);
432 }
433 }
434
435 for (y = 0; y < s->planeheight[p]; y++) {
436 for (x = 0; x < start_left; x++) {
437 int src = ptr[y * linesize + x];
438 ptr[y * linesize + x] = lerp8(fill, src, start_left - x, start_left);
439 }
440
441 for (x = 0; x < s->borders[p].right; x++) {
442 int src = ptr[y * linesize + start_right + x];
443 ptr[y * linesize + start_right + x] = lerp8(fill, src, x, s->borders[p].right);
444 }
445 }
446 }
447 }
448
449 static void fade_borders16(FillBordersContext *s, AVFrame *frame)
450 {
451 const int depth = s->depth;
452 int p, y, x;
453
454 for (p = 0; p < s->nb_planes; p++) {
455 uint16_t *ptr = (uint16_t *)frame->data[p];
456 const uint16_t fill = s->fill[p] << (depth - 8);
457 const int linesize = frame->linesize[p] / 2;
458 const int start_left = s->borders[p].left;
459 const int start_right = s->planewidth[p] - s->borders[p].right;
460 const int start_top = s->borders[p].top;
461 const int start_bottom = s->planeheight[p] - s->borders[p].bottom;
462
463 for (y = 0; y < start_top; y++) {
464 for (x = 0; x < s->planewidth[p]; x++) {
465 int src = ptr[y * linesize + x];
466 ptr[y * linesize + x] = lerp16(fill, src, start_top - y, start_top, depth);
467 }
468 }
469
470 for (y = start_bottom; y < s->planeheight[p]; y++) {
471 for (x = 0; x < s->planewidth[p]; x++) {
472 int src = ptr[y * linesize + x];
473 ptr[y * linesize + x] = lerp16(fill, src, y - start_bottom, s->borders[p].bottom, depth);
474 }
475 }
476
477 for (y = 0; y < s->planeheight[p]; y++) {
478 for (x = 0; x < start_left; x++) {
479 int src = ptr[y * linesize + x];
480 ptr[y * linesize + x] = lerp16(fill, src, start_left - x, start_left, depth);
481 }
482
483 for (x = 0; x < s->borders[p].right; x++) {
484 int src = ptr[y * linesize + start_right + x];
485 ptr[y * linesize + start_right + x] = lerp16(fill, src, x, s->borders[p].right, depth);
486 }
487 }
488 }
489 }
490
491 static void margins_borders8(FillBordersContext *s, AVFrame *frame)
492 {
493 for (int p = 0; p < s->nb_planes; p++) {
494 uint8_t *ptr = (uint8_t *)frame->data[p];
495 const int linesize = frame->linesize[p];
496 const int left = s->borders[p].left;
497 const int right = s->borders[p].right;
498 const int top = s->borders[p].top;
499 const int bottom = s->borders[p].bottom;
500 const int width = s->planewidth[p];
501 const int height = s->planeheight[p];
502
503 for (int y = top; y < height - bottom; y++) {
504 memset(ptr + linesize * y, ptr[linesize * y + left], left);
505 memset(ptr + linesize * y + width - right, (ptr + linesize * y + width - right)[-1], right);
506 }
507
508 for (int y = top - 1; y >= 0; y--) {
509 ptr[linesize * y] = ptr[linesize * (y + 1)];
510 memcpy(ptr + linesize * y + width - 8, ptr + linesize * (y + 1) + width - 8, 8);
511
512 for (int x = 1; x < width - 8; x++) {
513 int prev = ptr[linesize * (y + 1) + x - 1];
514 int cur = ptr[linesize * (y + 1) + x];
515 int next = ptr[linesize * (y + 1) + x + 1];
516
517 ptr[linesize * y + x] = (3 * prev + 2 * cur + 3 * next + 4) >> 3;
518 }
519 }
520
521 for (int y = height - bottom; y < height; y++) {
522 ptr[linesize * y] = ptr[linesize * (y - 1)];
523 memcpy(ptr + linesize * y + width - 8, ptr + linesize * (y - 1) + width - 8, 8);
524
525 for (int x = 1; x < width - 8; x++) {
526 int prev = ptr[linesize * (y - 1) + x - 1];
527 int cur = ptr[linesize * (y - 1) + x];
528 int next = ptr[linesize * (y - 1) + x + 1];
529
530 ptr[linesize * y + x] = (3 * prev + 2 * cur + 3 * next + 4) >> 3;
531 }
532 }
533 }
534 }
535
536 static void margins_borders16(FillBordersContext *s, AVFrame *frame)
537 {
538 for (int p = 0; p < s->nb_planes; p++) {
539 uint16_t *ptr = (uint16_t *)frame->data[p];
540 const int linesize = frame->linesize[p] / 2;
541 const int left = s->borders[p].left;
542 const int right = s->borders[p].right;
543 const int top = s->borders[p].top;
544 const int bottom = s->borders[p].bottom;
545 const int width = s->planewidth[p];
546 const int height = s->planeheight[p];
547
548 for (int y = top; y < height - bottom; y++) {
549 for (int x = 0; x < left; x++)
550 ptr[linesize * y + x] = ptr[linesize * y + left];
551
552 for (int x = 0; x < right; x++)
553 ptr[linesize * y + width - right + x] = ptr[linesize * y + width - right - 1];
554 }
555
556 for (int y = top - 1; y >= 0; y--) {
557 ptr[linesize * y] = ptr[linesize * (y + 1)];
558 memcpy(ptr + linesize * y + width - 8, ptr + linesize * (y + 1) + width - 8, 16);
559
560 for (int x = 1; x < width - 8; x++) {
561 int prev = ptr[linesize * (y + 1) + x - 1];
562 int cur = ptr[linesize * (y + 1) + x];
563 int next = ptr[linesize * (y + 1) + x + 1];
564
565 ptr[linesize * y + x] = (3 * prev + 2 * cur + 3 * next + 4) >> 3;
566 }
567 }
568
569 for (int y = height - bottom; y < height; y++) {
570 ptr[linesize * y] = ptr[linesize * (y - 1)];
571 memcpy(ptr + linesize * y + width - 8, ptr + linesize * (y - 1) + width - 8, 16);
572
573 for (int x = 1; x < width - 8; x++) {
574 int prev = ptr[linesize * (y - 1) + x - 1];
575 int cur = ptr[linesize * (y - 1) + x];
576 int next = ptr[linesize * (y - 1) + x + 1];
577
578 ptr[linesize * y + x] = (3 * prev + 2 * cur + 3 * next + 4) >> 3;
579 }
580 }
581 }
582 }
583
584 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
585 {
586 FillBordersContext *s = inlink->dst->priv;
587
588 s->fillborders(s, frame);
589
590 return ff_filter_frame(inlink->dst->outputs[0], frame);
591 }
592
593 static int config_input(AVFilterLink *inlink)
594 {
595 AVFilterContext *ctx = inlink->dst;
596 FillBordersContext *s = ctx->priv;
597 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
598
599 s->nb_planes = desc->nb_components;
600 s->depth = desc->comp[0].depth;
601
602 s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
603 s->planeheight[0] = s->planeheight[3] = inlink->h;
604 s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
605 s->planewidth[0] = s->planewidth[3] = inlink->w;
606
607 if (inlink->w < s->left + s->right ||
608 inlink->w <= s->left ||
609 inlink->w <= s->right ||
610 inlink->h < s->top + s->bottom ||
611 inlink->h <= s->top ||
612 inlink->h <= s->bottom ||
613 inlink->w < s->left * 2 ||
614 inlink->w < s->right * 2 ||
615 inlink->h < s->top * 2 ||
616 inlink->h < s->bottom * 2) {
617 av_log(ctx, AV_LOG_ERROR, "Borders are bigger than input frame size.\n");
618 return AVERROR(EINVAL);
619 }
620
621 s->borders[0].left = s->borders[3].left = s->left;
622 s->borders[0].right = s->borders[3].right = s->right;
623 s->borders[0].top = s->borders[3].top = s->top;
624 s->borders[0].bottom = s->borders[3].bottom = s->bottom;
625
626 s->borders[1].left = s->left >> desc->log2_chroma_w;
627 s->borders[1].right = s->right >> desc->log2_chroma_w;
628 s->borders[1].top = s->top >> desc->log2_chroma_h;
629 s->borders[1].bottom = s->bottom >> desc->log2_chroma_h;
630
631 s->borders[2].left = s->left >> desc->log2_chroma_w;
632 s->borders[2].right = s->right >> desc->log2_chroma_w;
633 s->borders[2].top = s->top >> desc->log2_chroma_h;
634 s->borders[2].bottom = s->bottom >> desc->log2_chroma_h;
635
636 switch (s->mode) {
637 case FM_SMEAR: s->fillborders = s->depth <= 8 ? smear_borders8 : smear_borders16; break;
638 case FM_MIRROR: s->fillborders = s->depth <= 8 ? mirror_borders8 : mirror_borders16; break;
639 case FM_FIXED: s->fillborders = s->depth <= 8 ? fixed_borders8 : fixed_borders16; break;
640 case FM_REFLECT:s->fillborders = s->depth <= 8 ? reflect_borders8: reflect_borders16;break;
641 case FM_WRAP: s->fillborders = s->depth <= 8 ? wrap_borders8 : wrap_borders16; break;
642 case FM_FADE: s->fillborders = s->depth <= 8 ? fade_borders8 : fade_borders16; break;
643 case FM_MARGINS:s->fillborders = s->depth <= 8 ? margins_borders8: margins_borders16;break;
644 default: av_assert0(0);
645 }
646
647 s->yuv_color[Y] = RGB_TO_Y_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B]);
648 s->yuv_color[U] = RGB_TO_U_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B], 0);
649 s->yuv_color[V] = RGB_TO_V_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B], 0);
650 s->yuv_color[A] = s->rgba_color[A];
651
652 if (desc->flags & AV_PIX_FMT_FLAG_RGB) {
653 uint8_t rgba_map[4];
654 int i;
655
656 ff_fill_rgba_map(rgba_map, inlink->format);
657 for (i = 0; i < 4; i++)
658 s->fill[rgba_map[i]] = s->rgba_color[i];
659 } else {
660 memcpy(s->fill, s->yuv_color, sizeof(s->yuv_color));
661 }
662
663 return 0;
664 }
665
666 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
667 char *res, int res_len, int flags)
668 {
669 int ret;
670
671 ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
672 if (ret < 0)
673 return ret;
674
675 return config_input(ctx->inputs[0]);
676 }
677
678 #define OFFSET(x) offsetof(FillBordersContext, x)
679 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
680
681 static const AVOption fillborders_options[] = {
682 { "left", "set the left fill border", OFFSET(left), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
683 { "right", "set the right fill border", OFFSET(right), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
684 { "top", "set the top fill border", OFFSET(top), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
685 { "bottom", "set the bottom fill border", OFFSET(bottom), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
686 { "mode", "set the fill borders mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=FM_SMEAR}, 0, FM_NB_MODES-1, FLAGS, "mode" },
687 { "smear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_SMEAR}, 0, 0, FLAGS, "mode" },
688 { "mirror", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_MIRROR}, 0, 0, FLAGS, "mode" },
689 { "fixed", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_FIXED}, 0, 0, FLAGS, "mode" },
690 { "reflect",NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_REFLECT},0, 0, FLAGS, "mode" },
691 { "wrap", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_WRAP}, 0, 0, FLAGS, "mode" },
692 { "fade", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_FADE}, 0, 0, FLAGS, "mode" },
693 { "margins",NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_MARGINS},0, 0, FLAGS, "mode" },
694 { "color", "set the color for the fixed/fade mode", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS },
695 { NULL }
696 };
697
698 AVFILTER_DEFINE_CLASS(fillborders);
699
700 static const AVFilterPad fillborders_inputs[] = {
701 {
702 .name = "default",
703 .type = AVMEDIA_TYPE_VIDEO,
704 .flags = AVFILTERPAD_FLAG_NEEDS_WRITABLE,
705 .config_props = config_input,
706 .filter_frame = filter_frame,
707 },
708 };
709
710 static const AVFilterPad fillborders_outputs[] = {
711 {
712 .name = "default",
713 .type = AVMEDIA_TYPE_VIDEO,
714 },
715 };
716
717 const AVFilter ff_vf_fillborders = {
718 .name = "fillborders",
719 .description = NULL_IF_CONFIG_SMALL("Fill borders of the input video."),
720 .priv_size = sizeof(FillBordersContext),
721 .priv_class = &fillborders_class,
722 FILTER_INPUTS(fillborders_inputs),
723 FILTER_OUTPUTS(fillborders_outputs),
724 FILTER_PIXFMTS_ARRAY(pix_fmts),
725 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
726 .process_command = process_command,
727 };
728