FFmpeg
Loading...
Searching...
No Matches
vf_morpho.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 ReneBrals
3 * Copyright (c) 2021 Paul B Mahol
4 *
5 * This file is part of FFmpeg.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26#include "libavutil/avassert.h"
27#include "libavutil/imgutils.h"
29#include "libavutil/mem.h"
30#include "libavutil/opt.h"
31#include "libavutil/pixdesc.h"
32#include "avfilter.h"
33#include "filters.h"
34#include "framesync.h"
35#include "video.h"
36
47
48typedef struct IPlane {
49 uint8_t **img;
50 int w, h;
51 int range;
52 int depth;
54
55 void (*max_out_place)(uint8_t *c, const uint8_t *a, const uint8_t *b, int x);
56 void (*min_out_place)(uint8_t *c, const uint8_t *a, const uint8_t *b, int x);
57 void (*diff_rin_place)(uint8_t *a, const uint8_t *b, int x);
58 void (*max_in_place)(uint8_t *a, const uint8_t *b, int x);
59 void (*min_in_place)(uint8_t *a, const uint8_t *b, int x);
60 void (*diff_in_place)(uint8_t *a, const uint8_t *b, int x);
61} IPlane;
62
63typedef struct LUT {
64 /* arr is shifted from base_arr by FFMAX(min_r, 0).
65 * arr != NULL means "lut completely allocated" */
66 uint8_t ***arr;
67 uint8_t ***base_arr;
68 int min_r;
69 int max_r;
70 int I;
71 int X;
74} LUT;
75
76typedef struct chord {
77 int x;
78 int y;
79 int l;
80 int i;
81} chord;
82
83typedef struct chord_set {
85 int size;
86 int cap;
87
88 int *R;
89 int Lnum;
90
91 int minX;
92 int maxX;
93 int minY;
94 int maxY;
95 unsigned nb_elements;
96} chord_set;
97
98#define MAX_THREADS 64
99
127
128#define OFFSET(x) offsetof(MorphoContext, x)
129#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM
130
131static const AVOption morpho_options[] = {
132 { "mode", "set morphological transform", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_MODES-1, FLAGS, .unit = "mode" },
133 { "erode", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ERODE}, 0, 0, FLAGS, .unit = "mode" },
134 { "dilate", NULL, 0, AV_OPT_TYPE_CONST, {.i64=DILATE}, 0, 0, FLAGS, .unit = "mode" },
135 { "open", NULL, 0, AV_OPT_TYPE_CONST, {.i64=OPEN}, 0, 0, FLAGS, .unit = "mode" },
136 { "close", NULL, 0, AV_OPT_TYPE_CONST, {.i64=CLOSE}, 0, 0, FLAGS, .unit = "mode" },
137 { "gradient",NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRADIENT},0, 0, FLAGS, .unit = "mode" },
138 { "tophat",NULL, 0, AV_OPT_TYPE_CONST, {.i64=TOPHAT}, 0, 0, FLAGS, .unit = "mode" },
139 { "blackhat",NULL, 0, AV_OPT_TYPE_CONST, {.i64=BLACKHAT},0, 0, FLAGS, .unit = "mode" },
140 { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS },
141 { "structure", "when to process structures", OFFSET(structures), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, .unit = "str" },
142 { "first", "process only first structure, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, .unit = "str" },
143 { "all", "process all structure", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, .unit = "str" },
144 { NULL }
145};
146
148
170
171static void min_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
172{
173 for (int i = 0; i < x; i++)
174 c[i] = FFMIN(b[i], a[i]);
175}
176
177static void mininplace_fun(uint8_t *a, const uint8_t *b, int x)
178{
179 for (int i = 0; i < x; i++)
180 a[i] = FFMIN(a[i], b[i]);
181}
182
183static void max_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
184{
185 for (int i = 0; i < x; i++)
186 c[i] = FFMAX(a[i], b[i]);
187}
188
189static void maxinplace_fun(uint8_t *a, const uint8_t *b, int x)
190{
191 for (int i = 0; i < x; i++)
192 a[i] = FFMAX(a[i], b[i]);
193}
194
195static void diff_fun(uint8_t *a, const uint8_t *b, int x)
196{
197 for (int i = 0; i < x; i++)
198 a[i] = FFMAX(b[i] - a[i], 0);
199}
200
201static void diffinplace_fun(uint8_t *a, const uint8_t *b, int x)
202{
203 for (int i = 0; i < x; i++)
204 a[i] = FFMAX(a[i] - b[i], 0);
205}
206
207static void min16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
208{
209 const uint16_t *a = (const uint16_t *)aa;
210 const uint16_t *b = (const uint16_t *)bb;
211 uint16_t *c = (uint16_t *)cc;
212
213 for (int i = 0; i < x; i++)
214 c[i] = FFMIN(b[i], a[i]);
215}
216
217static void mininplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
218{
219 uint16_t *a = (uint16_t *)aa;
220 const uint16_t *b = (const uint16_t *)bb;
221
222 for (int i = 0; i < x; i++)
223 a[i] = FFMIN(a[i], b[i]);
224}
225
226static void diff16_fun(uint8_t *aa, const uint8_t *bb, int x)
227{
228 const uint16_t *b = (const uint16_t *)bb;
229 uint16_t *a = (uint16_t *)aa;
230
231 for (int i = 0; i < x; i++)
232 a[i] = FFMAX(b[i] - a[i], 0);
233}
234
235static void diffinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
236{
237 uint16_t *a = (uint16_t *)aa;
238 const uint16_t *b = (const uint16_t *)bb;
239
240 for (int i = 0; i < x; i++)
241 a[i] = FFMAX(a[i] - b[i], 0);
242}
243
244static void max16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
245{
246 const uint16_t *a = (const uint16_t *)aa;
247 const uint16_t *b = (const uint16_t *)bb;
248 uint16_t *c = (uint16_t *)cc;
249
250 for (int i = 0; i < x; i++)
251 c[i] = FFMAX(a[i], b[i]);
252}
253
254static void maxinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
255{
256 uint16_t *a = (uint16_t *)aa;
257 const uint16_t *b = (const uint16_t *)bb;
258
259 for (int i = 0; i < x; i++)
260 a[i] = FFMAX(a[i], b[i]);
261}
262
263static int alloc_lut(LUT *Ty, chord_set *SE, int type_size, int mode)
264{
265 const int min = FFMAX(Ty->min_r, 0);
266 const int max = min + (Ty->max_r - Ty->min_r);
267 int pre_pad_x = 0;
268
269 if (SE->minX < 0)
270 pre_pad_x = 0 - SE->minX;
271 Ty->pre_pad_x = pre_pad_x;
272 Ty->type_size = type_size;
273
274 Ty->base_arr = av_calloc(max + 1, sizeof(*Ty->base_arr));
275 if (!Ty->base_arr)
276 return AVERROR(ENOMEM);
277 for (int r = min; r <= max; r++) {
278 uint8_t **arr = Ty->base_arr[r] = av_calloc(Ty->I, sizeof(uint8_t *));
279 if (!Ty->base_arr[r])
280 return AVERROR(ENOMEM);
281 for (int i = 0; i < Ty->I; i++) {
282 arr[i] = av_calloc(Ty->X + pre_pad_x, type_size);
283 if (!arr[i])
284 return AVERROR(ENOMEM);
285 if (mode == ERODE)
286 memset(arr[i], UINT8_MAX, pre_pad_x * type_size);
287 /* Shifting the X index such that negative indices correspond to
288 * the pre-padding.
289 */
290 arr[i] = &(arr[i][pre_pad_x * type_size]);
291 }
292 }
293
294 Ty->arr = &(Ty->base_arr[min - Ty->min_r]);
295
296 return 0;
297}
298
299static void free_lut(LUT *table)
300{
301 const int min = FFMAX(table->min_r, 0);
302 const int max = min + (table->max_r - table->min_r);
303
304 if (!table->base_arr)
305 return;
306
307 for (int r = min; r <= max; r++) {
308 if (!table->base_arr[r])
309 break;
310 for (int i = 0; i < table->I; i++) {
311 if (!table->base_arr[r][i])
312 break;
313 // The X index was also shifted, for padding purposes.
314 av_free(table->base_arr[r][i] - table->pre_pad_x * table->type_size);
315 }
316 av_freep(&table->base_arr[r]);
317 }
318 av_freep(&table->base_arr);
319 table->arr = NULL;
320}
321
323 int num, enum MorphModes mode)
324{
325 if (!Ty->arr || Ty->I != SE->Lnum ||
326 Ty->X != f->w ||
327 SE->minX < 0 && -SE->minX > Ty->pre_pad_x ||
328 Ty->min_r != SE->minY ||
329 Ty->max_r != SE->maxY + num - 1) {
330 int ret;
331
332 free_lut(Ty);
333
334 Ty->I = SE->Lnum;
335 Ty->X = f->w;
336 Ty->min_r = SE->minY;
337 Ty->max_r = SE->maxY + num - 1;
338 ret = alloc_lut(Ty, SE, f->type_size, mode);
339 if (ret < 0)
340 return ret;
341 }
342 return 0;
343}
344
345static void circular_swap(LUT *Ty)
346{
347 /*
348 * Swap the pointers to r-indices in a circle. This is useful because
349 * Ty(r,i,x) = Ty-1(r+1,i,x) for r < ymax.
350 */
351 if (Ty->max_r - Ty->min_r > 0) {
352 uint8_t **Ty0 = Ty->arr[Ty->min_r];
353
354 for (int r = Ty->min_r; r < Ty->max_r; r++)
355 Ty->arr[r] = Ty->arr[r + 1];
356
357 Ty->arr[Ty->max_r] = Ty0;
358 }
359}
360
361static void compute_min_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
362{
363 if (y + r >= 0 && y + r < f->h) {
364 memcpy(Ty->arr[r][0], f->img[y + r], Ty->X * Ty->type_size);
365 } else {
366 memset(Ty->arr[r][0], UINT8_MAX, Ty->X * Ty->type_size);
367 }
368
369 for (int i = 1; i < SE->Lnum; i++) {
370 int d = SE->R[i] - SE->R[i - 1];
371
372 f->min_out_place(Ty->arr[r][i] - Ty->pre_pad_x * f->type_size,
373 Ty->arr[r][i - 1] - Ty->pre_pad_x * f->type_size,
374 Ty->arr[r][i - 1] + (d - Ty->pre_pad_x) * f->type_size,
375 Ty->X + Ty->pre_pad_x - d);
376 memcpy(Ty->arr[r][i] + (Ty->X - d) * f->type_size,
377 Ty->arr[r][i - 1] + (Ty->X - d) * f->type_size,
378 d * f->type_size);
379 }
380}
381
382static void update_min_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
383{
384 for (int i = 0; i < num; i++)
385 circular_swap(Ty);
386
387 compute_min_row(f, Ty, SE, Ty->max_r - tid, y);
388}
389
390static int compute_min_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
391{
392 int ret = alloc_lut_if_necessary(Ty, f, SE, num, ERODE);
393 if (ret < 0)
394 return ret;
395
396 for (int r = Ty->min_r; r <= Ty->max_r; r++)
397 compute_min_row(f, Ty, SE, r, y);
398
399 return 0;
400}
401
402static void compute_max_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
403{
404 if (y + r >= 0 && y + r < f->h) {
405 memcpy(Ty->arr[r][0], f->img[y + r], Ty->X * Ty->type_size);
406 } else {
407 memset(Ty->arr[r][0], 0, Ty->X * Ty->type_size);
408 }
409
410 for (int i = 1; i < SE->Lnum; i++) {
411 int d = SE->R[i] - SE->R[i - 1];
412
413 f->max_out_place(Ty->arr[r][i] - Ty->pre_pad_x * f->type_size,
414 Ty->arr[r][i - 1] - Ty->pre_pad_x * f->type_size,
415 Ty->arr[r][i - 1] + (d - Ty->pre_pad_x) * f->type_size,
416 Ty->X + Ty->pre_pad_x - d);
417 memcpy(Ty->arr[r][i] + (Ty->X - d) * f->type_size,
418 Ty->arr[r][i - 1] + (Ty->X - d) * f->type_size,
419 d * f->type_size);
420 }
421}
422
423static void update_max_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
424{
425 for (int i = 0; i < num; i++)
426 circular_swap(Ty);
427
428 compute_max_row(f, Ty, SE, Ty->max_r - tid, y);
429}
430
431static int compute_max_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
432{
433 int ret = alloc_lut_if_necessary(Ty, f, SE, num, DILATE);
434 if (ret < 0)
435 return ret;
436
437 for (int r = Ty->min_r; r <= Ty->max_r; r++)
438 compute_max_row(f, Ty, SE, r, y);
439
440 return 0;
441}
442
443static void line_dilate(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
444{
445 memset(g->img[y], 0, g->w * g->type_size);
446
447 for (int c = 0; c < SE->size; c++) {
448 g->max_in_place(g->img[y],
449 Ty->arr[SE->C[c].y + tid][SE->C[c].i] + SE->C[c].x * Ty->type_size,
450 av_clip(g->w - SE->C[c].x, 0, g->w));
451 }
452}
453
454static void line_erode(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
455{
456 memset(g->img[y], UINT8_MAX, g->w * g->type_size);
457
458 for (int c = 0; c < SE->size; c++) {
459 g->min_in_place(g->img[y],
460 Ty->arr[SE->C[c].y + tid][SE->C[c].i] + SE->C[c].x * Ty->type_size,
461 av_clip(g->w - SE->C[c].x, 0, g->w));
462 }
463}
464
465static int dilate(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty, int y0, int y1)
466{
467 int ret = compute_max_lut(Ty, f, SE, y0, 1);
468 if (ret < 0)
469 return ret;
470
471 line_dilate(g, Ty, SE, y0, 0);
472 for (int y = y0 + 1; y < y1; y++) {
473 update_max_lut(f, Ty, SE, y, 0, 1);
474 line_dilate(g, Ty, SE, y, 0);
475 }
476
477 return 0;
478}
479
480static int erode(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty, int y0, int y1)
481{
482 int ret = compute_min_lut(Ty, f, SE, y0, 1);
483 if (ret < 0)
484 return ret;
485
486 line_erode(g, Ty, SE, y0, 0);
487 for (int y = y0 + 1; y < y1; y++) {
488 update_min_lut(f, Ty, SE, y, 0, 1);
489 line_erode(g, Ty, SE, y, 0);
490 }
491
492 return 0;
493}
494
495static void difference(IPlane *g, IPlane *f, int y0, int y1)
496{
497 for (int y = y0; y < y1; y++)
498 f->diff_in_place(g->img[y], f->img[y], f->w);
499}
500
501static void difference2(IPlane *g, IPlane *f, int y0, int y1)
502{
503 for (int y = y0; y < y1; y++)
504 f->diff_rin_place(g->img[y], f->img[y], f->w);
505}
506
507static int insert_chord_set(chord_set *chords, chord c)
508{
509 // Checking if chord fits in dynamic array, resize if not.
510 if (chords->size == chords->cap) {
511 chords->C = av_realloc_f(chords->C, chords->cap * 2, sizeof(chord));
512 if (!chords->C)
513 return AVERROR(ENOMEM);
514 chords->cap *= 2;
515 }
516
517 // Add the chord to the dynamic array.
518 chords->C[chords->size].x = c.x;
519 chords->C[chords->size].y = c.y;
520 chords->C[chords->size++].l = c.l;
521
522 // Update minimum/maximum x/y offsets of the chord set.
523 chords->minX = FFMIN(chords->minX, c.x);
524 chords->maxX = FFMAX(chords->maxX, c.x);
525
526 chords->minY = FFMIN(chords->minY, c.y);
527 chords->maxY = FFMAX(chords->maxY, c.y);
528
529 return 0;
530}
531
533{
534 av_freep(&SE->C);
535 SE->size = 0;
536 SE->cap = 0;
537
538 av_freep(&SE->R);
539 SE->Lnum = 0;
540}
541
542static int init_chordset(chord_set *chords)
543{
544 chords->nb_elements = 0;
545 chords->size = 0;
546 chords->C = av_calloc(1, sizeof(chord));
547 if (!chords->C)
548 return AVERROR(ENOMEM);
549
550 chords->cap = 1;
551 chords->minX = INT16_MAX;
552 chords->maxX = INT16_MIN;
553 chords->minY = INT16_MAX;
554 chords->maxY = INT16_MIN;
555
556 return 0;
557}
558
559static int comp_chord_length(const void *p, const void *q)
560{
561 chord a, b;
562 a = *((chord *)p);
563 b = *((chord *)q);
564
565 return (a.l > b.l) - (a.l < b.l);
566}
567
568static int comp_chord(const void *p, const void *q)
569{
570 chord a, b;
571 a = *((chord *)p);
572 b = *((chord *)q);
573
574 return (a.y > b.y) - (a.y < b.y);
575}
576
577static int build_chord_set(IPlane *SE, chord_set *chords)
578{
579 const int mid = 1 << (SE->depth - 1);
580 int chord_length_index;
581 int chord_start, val, ret;
582 int centerX, centerY;
583 int r_cap = 1;
584 chord c;
585
586 ret = init_chordset(chords);
587 if (ret < 0)
588 return ret;
589 /*
590 * In erosion/dilation, the center of the IPlane has S.E. offset (0,0).
591 * Otherwise, the resulting IPlane would be shifted to the top-left.
592 */
593 centerX = (SE->w - 1) / 2;
594 centerY = (SE->h - 1) / 2;
595
596 /*
597 * Computing the set of chords C.
598 */
599 for (int y = 0; y < SE->h; y++) {
600 int x;
601
602 chord_start = -1;
603 for (x = 0; x < SE->w; x++) {
604 if (SE->type_size == 1) {
605 chords->nb_elements += (SE->img[y][x] >= mid);
606 //A chord is a run of non-zero pixels.
607 if (SE->img[y][x] >= mid && chord_start == -1) {
608 // Chord starts.
609 chord_start = x;
610 } else if (SE->img[y][x] < mid && chord_start != -1) {
611 // Chord ends before end of line.
612 c.x = chord_start - centerX;
613 c.y = y - centerY;
614 c.l = x - chord_start;
615 ret = insert_chord_set(chords, c);
616 if (ret < 0)
617 return AVERROR(ENOMEM);
618 chord_start = -1;
619 }
620 } else {
621 chords->nb_elements += (AV_RN16(&SE->img[y][x * 2]) >= mid);
622 //A chord is a run of non-zero pixels.
623 if (AV_RN16(&SE->img[y][x * 2]) >= mid && chord_start == -1) {
624 // Chord starts.
625 chord_start = x;
626 } else if (AV_RN16(&SE->img[y][x * 2]) < mid && chord_start != -1) {
627 // Chord ends before end of line.
628 c.x = chord_start - centerX;
629 c.y = y - centerY;
630 c.l = x - chord_start;
631 ret = insert_chord_set(chords, c);
632 if (ret < 0)
633 return AVERROR(ENOMEM);
634 chord_start = -1;
635 }
636 }
637 }
638 if (chord_start != -1) {
639 // Chord ends at end of line.
640 c.x = chord_start - centerX;
641 c.y = y - centerY;
642 c.l = x - chord_start;
643 ret = insert_chord_set(chords, c);
644 if (ret < 0)
645 return AVERROR(ENOMEM);
646 }
647 }
648
649 /*
650 * Computing the array of chord lengths R(i).
651 * This is needed because the lookup table will contain a row for each
652 * length index i.
653 */
654 qsort(chords->C, chords->size, sizeof(chord), comp_chord_length);
655 chords->R = av_calloc(1, sizeof(*chords->R));
656 if (!chords->R)
657 return AVERROR(ENOMEM);
658 chords->Lnum = 0;
659 val = 0;
660 r_cap = 1;
661
662 if (chords->size > 0) {
663 val = 1;
664 if (chords->Lnum >= r_cap) {
665 chords->R = av_realloc_f(chords->R, r_cap * 2, sizeof(*chords->R));
666 if (!chords->R)
667 return AVERROR(ENOMEM);
668 r_cap *= 2;
669 }
670 chords->R[chords->Lnum++] = 1;
671 val = 1;
672 }
673
674 for (int i = 0; i < chords->size; i++) {
675 if (val != chords->C[i].l) {
676 while (2 * val < chords->C[i].l && val != 0) {
677 if (chords->Lnum >= r_cap) {
678 chords->R = av_realloc_f(chords->R, r_cap * 2, sizeof(*chords->R));
679 if (!chords->R)
680 return AVERROR(ENOMEM);
681 r_cap *= 2;
682 }
683
684 chords->R[chords->Lnum++] = 2 * val;
685 val *= 2;
686 }
687 val = chords->C[i].l;
688
689 if (chords->Lnum >= r_cap) {
690 chords->R = av_realloc_f(chords->R, r_cap * 2, sizeof(*chords->R));
691 if (!chords->R)
692 return AVERROR(ENOMEM);
693 r_cap *= 2;
694 }
695 chords->R[chords->Lnum++] = val;
696 }
697 }
698
699 /*
700 * Setting the length indices of chords.
701 * These are needed so that the algorithm can, for each chord,
702 * access the lookup table at the correct length in constant time.
703 */
704 chord_length_index = 0;
705 for (int i = 0; i < chords->size; i++) {
706 while (chords->R[chord_length_index] < chords->C[i].l)
707 chord_length_index++;
708 chords->C[i].i = chord_length_index;
709 }
710
711 /*
712 * Chords are sorted on Y. This way, when a row of the lookup table or IPlane
713 * is cached, the next chord offset has a better chance of being on the
714 * same cache line.
715 */
716 qsort(chords->C, chords->size, sizeof(chord), comp_chord);
717
718 return 0;
719}
720
721static void free_iplane(IPlane *imp)
722{
723 av_freep(&imp->img);
724}
725
726static int read_iplane(IPlane *imp, const uint8_t *dst, int dst_linesize,
727 int w, int h, int R, int type_size, int depth)
728{
729 if (!imp->img)
730 imp->img = av_calloc(h, sizeof(*imp->img));
731 if (!imp->img)
732 return AVERROR(ENOMEM);
733
734 imp->w = w;
735 imp->h = h;
736 imp->range = R;
737 imp->depth = depth;
738 imp->type_size = type_size;
739 imp->max_out_place = type_size == 1 ? max_fun : max16_fun;
740 imp->min_out_place = type_size == 1 ? min_fun : min16_fun;
741 imp->diff_rin_place = type_size == 1 ? diff_fun : diff16_fun;
742 imp->max_in_place = type_size == 1 ? maxinplace_fun : maxinplace16_fun;
743 imp->min_in_place = type_size == 1 ? mininplace_fun : mininplace16_fun;
744 imp->diff_in_place = type_size == 1 ? diffinplace_fun : diffinplace16_fun;
745
746 for (int y = 0; y < h; y++)
747 imp->img[y] = (uint8_t *)dst + y * dst_linesize;
748
749 return 0;
750}
751
752static int config_input(AVFilterLink *inlink)
753{
755 MorphoContext *s = inlink->dst->priv;
756
757 s->depth = desc->comp[0].depth;
758 s->type_size = (s->depth + 7) / 8;
759 s->nb_planes = desc->nb_components;
760 s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
761 s->planewidth[0] = s->planewidth[3] = inlink->w;
762 s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
763 s->planeheight[0] = s->planeheight[3] = inlink->h;
764
765 return 0;
766}
767
769{
771 AVFilterContext *ctx = inlink->dst;
772 MorphoContext *s = inlink->dst->priv;
773
774 av_assert0(ctx->inputs[0]->format == ctx->inputs[1]->format);
775
776 s->splanewidth[1] = s->splanewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
777 s->splanewidth[0] = s->splanewidth[3] = inlink->w;
778 s->splaneheight[1] = s->splaneheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
779 s->splaneheight[0] = s->splaneheight[3] = inlink->h;
780
781 return 0;
782}
783
785{
786 MorphoContext *s = ctx->priv;
787 return ff_framesync_activate(&s->fs);
788}
789
790typedef struct ThreadData {
791 AVFrame *in, *out;
792} ThreadData;
793
794static int morpho_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
795{
796 MorphoContext *s = ctx->priv;
797 ThreadData *td = arg;
798 AVFrame *out = td->out;
799 AVFrame *in = td->in;
800 int ret;
801
802 for (int p = 0; p < s->nb_planes; p++) {
803 const int width = s->planewidth[p];
804 const int height = s->planeheight[p];
805 const int y0 = ff_slice_pos(height, jobnr, nb_jobs);
806 const int y1 = ff_slice_pos(height, jobnr + 1, nb_jobs);
807 const int depth = s->depth;
808
809 if (ctx->is_disabled || !(s->planes & (1 << p))) {
810copy:
811 av_image_copy_plane(out->data[p] + y0 * out->linesize[p],
812 out->linesize[p],
813 in->data[p] + y0 * in->linesize[p],
814 in->linesize[p],
815 width * ((depth + 7) / 8),
816 y1 - y0);
817 continue;
818 }
819
820 if (s->SE[p].minX == INT16_MAX ||
821 s->SE[p].minY == INT16_MAX ||
822 s->SE[p].maxX == INT16_MIN ||
823 s->SE[p].maxY == INT16_MIN)
824 goto copy;
825
826 switch (s->mode) {
827 case ERODE:
828 ret = erode(&s->g[p], &s->f[p], &s->SE[p], &s->Ty[jobnr][0][p], y0, y1);
829 break;
830 case DILATE:
831 case GRADIENT:
832 ret = dilate(&s->g[p], &s->f[p], &s->SE[p], &s->Ty[jobnr][0][p], y0, y1);
833 break;
834 case OPEN:
835 case TOPHAT:
836 ret = erode(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[jobnr][0][p], y0, y1);
837 break;
838 case CLOSE:
839 case BLACKHAT:
840 ret = dilate(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[jobnr][0][p], y0, y1);
841 break;
842 default:
843 av_assert0(0);
844 }
845
846 if (ret < 0)
847 return ret;
848 }
849
850 return 0;
851}
852
853static int morpho_sliceX(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
854{
855 MorphoContext *s = ctx->priv;
856 int ret;
857
858 for (int p = 0; p < s->nb_planes; p++) {
859 const int height = s->planeheight[p];
860 const int y0 = ff_slice_pos(height, jobnr, nb_jobs);
861 const int y1 = ff_slice_pos(height, jobnr + 1, nb_jobs);
862
863 if (ctx->is_disabled || !(s->planes & (1 << p))) {
864copy:
865 continue;
866 }
867
868 if (s->SE[p].minX == INT16_MAX ||
869 s->SE[p].minY == INT16_MAX ||
870 s->SE[p].maxX == INT16_MIN ||
871 s->SE[p].maxY == INT16_MIN)
872 goto copy;
873
874 switch (s->mode) {
875 case OPEN:
876 ret = dilate(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[jobnr][1][p], y0, y1);
877 break;
878 case CLOSE:
879 ret = erode(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[jobnr][1][p], y0, y1);
880 break;
881 case GRADIENT:
882 ret = erode(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[jobnr][1][p], y0, y1);
883 if (ret < 0)
884 break;
885 difference(&s->g[p], &s->h[p], y0, y1);
886 break;
887 case TOPHAT:
888 ret = dilate(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[jobnr][1][p], y0, y1);
889 if (ret < 0)
890 break;
891 difference2(&s->g[p], &s->f[p], y0, y1);
892 break;
893 case BLACKHAT:
894 ret = erode(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[jobnr][1][p], y0, y1);
895 if (ret < 0)
896 break;
897 difference(&s->g[p], &s->f[p], y0, y1);
898 break;
899 default:
900 av_assert0(0);
901 }
902
903 if (ret < 0)
904 return ret;
905 }
906
907 return 0;
908}
909
911{
912 AVFilterContext *ctx = fs->parent;
913 AVFilterLink *outlink = ctx->outputs[0];
914 MorphoContext *s = ctx->priv;
915 AVFrame *in = NULL, *structurepic = NULL;
916 ThreadData td;
917 AVFrame *out;
918 int ret;
919
920 ret = ff_framesync_dualinput_get(fs, &in, &structurepic);
921 if (ret < 0)
922 return ret;
923 if (!structurepic)
924 return ff_filter_frame(outlink, in);
925
926 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
927 if (!out) {
928 av_frame_free(&in);
929 return AVERROR(ENOMEM);
930 }
932
933 for (int p = 0; p < s->nb_planes; p++) {
934 const uint8_t *ssrc = structurepic->data[p];
935 const int ssrc_linesize = structurepic->linesize[p];
936 const int swidth = s->splanewidth[p];
937 const int sheight = s->splaneheight[p];
938 const uint8_t *src = in->data[p];
939 int src_linesize = in->linesize[p];
940 uint8_t *dst = out->data[p];
941 int dst_linesize = out->linesize[p];
942 const int width = s->planewidth[p];
943 const int height = s->planeheight[p];
944 const int depth = s->depth;
945 int type_size = s->type_size;
946
947 if (!s->got_structure[p] || s->structures) {
948 free_chord_set(&s->SE[p]);
949
950 ret = read_iplane(&s->SEimg[p], ssrc, ssrc_linesize, swidth, sheight, 1, type_size, depth);
951 if (ret < 0)
952 goto fail;
953 ret = build_chord_set(&s->SEimg[p], &s->SE[p]);
954 if (ret < 0)
955 goto fail;
956 s->got_structure[p] = 1;
957 }
958
959 ret = read_iplane(&s->f[p], src, src_linesize, width, height, 1, type_size, depth);
960 if (ret < 0)
961 goto fail;
962
963 ret = read_iplane(&s->g[p], dst, dst_linesize, s->f[p].w, s->f[p].h, s->f[p].range, type_size, depth);
964 if (ret < 0)
965 goto fail;
966
967 switch (s->mode) {
968 case OPEN:
969 case CLOSE:
970 case GRADIENT:
971 case TOPHAT:
972 case BLACKHAT:
973 ret = read_iplane(&s->h[p], s->temp->data[p], s->temp->linesize[p], width, height, 1, type_size, depth);
974 break;
975 }
976
977 if (ret < 0)
978 goto fail;
979 }
980
981 td.in = in; td.out = out;
983 FFMIN3(s->planeheight[1], s->planeheight[2],
985 if (ret == 0 && (s->mode != ERODE && s->mode != DILATE)) {
987 FFMIN3(s->planeheight[1], s->planeheight[2],
989 }
990
991 av_frame_free(&in);
992 out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base);
993 return ff_filter_frame(outlink, out);
994fail:
996 av_frame_free(&in);
997 return ret;
998}
999
1000static int config_output(AVFilterLink *outlink)
1001{
1002 AVFilterContext *ctx = outlink->src;
1003 MorphoContext *s = ctx->priv;
1004 AVFilterLink *mainlink = ctx->inputs[0];
1005 FilterLink *il = ff_filter_link(mainlink);
1006 FilterLink *ol = ff_filter_link(outlink);
1007 int ret;
1008
1009 s->fs.on_event = do_morpho;
1010 ret = ff_framesync_init_dualinput(&s->fs, ctx);
1011 if (ret < 0)
1012 return ret;
1013 outlink->w = mainlink->w;
1014 outlink->h = mainlink->h;
1015 outlink->time_base = mainlink->time_base;
1016 outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
1017 ol->frame_rate = il->frame_rate;
1018
1019 if ((ret = ff_framesync_configure(&s->fs)) < 0)
1020 return ret;
1021 outlink->time_base = s->fs.time_base;
1022
1023 s->temp = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1024 if (!s->temp)
1025 return AVERROR(ENOMEM);
1026
1027 s->plane_f = av_calloc(outlink->w * outlink->h, sizeof(*s->plane_f));
1028 s->plane_g = av_calloc(outlink->w * outlink->h, sizeof(*s->plane_g));
1029 if (!s->plane_f || !s->plane_g)
1030 return AVERROR(ENOMEM);
1031
1032 return 0;
1033}
1034
1036{
1037 MorphoContext *s = ctx->priv;
1038
1039 for (int p = 0; p < 4; p++) {
1040 free_iplane(&s->SEimg[p]);
1041 free_iplane(&s->f[p]);
1042 free_iplane(&s->g[p]);
1043 free_iplane(&s->h[p]);
1044 free_chord_set(&s->SE[p]);
1045 for (int n = 0; n < MAX_THREADS; n++) {
1046 free_lut(&s->Ty[n][0][p]);
1047 free_lut(&s->Ty[n][1][p]);
1048 }
1049 }
1050
1051 ff_framesync_uninit(&s->fs);
1052
1053 av_frame_free(&s->temp);
1054 av_freep(&s->plane_f);
1055 av_freep(&s->plane_g);
1056}
1057
1058static const AVFilterPad morpho_inputs[] = {
1059 {
1060 .name = "default",
1061 .type = AVMEDIA_TYPE_VIDEO,
1062 .config_props = config_input,
1063 },
1064 {
1065 .name = "structure",
1066 .type = AVMEDIA_TYPE_VIDEO,
1067 .config_props = config_input_structure,
1068 },
1069};
1070
1071static const AVFilterPad morpho_outputs[] = {
1072 {
1073 .name = "default",
1074 .type = AVMEDIA_TYPE_VIDEO,
1075 .config_props = config_output,
1076 },
1077};
1078
1080 .p.name = "morpho",
1081 .p.description = NULL_IF_CONFIG_SMALL("Apply Morphological filter."),
1082 .p.priv_class = &morpho_class,
1085 .preinit = morpho_framesync_preinit,
1086 .priv_size = sizeof(MorphoContext),
1087 .activate = activate,
1088 .uninit = uninit,
1092 .process_command = ff_filter_process_command,
1093};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static double val(void *priv, double ch)
Definition aeval.c:77
static int config_input(AVFilterLink *inlink)
@ NB_MODES
Definition af_afftdn.c:48
const FFFilter ff_vf_morpho
Definition vf_morpho.c:1079
static FILE * out
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition avfilter.c:906
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition avfilter.c:1696
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition avfilter.c:846
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
#define s(width, name)
Definition cbs_vp9.c:198
#define fs(width, name, subs,...)
Definition cbs_vp9.c:200
#define FLAGS
Definition cmdutils.c:598
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define av_clip
Definition common.h:100
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define min(a, b)
#define max(a, b)
#define SE
Definition dvbsubenc.c:531
#define MAX_THREADS
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition framesync.c:137
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition framesync.c:390
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition framesync.c:352
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition framesync.c:372
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition framesync.c:301
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
Definition framesync.h:352
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition avfilter.h:166
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition avfilter.h:204
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition imgutils.c:374
int a
#define R
Definition huffyuv.h:44
misc image utilities
#define r
Definition input.c:42
#define b
Definition input.c:43
#define AV_RN16(p)
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
#define C
const char * arg
Definition jacosubdec.c:65
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
Definition filters.h:763
#define FILTER_PIXFMTS_ARRAY(array)
Definition filters.h:244
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static enum AVPixelFormat pix_fmts[]
Definition libkvazaar.c:296
const char * desc
Definition libsvtav1.c:83
static const struct @257111027162314367033347246032313251342043035002 planes[]
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
#define FFMIN3(a, b, c)
Definition macros.h:50
@ GRADIENT
Definition magicyuv.c:47
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_GBRAP12
Definition pixfmt.h:569
#define AV_PIX_FMT_YUV420P16
Definition pixfmt.h:556
#define AV_PIX_FMT_YUV444P12
Definition pixfmt.h:552
#define AV_PIX_FMT_YUV444P9
Definition pixfmt.h:544
#define AV_PIX_FMT_YUV420P10
Definition pixfmt.h:545
#define AV_PIX_FMT_YUV440P12
Definition pixfmt.h:551
#define AV_PIX_FMT_GRAY9
Definition pixfmt.h:524
#define AV_PIX_FMT_GBRAP16
Definition pixfmt.h:571
#define AV_PIX_FMT_GBRP9
Definition pixfmt.h:563
#define AV_PIX_FMT_YUV422P9
Definition pixfmt.h:543
#define AV_PIX_FMT_YUVA444P10
Definition pixfmt.h:598
#define AV_PIX_FMT_YUVA420P16
Definition pixfmt.h:601
#define AV_PIX_FMT_YUV420P12
Definition pixfmt.h:549
#define AV_PIX_FMT_YUVA420P10
Definition pixfmt.h:596
#define AV_PIX_FMT_YUVA422P9
Definition pixfmt.h:594
#define AV_PIX_FMT_YUV422P12
Definition pixfmt.h:550
#define AV_PIX_FMT_GBRP10
Definition pixfmt.h:564
#define AV_PIX_FMT_YUV422P10
Definition pixfmt.h:546
#define AV_PIX_FMT_GRAY12
Definition pixfmt.h:526
#define AV_PIX_FMT_GBRP12
Definition pixfmt.h:565
#define AV_PIX_FMT_YUV420P9
Definition pixfmt.h:542
#define AV_PIX_FMT_YUVA420P9
Definition pixfmt.h:593
#define AV_PIX_FMT_YUVA422P10
Definition pixfmt.h:597
#define AV_PIX_FMT_YUV420P14
Definition pixfmt.h:553
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition pixfmt.h:106
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition pixfmt.h:108
@ AV_PIX_FMT_YUVJ440P
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range
Definition pixfmt.h:107
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition pixfmt.h:79
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition pixfmt.h:80
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition pixfmt.h:174
@ AV_PIX_FMT_YUVJ411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
Definition pixfmt.h:283
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition pixfmt.h:212
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition pixfmt.h:86
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition pixfmt.h:173
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition pixfmt.h:165
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition pixfmt.h:87
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition pixfmt.h:85
#define AV_PIX_FMT_YUVA422P12
Definition pixfmt.h:599
#define AV_PIX_FMT_YUV422P14
Definition pixfmt.h:554
#define AV_PIX_FMT_GRAY10
Definition pixfmt.h:525
#define AV_PIX_FMT_GRAY14
Definition pixfmt.h:527
#define AV_PIX_FMT_YUV422P16
Definition pixfmt.h:557
#define AV_PIX_FMT_GRAY16
Definition pixfmt.h:528
#define AV_PIX_FMT_GBRAP10
Definition pixfmt.h:568
#define AV_PIX_FMT_YUVA444P16
Definition pixfmt.h:603
#define AV_PIX_FMT_YUVA422P16
Definition pixfmt.h:602
#define AV_PIX_FMT_GBRP16
Definition pixfmt.h:567
#define AV_PIX_FMT_YUV444P14
Definition pixfmt.h:555
#define AV_PIX_FMT_YUVA444P9
Definition pixfmt.h:595
#define AV_PIX_FMT_GBRP14
Definition pixfmt.h:566
#define AV_PIX_FMT_YUVA444P12
Definition pixfmt.h:600
#define AV_PIX_FMT_YUV444P16
Definition pixfmt.h:558
#define AV_PIX_FMT_YUV444P10
Definition pixfmt.h:548
static const uint16_t table[]
Definition prosumer.c:203
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
void * priv
private data for use by the filter
Definition avfilter.h:288
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition frame.h:517
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
Frame sync structure.
Definition framesync.h:168
int type_size
Definition vf_morpho.c:53
void(* max_in_place)(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:58
void(* max_out_place)(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:55
int depth
Definition vf_morpho.c:52
void(* min_in_place)(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:59
int h
Definition vf_morpho.c:50
void(* diff_in_place)(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:60
void(* diff_rin_place)(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:57
int range
Definition vf_morpho.c:51
void(* min_out_place)(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:56
int w
Definition vf_morpho.c:50
uint8_t ** img
Definition vf_morpho.c:49
uint8_t *** arr
Definition vf_morpho.c:66
int I
Definition vf_morpho.c:70
int max_r
Definition vf_morpho.c:69
int type_size
Definition vf_morpho.c:73
int pre_pad_x
Definition vf_morpho.c:72
int X
Definition vf_morpho.c:71
uint8_t *** base_arr
Definition vf_morpho.c:67
int min_r
Definition vf_morpho.c:68
IPlane g[4]
Definition vf_morpho.c:106
LUT Ty[MAX_THREADS][2][4]
Definition vf_morpho.c:107
IPlane f[4]
Definition vf_morpho.c:106
int splanewidth[4]
Definition vf_morpho.c:115
IPlane SEimg[4]
Definition vf_morpho.c:105
int64_t * plane_g
Definition vf_morpho.c:125
int64_t * plane_f
Definition vf_morpho.c:125
int got_structure[4]
Definition vf_morpho.c:121
int splaneheight[4]
Definition vf_morpho.c:116
int planewidth[4]
Definition vf_morpho.c:113
FFFrameSync fs
Definition vf_morpho.c:102
IPlane h[4]
Definition vf_morpho.c:106
chord_set SE[4]
Definition vf_morpho.c:104
AVFrame * temp
Definition vf_morpho.c:123
int planeheight[4]
Definition vf_morpho.c:114
Used for passing data between threads.
Definition dsddec.c:71
AVFrame * out
int * R
Definition vf_morpho.c:88
unsigned nb_elements
Definition vf_morpho.c:95
chord * C
Definition vf_morpho.c:84
int x
Definition vf_morpho.c:77
int l
Definition vf_morpho.c:79
int y
Definition vf_morpho.c:78
int i
Definition vf_morpho.c:80
Definition swscale.c:71
#define av_free(p)
#define av_realloc_f(p, o, n)
#define av_freep(p)
#define src
Definition vp8dsp.c:248
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
const char * g
Definition vf_curves.c:128
static void update_min_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
Definition vf_morpho.c:382
static int insert_chord_set(chord_set *chords, chord c)
Definition vf_morpho.c:507
static void min16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
Definition vf_morpho.c:207
static int compute_max_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
Definition vf_morpho.c:431
static void compute_max_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
Definition vf_morpho.c:402
static int alloc_lut_if_necessary(LUT *Ty, IPlane *f, chord_set *SE, int num, enum MorphModes mode)
Definition vf_morpho.c:322
static const AVFilterPad morpho_inputs[]
Definition vf_morpho.c:1058
MorphModes
Definition vf_morpho.c:37
@ OPEN
Definition vf_morpho.c:40
@ BLACKHAT
Definition vf_morpho.c:44
@ ERODE
Definition vf_morpho.c:38
@ CLOSE
Definition vf_morpho.c:41
@ DILATE
Definition vf_morpho.c:39
@ TOPHAT
Definition vf_morpho.c:43
static int erode(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty, int y0, int y1)
Definition vf_morpho.c:480
static void free_chord_set(chord_set *SE)
Definition vf_morpho.c:532
static void line_dilate(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
Definition vf_morpho.c:443
static int comp_chord(const void *p, const void *q)
Definition vf_morpho.c:568
static void update_max_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
Definition vf_morpho.c:423
static void maxinplace_fun(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:189
static int read_iplane(IPlane *imp, const uint8_t *dst, int dst_linesize, int w, int h, int R, int type_size, int depth)
Definition vf_morpho.c:726
static int init_chordset(chord_set *chords)
Definition vf_morpho.c:542
static void diff16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition vf_morpho.c:226
static int config_input(AVFilterLink *inlink)
Definition vf_morpho.c:752
static void difference(IPlane *g, IPlane *f, int y0, int y1)
Definition vf_morpho.c:495
static int morpho_sliceX(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_morpho.c:853
static void free_iplane(IPlane *imp)
Definition vf_morpho.c:721
static void diffinplace_fun(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:201
static int do_morpho(FFFrameSync *fs)
Definition vf_morpho.c:910
static void diffinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition vf_morpho.c:235
static int compute_min_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
Definition vf_morpho.c:390
static void mininplace_fun(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:177
#define MAX_THREADS
Definition vf_morpho.c:98
static int build_chord_set(IPlane *SE, chord_set *chords)
Definition vf_morpho.c:577
static void line_erode(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
Definition vf_morpho.c:454
static void mininplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition vf_morpho.c:217
static const AVOption morpho_options[]
Definition vf_morpho.c:131
static const AVFilterPad morpho_outputs[]
Definition vf_morpho.c:1071
static int alloc_lut(LUT *Ty, chord_set *SE, int type_size, int mode)
Definition vf_morpho.c:263
static int dilate(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty, int y0, int y1)
Definition vf_morpho.c:465
static int activate(AVFilterContext *ctx)
Definition vf_morpho.c:784
static av_cold void uninit(AVFilterContext *ctx)
Definition vf_morpho.c:1035
static void difference2(IPlane *g, IPlane *f, int y0, int y1)
Definition vf_morpho.c:501
#define OFFSET(x)
Definition vf_morpho.c:128
static void max_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:183
static int config_output(AVFilterLink *outlink)
Definition vf_morpho.c:1000
static int comp_chord_length(const void *p, const void *q)
Definition vf_morpho.c:559
static void diff_fun(uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:195
static void compute_min_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
Definition vf_morpho.c:361
static void maxinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition vf_morpho.c:254
static int morpho_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_morpho.c:794
static int config_input_structure(AVFilterLink *inlink)
Definition vf_morpho.c:768
static void circular_swap(LUT *Ty)
Definition vf_morpho.c:345
static void min_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition vf_morpho.c:171
static void max16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
Definition vf_morpho.c:244
static void free_lut(LUT *table)
Definition vf_morpho.c:299
static void copy(const float *p1, float *p2, const int length)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89
static double c[64]