FFmpeg
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"
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/pixdesc.h"
31 #include "avfilter.h"
32 #include "formats.h"
33 #include "framesync.h"
34 #include "internal.h"
35 #include "video.h"
36 
37 enum MorphModes {
46 };
47 
48 typedef struct IPlane {
49  uint8_t **img;
50  int w, h;
51  int range;
52  int depth;
53  int type_size;
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 
63 typedef 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;
72  int pre_pad_x;
73  int type_size;
74 } LUT;
75 
76 typedef struct chord {
77  int x;
78  int y;
79  int l;
80  int i;
81 } chord;
82 
83 typedef struct chord_set {
84  chord *C;
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 typedef struct MorphoContext {
99  const AVClass *class;
101 
104  IPlane g[4], f[4], h[4];
105  LUT Ty[2][4];
106 
107  int mode;
108  int planes;
110 
111  int planewidth[4];
112  int planeheight[4];
113  int splanewidth[4];
114  int splaneheight[4];
115  int depth;
118 
120 
122 
123  int64_t *plane_f, *plane_g;
124 } MorphoContext;
125 
126 #define OFFSET(x) offsetof(MorphoContext, x)
127 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM
128 
129 static const AVOption morpho_options[] = {
130  { "mode", "set morphological transform", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_MODES-1, FLAGS, "mode" },
131  { "erode", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ERODE}, 0, 0, FLAGS, "mode" },
132  { "dilate", NULL, 0, AV_OPT_TYPE_CONST, {.i64=DILATE}, 0, 0, FLAGS, "mode" },
133  { "open", NULL, 0, AV_OPT_TYPE_CONST, {.i64=OPEN}, 0, 0, FLAGS, "mode" },
134  { "close", NULL, 0, AV_OPT_TYPE_CONST, {.i64=CLOSE}, 0, 0, FLAGS, "mode" },
135  { "gradient",NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRADIENT},0, 0, FLAGS, "mode" },
136  { "tophat",NULL, 0, AV_OPT_TYPE_CONST, {.i64=TOPHAT}, 0, 0, FLAGS, "mode" },
137  { "blackhat",NULL, 0, AV_OPT_TYPE_CONST, {.i64=BLACKHAT},0, 0, FLAGS, "mode" },
138  { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS },
139  { "structure", "when to process structures", OFFSET(structures), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "str" },
140  { "first", "process only first structure, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "str" },
141  { "all", "process all structure", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "str" },
142  { NULL }
143 };
144 
146 
147 static const enum AVPixelFormat pix_fmts[] = {
167 };
168 
169 static void min_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
170 {
171  for (int i = 0; i < x; i++)
172  c[i] = FFMIN(b[i], a[i]);
173 }
174 
175 static void mininplace_fun(uint8_t *a, const uint8_t *b, int x)
176 {
177  for (int i = 0; i < x; i++)
178  a[i] = FFMIN(a[i], b[i]);
179 }
180 
181 static void max_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
182 {
183  for (int i = 0; i < x; i++)
184  c[i] = FFMAX(a[i], b[i]);
185 }
186 
187 static void maxinplace_fun(uint8_t *a, const uint8_t *b, int x)
188 {
189  for (int i = 0; i < x; i++)
190  a[i] = FFMAX(a[i], b[i]);
191 }
192 
193 static void diff_fun(uint8_t *a, const uint8_t *b, int x)
194 {
195  for (int i = 0; i < x; i++)
196  a[i] = FFMAX(b[i] - a[i], 0);
197 }
198 
199 static void diffinplace_fun(uint8_t *a, const uint8_t *b, int x)
200 {
201  for (int i = 0; i < x; i++)
202  a[i] = FFMAX(a[i] - b[i], 0);
203 }
204 
205 static void min16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
206 {
207  const uint16_t *a = (const uint16_t *)aa;
208  const uint16_t *b = (const uint16_t *)bb;
209  uint16_t *c = (uint16_t *)cc;
210 
211  for (int i = 0; i < x; i++)
212  c[i] = FFMIN(b[i], a[i]);
213 }
214 
215 static void mininplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
216 {
217  uint16_t *a = (uint16_t *)aa;
218  const uint16_t *b = (const uint16_t *)bb;
219 
220  for (int i = 0; i < x; i++)
221  a[i] = FFMIN(a[i], b[i]);
222 }
223 
224 static void diff16_fun(uint8_t *aa, const uint8_t *bb, int x)
225 {
226  const uint16_t *b = (const uint16_t *)bb;
227  uint16_t *a = (uint16_t *)aa;
228 
229  for (int i = 0; i < x; i++)
230  a[i] = FFMAX(b[i] - a[i], 0);
231 }
232 
233 static void diffinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
234 {
235  uint16_t *a = (uint16_t *)aa;
236  const uint16_t *b = (const uint16_t *)bb;
237 
238  for (int i = 0; i < x; i++)
239  a[i] = FFMAX(a[i] - b[i], 0);
240 }
241 
242 static void max16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
243 {
244  const uint16_t *a = (const uint16_t *)aa;
245  const uint16_t *b = (const uint16_t *)bb;
246  uint16_t *c = (uint16_t *)cc;
247 
248  for (int i = 0; i < x; i++)
249  c[i] = FFMAX(a[i], b[i]);
250 }
251 
252 static void maxinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
253 {
254  uint16_t *a = (uint16_t *)aa;
255  const uint16_t *b = (const uint16_t *)bb;
256 
257  for (int i = 0; i < x; i++)
258  a[i] = FFMAX(a[i], b[i]);
259 }
260 
261 static int alloc_lut(LUT *Ty, chord_set *SE, int type_size, int mode)
262 {
263  const int min = FFMAX(Ty->min_r, 0);
264  const int max = min + (Ty->max_r - Ty->min_r);
265  int pre_pad_x = 0;
266 
267  if (SE->minX < 0)
268  pre_pad_x = 0 - SE->minX;
269  Ty->pre_pad_x = pre_pad_x;
270  Ty->type_size = type_size;
271 
272  Ty->base_arr = av_calloc(max + 1, sizeof(*Ty->base_arr));
273  if (!Ty->base_arr)
274  return AVERROR(ENOMEM);
275  for (int r = min; r <= max; r++) {
276  uint8_t **arr = Ty->base_arr[r] = av_calloc(Ty->I, sizeof(uint8_t *));
277  if (!Ty->base_arr[r])
278  return AVERROR(ENOMEM);
279  for (int i = 0; i < Ty->I; i++) {
280  arr[i] = av_calloc(Ty->X + pre_pad_x, type_size);
281  if (!arr[i])
282  return AVERROR(ENOMEM);
283  if (mode == ERODE)
284  memset(arr[i], UINT8_MAX, pre_pad_x * type_size);
285  /* Shifting the X index such that negative indices correspond to
286  * the pre-padding.
287  */
288  arr[i] = &(arr[i][pre_pad_x * type_size]);
289  }
290  }
291 
292  Ty->arr = &(Ty->base_arr[min - Ty->min_r]);
293 
294  return 0;
295 }
296 
297 static void free_lut(LUT *table)
298 {
299  const int min = FFMAX(table->min_r, 0);
300  const int max = min + (table->max_r - table->min_r);
301 
302  if (!table->base_arr)
303  return;
304 
305  for (int r = min; r <= max; r++) {
306  if (!table->base_arr[r])
307  break;
308  for (int i = 0; i < table->I; i++) {
309  if (!table->base_arr[r][i])
310  break;
311  // The X index was also shifted, for padding purposes.
312  av_free(table->base_arr[r][i] - table->pre_pad_x * table->type_size);
313  }
314  av_freep(&table->base_arr[r]);
315  }
316  av_freep(&table->base_arr);
317  table->arr = NULL;
318 }
319 
321  int y, int num, enum MorphModes mode)
322 {
323  if (!Ty->arr || Ty->I != SE->Lnum ||
324  Ty->X != f->w ||
325  SE->minX < 0 && -SE->minX > Ty->pre_pad_x ||
326  Ty->min_r != SE->minY ||
327  Ty->max_r != SE->maxY + num - 1) {
328  int ret;
329 
330  free_lut(Ty);
331 
332  Ty->I = SE->Lnum;
333  Ty->X = f->w;
334  Ty->min_r = SE->minY;
335  Ty->max_r = SE->maxY + num - 1;
336  ret = alloc_lut(Ty, SE, f->type_size, mode);
337  if (ret < 0)
338  return ret;
339  }
340  return 0;
341 }
342 
343 static void circular_swap(LUT *Ty)
344 {
345  /*
346  * Swap the pointers to r-indices in a circle. This is useful because
347  * Ty(r,i,x) = Ty-1(r+1,i,x) for r < ymax.
348  */
349  if (Ty->max_r - Ty->min_r > 0) {
350  uint8_t **Ty0 = Ty->arr[Ty->min_r];
351 
352  for (int r = Ty->min_r; r < Ty->max_r; r++)
353  Ty->arr[r] = Ty->arr[r + 1];
354 
355  Ty->arr[Ty->max_r] = Ty0;
356  }
357 }
358 
359 static void compute_min_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
360 {
361  if (y + r >= 0 && y + r < f->h) {
362  memcpy(Ty->arr[r][0], f->img[y + r], Ty->X * Ty->type_size);
363  } else {
364  memset(Ty->arr[r][0], UINT8_MAX, Ty->X * Ty->type_size);
365  }
366 
367  for (int i = 1; i < SE->Lnum; i++) {
368  int d = SE->R[i] - SE->R[i - 1];
369 
370  f->min_out_place(Ty->arr[r][i] - Ty->pre_pad_x * f->type_size,
371  Ty->arr[r][i - 1] - Ty->pre_pad_x * f->type_size,
372  Ty->arr[r][i - 1] + (d - Ty->pre_pad_x) * f->type_size,
373  Ty->X + Ty->pre_pad_x - d);
374  memcpy(Ty->arr[r][i] + (Ty->X - d) * f->type_size,
375  Ty->arr[r][i - 1] + (Ty->X - d) * f->type_size,
376  d * f->type_size);
377  }
378 }
379 
380 static void update_min_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
381 {
382  for (int i = 0; i < num; i++)
383  circular_swap(Ty);
384 
385  compute_min_row(f, Ty, SE, Ty->max_r - tid, y);
386 }
387 
388 static int compute_min_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
389 {
390  int ret = alloc_lut_if_necessary(Ty, f, SE, y, num, ERODE);
391  if (ret < 0)
392  return ret;
393 
394  for (int r = Ty->min_r; r <= Ty->max_r; r++)
395  compute_min_row(f, Ty, SE, r, y);
396 
397  return 0;
398 }
399 
400 static void compute_max_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
401 {
402  if (y + r >= 0 && y + r < f->h) {
403  memcpy(Ty->arr[r][0], f->img[y + r], Ty->X * Ty->type_size);
404  } else {
405  memset(Ty->arr[r][0], 0, Ty->X * Ty->type_size);
406  }
407 
408  for (int i = 1; i < SE->Lnum; i++) {
409  int d = SE->R[i] - SE->R[i - 1];
410 
411  f->max_out_place(Ty->arr[r][i] - Ty->pre_pad_x * f->type_size,
412  Ty->arr[r][i - 1] - Ty->pre_pad_x * f->type_size,
413  Ty->arr[r][i - 1] + (d - Ty->pre_pad_x) * f->type_size,
414  Ty->X + Ty->pre_pad_x - d);
415  memcpy(Ty->arr[r][i] + (Ty->X - d) * f->type_size,
416  Ty->arr[r][i - 1] + (Ty->X - d) * f->type_size,
417  d * f->type_size);
418  }
419 }
420 
421 static void update_max_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
422 {
423  for (int i = 0; i < num; i++)
424  circular_swap(Ty);
425 
426  compute_max_row(f, Ty, SE, Ty->max_r - tid, y);
427 }
428 
429 static int compute_max_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
430 {
431  int ret = alloc_lut_if_necessary(Ty, f, SE, y, num, DILATE);
432  if (ret < 0)
433  return ret;
434 
435  for (int r = Ty->min_r; r <= Ty->max_r; r++)
436  compute_max_row(f, Ty, SE, r, y);
437 
438  return 0;
439 }
440 
441 static void line_dilate(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
442 {
443  memset(g->img[y], 0, g->w * g->type_size);
444 
445  for (int c = 0; c < SE->size; c++) {
446  g->max_in_place(g->img[y],
447  Ty->arr[SE->C[c].y + tid][SE->C[c].i] + SE->C[c].x * Ty->type_size,
448  av_clip(g->w - SE->C[c].x, 0, g->w));
449  }
450 }
451 
452 static void line_erode(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
453 {
454  memset(g->img[y], UINT8_MAX, g->w * g->type_size);
455 
456  for (int c = 0; c < SE->size; c++) {
457  g->min_in_place(g->img[y],
458  Ty->arr[SE->C[c].y + tid][SE->C[c].i] + SE->C[c].x * Ty->type_size,
459  av_clip(g->w - SE->C[c].x, 0, g->w));
460  }
461 }
462 
463 static int dilate(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty)
464 {
465  int ret = compute_max_lut(Ty, f, SE, 0, 1);
466  if (ret < 0)
467  return ret;
468 
469  line_dilate(g, Ty, SE, 0, 0);
470  for (int y = 1; y < f->h; y++) {
471  update_max_lut(f, Ty, SE, y, 0, 1);
472  line_dilate(g, Ty, SE, y, 0);
473  }
474 
475  return 0;
476 }
477 
478 static int erode(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty)
479 {
480  int ret = compute_min_lut(Ty, f, SE, 0, 1);
481  if (ret < 0)
482  return ret;
483 
484  line_erode(g, Ty, SE, 0, 0);
485  for (int y = 1; y < f->h; y++) {
486  update_min_lut(f, Ty, SE, y, 0, 1);
487  line_erode(g, Ty, SE, y, 0);
488  }
489 
490  return 0;
491 }
492 
493 static void difference(IPlane *g, IPlane *f)
494 {
495  for (int y = 0; y < f->h; y++)
496  f->diff_in_place(g->img[y], f->img[y], f->w);
497 }
498 
499 static void difference2(IPlane *g, IPlane *f)
500 {
501  for (int y = 0; y < f->h; y++)
502  f->diff_rin_place(g->img[y], f->img[y], f->w);
503 }
504 
505 static int insert_chord_set(chord_set *chords, chord c)
506 {
507  // Checking if chord fits in dynamic array, resize if not.
508  if (chords->size == chords->cap) {
509  chords->C = av_realloc_f(chords->C, chords->cap * 2, sizeof(chord));
510  if (!chords->C)
511  return AVERROR(ENOMEM);
512  chords->cap *= 2;
513  }
514 
515  // Add the chord to the dynamic array.
516  chords->C[chords->size].x = c.x;
517  chords->C[chords->size].y = c.y;
518  chords->C[chords->size++].l = c.l;
519 
520  // Update minimum/maximum x/y offsets of the chord set.
521  chords->minX = FFMIN(chords->minX, c.x);
522  chords->maxX = FFMAX(chords->maxX, c.x);
523 
524  chords->minY = FFMIN(chords->minY, c.y);
525  chords->maxY = FFMAX(chords->maxY, c.y);
526 
527  return 0;
528 }
529 
531 {
532  av_freep(&SE->C);
533  SE->size = 0;
534  SE->cap = 0;
535 
536  av_freep(&SE->R);
537  SE->Lnum = 0;
538 }
539 
540 static int init_chordset(chord_set *chords)
541 {
542  chords->nb_elements = 0;
543  chords->size = 0;
544  chords->C = av_calloc(1, sizeof(chord));
545  if (!chords->C)
546  return AVERROR(ENOMEM);
547 
548  chords->cap = 1;
549  chords->minX = INT16_MAX;
550  chords->maxX = INT16_MIN;
551  chords->minY = INT16_MAX;
552  chords->maxY = INT16_MIN;
553 
554  return 0;
555 }
556 
557 static int comp_chord_length(const void *p, const void *q)
558 {
559  chord a, b;
560  a = *((chord *)p);
561  b = *((chord *)q);
562 
563  return (a.l > b.l) - (a.l < b.l);
564 }
565 
566 static int comp_chord(const void *p, const void *q)
567 {
568  chord a, b;
569  a = *((chord *)p);
570  b = *((chord *)q);
571 
572  return (a.y > b.y) - (a.y < b.y);
573 }
574 
575 static int build_chord_set(IPlane *SE, chord_set *chords)
576 {
577  const int mid = 1 << (SE->depth - 1);
578  int chord_length_index;
579  int chord_start, val, ret;
580  int centerX, centerY;
581  int r_cap = 1;
582  chord c;
583 
584  ret = init_chordset(chords);
585  if (ret < 0)
586  return ret;
587  /*
588  * In erosion/dilation, the center of the IPlane has S.E. offset (0,0).
589  * Otherwise, the resulting IPlane would be shifted to the top-left.
590  */
591  centerX = (SE->w - 1) / 2;
592  centerY = (SE->h - 1) / 2;
593 
594  /*
595  * Computing the set of chords C.
596  */
597  for (int y = 0; y < SE->h; y++) {
598  int x;
599 
600  chord_start = -1;
601  for (x = 0; x < SE->w; x++) {
602  if (SE->type_size == 1) {
603  chords->nb_elements += (SE->img[y][x] >= mid);
604  //A chord is a run of non-zero pixels.
605  if (SE->img[y][x] >= mid && chord_start == -1) {
606  // Chord starts.
607  chord_start = x;
608  } else if (SE->img[y][x] < mid && chord_start != -1) {
609  // Chord ends before end of line.
610  c.x = chord_start - centerX;
611  c.y = y - centerY;
612  c.l = x - chord_start;
613  ret = insert_chord_set(chords, c);
614  if (ret < 0)
615  return AVERROR(ENOMEM);
616  chord_start = -1;
617  }
618  } else {
619  chords->nb_elements += (AV_RN16(&SE->img[y][x * 2]) >= mid);
620  //A chord is a run of non-zero pixels.
621  if (AV_RN16(&SE->img[y][x * 2]) >= mid && chord_start == -1) {
622  // Chord starts.
623  chord_start = x;
624  } else if (AV_RN16(&SE->img[y][x * 2]) < mid && chord_start != -1) {
625  // Chord ends before end of line.
626  c.x = chord_start - centerX;
627  c.y = y - centerY;
628  c.l = x - chord_start;
629  ret = insert_chord_set(chords, c);
630  if (ret < 0)
631  return AVERROR(ENOMEM);
632  chord_start = -1;
633  }
634  }
635  }
636  if (chord_start != -1) {
637  // Chord ends at end of line.
638  c.x = chord_start - centerX;
639  c.y = y - centerY;
640  c.l = x - chord_start;
641  ret = insert_chord_set(chords, c);
642  if (ret < 0)
643  return AVERROR(ENOMEM);
644  }
645  }
646 
647  /*
648  * Computing the array of chord lengths R(i).
649  * This is needed because the lookup table will contain a row for each
650  * length index i.
651  */
652  qsort(chords->C, chords->size, sizeof(chord), comp_chord_length);
653  chords->R = av_calloc(1, sizeof(*chords->R));
654  if (!chords->R)
655  return AVERROR(ENOMEM);
656  chords->Lnum = 0;
657  val = 0;
658  r_cap = 1;
659 
660  if (chords->size > 0) {
661  val = 1;
662  if (chords->Lnum >= r_cap) {
663  chords->R = av_realloc_f(chords->R, r_cap * 2, sizeof(*chords->R));
664  if (!chords->R)
665  return AVERROR(ENOMEM);
666  r_cap *= 2;
667  }
668  chords->R[chords->Lnum++] = 1;
669  val = 1;
670  }
671 
672  for (int i = 0; i < chords->size; i++) {
673  if (val != chords->C[i].l) {
674  while (2 * val < chords->C[i].l && val != 0) {
675  if (chords->Lnum >= r_cap) {
676  chords->R = av_realloc_f(chords->R, r_cap * 2, sizeof(*chords->R));
677  if (!chords->R)
678  return AVERROR(ENOMEM);
679  r_cap *= 2;
680  }
681 
682  chords->R[chords->Lnum++] = 2 * val;
683  val *= 2;
684  }
685  val = chords->C[i].l;
686 
687  if (chords->Lnum >= r_cap) {
688  chords->R = av_realloc_f(chords->R, r_cap * 2, sizeof(*chords->R));
689  if (!chords->R)
690  return AVERROR(ENOMEM);
691  r_cap *= 2;
692  }
693  chords->R[chords->Lnum++] = val;
694  }
695  }
696 
697  /*
698  * Setting the length indices of chords.
699  * These are needed so that the algorithm can, for each chord,
700  * access the lookup table at the correct length in constant time.
701  */
702  chord_length_index = 0;
703  for (int i = 0; i < chords->size; i++) {
704  while (chords->R[chord_length_index] < chords->C[i].l)
705  chord_length_index++;
706  chords->C[i].i = chord_length_index;
707  }
708 
709  /*
710  * Chords are sorted on Y. This way, when a row of the lookup table or IPlane
711  * is cached, the next chord offset has a better chance of being on the
712  * same cache line.
713  */
714  qsort(chords->C, chords->size, sizeof(chord), comp_chord);
715 
716  return 0;
717 }
718 
719 static void free_iplane(IPlane *imp)
720 {
721  av_freep(&imp->img);
722 }
723 
724 static int read_iplane(IPlane *imp, const uint8_t *dst, int dst_linesize,
725  int w, int h, int R, int type_size, int depth)
726 {
727  if (!imp->img)
728  imp->img = av_calloc(h, sizeof(*imp->img));
729  if (!imp->img)
730  return AVERROR(ENOMEM);
731 
732  imp->w = w;
733  imp->h = h;
734  imp->range = R;
735  imp->depth = depth;
736  imp->type_size = type_size;
737  imp->max_out_place = type_size == 1 ? max_fun : max16_fun;
738  imp->min_out_place = type_size == 1 ? min_fun : min16_fun;
739  imp->diff_rin_place = type_size == 1 ? diff_fun : diff16_fun;
740  imp->max_in_place = type_size == 1 ? maxinplace_fun : maxinplace16_fun;
741  imp->min_in_place = type_size == 1 ? mininplace_fun : mininplace16_fun;
742  imp->diff_in_place = type_size == 1 ? diffinplace_fun : diffinplace16_fun;
743 
744  for (int y = 0; y < h; y++)
745  imp->img[y] = (uint8_t *)dst + y * dst_linesize;
746 
747  return 0;
748 }
749 
751 {
753  MorphoContext *s = inlink->dst->priv;
754 
755  s->depth = desc->comp[0].depth;
756  s->type_size = (s->depth + 7) / 8;
757  s->nb_planes = desc->nb_components;
758  s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
759  s->planewidth[0] = s->planewidth[3] = inlink->w;
760  s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
761  s->planeheight[0] = s->planeheight[3] = inlink->h;
762 
763  return 0;
764 }
765 
767 {
769  AVFilterContext *ctx = inlink->dst;
770  MorphoContext *s = inlink->dst->priv;
771 
772  av_assert0(ctx->inputs[0]->format == ctx->inputs[1]->format);
773 
774  s->splanewidth[1] = s->splanewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
775  s->splanewidth[0] = s->splanewidth[3] = inlink->w;
776  s->splaneheight[1] = s->splaneheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
777  s->splaneheight[0] = s->splaneheight[3] = inlink->h;
778 
779  return 0;
780 }
781 
783 {
784  MorphoContext *s = ctx->priv;
785  return ff_framesync_activate(&s->fs);
786 }
787 
789 {
790  AVFilterContext *ctx = fs->parent;
791  AVFilterLink *outlink = ctx->outputs[0];
792  MorphoContext *s = ctx->priv;
793  AVFrame *in = NULL, *structurepic = NULL;
794  AVFrame *out;
795  int ret;
796 
797  ret = ff_framesync_dualinput_get(fs, &in, &structurepic);
798  if (ret < 0)
799  return ret;
800  if (!structurepic)
801  return ff_filter_frame(outlink, in);
802 
803  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
804  if (!out) {
805  av_frame_free(&in);
806  return AVERROR(ENOMEM);
807  }
809 
810  for (int p = 0; p < s->nb_planes; p++) {
811  const uint8_t *src = in->data[p];
812  int src_linesize = in->linesize[p];
813  const uint8_t *ssrc = structurepic->data[p];
814  const int ssrc_linesize = structurepic->linesize[p];
815  uint8_t *dst = out->data[p];
816  int dst_linesize = out->linesize[p];
817  const int swidth = s->splanewidth[p];
818  const int sheight = s->splaneheight[p];
819  const int width = s->planewidth[p];
820  const int height = s->planeheight[p];
821  const int depth = s->depth;
822  int type_size = s->type_size;
823 
824  if (ctx->is_disabled || !(s->planes & (1 << p))) {
825 copy:
826  av_image_copy_plane(out->data[p] + 0 * out->linesize[p],
827  out->linesize[p],
828  in->data[p] + 0 * in->linesize[p],
829  in->linesize[p],
830  width * ((s->depth + 7) / 8),
831  height);
832  continue;
833  }
834 
835  if (!s->got_structure[p] || s->structures) {
836  free_chord_set(&s->SE[p]);
837 
838  ret = read_iplane(&s->SEimg[p], ssrc, ssrc_linesize, swidth, sheight, 1, type_size, depth);
839  if (ret < 0)
840  goto fail;
841  ret = build_chord_set(&s->SEimg[p], &s->SE[p]);
842  if (ret < 0)
843  goto fail;
844  s->got_structure[p] = 1;
845  }
846 
847  if (s->SE[p].minX == INT16_MAX ||
848  s->SE[p].minY == INT16_MAX ||
849  s->SE[p].maxX == INT16_MIN ||
850  s->SE[p].maxY == INT16_MIN)
851  goto copy;
852 
853  ret = read_iplane(&s->f[p], src, src_linesize, width, height, 1, type_size, depth);
854  if (ret < 0)
855  goto fail;
856 
857  ret = read_iplane(&s->g[p], dst, dst_linesize, s->f[p].w, s->f[p].h, s->f[p].range, type_size, depth);
858  if (ret < 0)
859  goto fail;
860 
861  switch (s->mode) {
862  case ERODE:
863  ret = erode(&s->g[p], &s->f[p], &s->SE[p], &s->Ty[0][p]);
864  break;
865  case DILATE:
866  ret = dilate(&s->g[p], &s->f[p], &s->SE[p], &s->Ty[0][p]);
867  break;
868  case OPEN:
869  ret = read_iplane(&s->h[p], s->temp->data[p], s->temp->linesize[p], width, height, 1, type_size, depth);
870  if (ret < 0)
871  break;
872  ret = erode(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[0][p]);
873  if (ret < 0)
874  break;
875  ret = dilate(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[1][p]);
876  break;
877  case CLOSE:
878  ret = read_iplane(&s->h[p], s->temp->data[p], s->temp->linesize[p], width, height, 1, type_size, depth);
879  if (ret < 0)
880  break;
881  ret = dilate(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[0][p]);
882  if (ret < 0)
883  break;
884  ret = erode(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[1][p]);
885  break;
886  case GRADIENT:
887  ret = read_iplane(&s->h[p], s->temp->data[p], s->temp->linesize[p], width, height, 1, type_size, depth);
888  if (ret < 0)
889  break;
890  ret = dilate(&s->g[p], &s->f[p], &s->SE[p], &s->Ty[0][p]);
891  if (ret < 0)
892  break;
893  ret = erode(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[1][p]);
894  if (ret < 0)
895  break;
896  difference(&s->g[p], &s->h[p]);
897  break;
898  case TOPHAT:
899  ret = read_iplane(&s->h[p], s->temp->data[p], s->temp->linesize[p], width, height, 1, type_size, depth);
900  if (ret < 0)
901  break;
902  ret = erode(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[0][p]);
903  if (ret < 0)
904  break;
905  ret = dilate(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[1][p]);
906  if (ret < 0)
907  break;
908  difference2(&s->g[p], &s->f[p]);
909  break;
910  case BLACKHAT:
911  ret = read_iplane(&s->h[p], s->temp->data[p], s->temp->linesize[p], width, height, 1, type_size, depth);
912  if (ret < 0)
913  break;
914  ret = dilate(&s->h[p], &s->f[p], &s->SE[p], &s->Ty[0][p]);
915  if (ret < 0)
916  break;
917  ret = erode(&s->g[p], &s->h[p], &s->SE[p], &s->Ty[1][p]);
918  if (ret < 0)
919  break;
920  difference(&s->g[p], &s->f[p]);
921  break;
922  default:
923  av_assert0(0);
924  }
925 
926  if (ret < 0)
927  goto fail;
928  }
929 
930  av_frame_free(&in);
931  out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base);
932  return ff_filter_frame(outlink, out);
933 fail:
934  av_frame_free(&out);
935  av_frame_free(&in);
936  return ret;
937 }
938 
939 static int config_output(AVFilterLink *outlink)
940 {
941  AVFilterContext *ctx = outlink->src;
942  MorphoContext *s = ctx->priv;
943  AVFilterLink *mainlink = ctx->inputs[0];
944  int ret;
945 
946  s->fs.on_event = do_morpho;
948  if (ret < 0)
949  return ret;
950  outlink->w = mainlink->w;
951  outlink->h = mainlink->h;
952  outlink->time_base = mainlink->time_base;
953  outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
954  outlink->frame_rate = mainlink->frame_rate;
955 
956  if ((ret = ff_framesync_configure(&s->fs)) < 0)
957  return ret;
958  outlink->time_base = s->fs.time_base;
959 
960  s->temp = ff_get_video_buffer(outlink, outlink->w, outlink->h);
961  if (!s->temp)
962  return AVERROR(ENOMEM);
963 
964  s->plane_f = av_calloc(outlink->w * outlink->h, sizeof(*s->plane_f));
965  s->plane_g = av_calloc(outlink->w * outlink->h, sizeof(*s->plane_g));
966  if (!s->plane_f || !s->plane_g)
967  return AVERROR(ENOMEM);
968 
969  return 0;
970 }
971 
973 {
974  MorphoContext *s = ctx->priv;
975 
976  for (int p = 0; p < 4; p++) {
977  free_iplane(&s->SEimg[p]);
978  free_iplane(&s->f[p]);
979  free_iplane(&s->g[p]);
980  free_iplane(&s->h[p]);
981  free_chord_set(&s->SE[p]);
982  free_lut(&s->Ty[0][p]);
983  free_lut(&s->Ty[1][p]);
984  }
985 
986  ff_framesync_uninit(&s->fs);
987 
988  av_frame_free(&s->temp);
989  av_freep(&s->plane_f);
990  av_freep(&s->plane_g);
991 }
992 
993 static const AVFilterPad morpho_inputs[] = {
994  {
995  .name = "default",
996  .type = AVMEDIA_TYPE_VIDEO,
997  .config_props = config_input,
998  },
999  {
1000  .name = "structure",
1001  .type = AVMEDIA_TYPE_VIDEO,
1002  .config_props = config_input_structure,
1003  },
1004 };
1005 
1006 static const AVFilterPad morpho_outputs[] = {
1007  {
1008  .name = "default",
1009  .type = AVMEDIA_TYPE_VIDEO,
1010  .config_props = config_output,
1011  },
1012 };
1013 
1015  .name = "morpho",
1016  .description = NULL_IF_CONFIG_SMALL("Apply Morphological filter."),
1017  .preinit = morpho_framesync_preinit,
1018  .priv_size = sizeof(MorphoContext),
1019  .priv_class = &morpho_class,
1020  .activate = activate,
1021  .uninit = uninit,
1026  .process_command = ff_filter_process_command,
1027 };
IPlane::h
int h
Definition: vf_morpho.c:50
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:98
AV_PIX_FMT_YUVA422P16
#define AV_PIX_FMT_YUVA422P16
Definition: pixfmt.h:447
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:426
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:119
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
av_clip
#define av_clip
Definition: common.h:96
r
const char * r
Definition: vf_curves.c:116
line_erode
static void line_erode(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
Definition: vf_morpho.c:452
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
IPlane
Definition: vf_morpho.c:48
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:285
out
FILE * out
Definition: movenc.c:54
chord::i
int i
Definition: vf_morpho.c:80
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1018
free_chord_set
static void free_chord_set(chord_set *SE)
Definition: vf_morpho.c:530
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2660
mininplace_fun
static void mininplace_fun(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:175
IPlane::min_in_place
void(* min_in_place)(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:59
FILTER_PIXFMTS_ARRAY
#define FILTER_PIXFMTS_ARRAY(array)
Definition: internal.h:171
DILATE
@ DILATE
Definition: vf_morpho.c:39
diffinplace_fun
static void diffinplace_fun(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:199
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
activate
static int activate(AVFilterContext *ctx)
Definition: vf_morpho.c:782
GRADIENT
@ GRADIENT
Definition: vf_morpho.c:42
chord_set::R
int * R
Definition: vf_morpho.c:88
AV_RN16
#define AV_RN16(p)
Definition: intreadwrite.h:360
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:109
AV_PIX_FMT_YUVA422P9
#define AV_PIX_FMT_YUVA422P9
Definition: pixfmt.h:439
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:310
pixdesc.h
AV_PIX_FMT_YUVA420P16
#define AV_PIX_FMT_YUVA420P16
Definition: pixfmt.h:446
w
uint8_t w
Definition: llviddspenc.c:38
R
#define R
Definition: huffyuvdsp.h:34
AV_PIX_FMT_YUVA420P10
#define AV_PIX_FMT_YUVA420P10
Definition: pixfmt.h:441
AVOption
AVOption.
Definition: opt.h:247
b
#define b
Definition: input.c:40
table
static const uint16_t table[]
Definition: prosumer.c:206
AV_PIX_FMT_YUV420P10
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:404
alloc_lut_if_necessary
static int alloc_lut_if_necessary(LUT *Ty, IPlane *f, chord_set *SE, int y, int num, enum MorphModes mode)
Definition: vf_morpho.c:320
LUT::base_arr
uint8_t *** base_arr
Definition: vf_morpho.c:67
IPlane::range
int range
Definition: vf_morpho.c:51
ff_vf_morpho
const AVFilter ff_vf_morpho
Definition: vf_morpho.c:1014
MorphoContext
Definition: vf_morpho.c:98
FRAMESYNC_DEFINE_CLASS
FRAMESYNC_DEFINE_CLASS(morpho, MorphoContext, fs)
AV_PIX_FMT_YUV440P
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
max
#define max(a, b)
Definition: cuda_runtime.h:33
chord_set::cap
int cap
Definition: vf_morpho.c:86
chord_set::nb_elements
unsigned nb_elements
Definition: vf_morpho.c:95
LUT::X
int X
Definition: vf_morpho.c:71
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
MorphoContext::splaneheight
int splaneheight[4]
Definition: vf_morpho.c:114
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:169
FFFrameSync
Frame sync structure.
Definition: framesync.h:146
LUT::max_r
int max_r
Definition: vf_morpho.c:69
video.h
AV_PIX_FMT_YUVA422P10
#define AV_PIX_FMT_YUVA422P10
Definition: pixfmt.h:442
IPlane::min_out_place
void(* min_out_place)(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:56
AV_PIX_FMT_GRAY9
#define AV_PIX_FMT_GRAY9
Definition: pixfmt.h:384
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:331
av_image_copy_plane
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
MorphoContext::depth
int depth
Definition: vf_morpho.c:115
formats.h
AV_PIX_FMT_YUVA420P9
#define AV_PIX_FMT_YUVA420P9
Definition: pixfmt.h:438
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:422
alloc_lut
static int alloc_lut(LUT *Ty, chord_set *SE, int type_size, int mode)
Definition: vf_morpho.c:261
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:205
fail
#define fail()
Definition: checkasm.h:127
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:420
AV_PIX_FMT_YUVA444P16
#define AV_PIX_FMT_YUVA444P16
Definition: pixfmt.h:448
MorphoContext::f
IPlane f[4]
Definition: vf_morpho.c:104
min16_fun
static void min16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
Definition: vf_morpho.c:205
AV_PIX_FMT_YUV422P9
#define AV_PIX_FMT_YUV422P9
Definition: pixfmt.h:402
MorphoContext::mode
int mode
Definition: vf_morpho.c:107
val
static double val(void *priv, double ch)
Definition: aeval.c:76
MorphoContext::planeheight
int planeheight[4]
Definition: vf_morpho.c:112
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:388
NB_MODES
@ NB_MODES
Definition: vf_morpho.c:45
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: vf_morpho.c:147
MorphoContext::SEimg
IPlane SEimg[4]
Definition: vf_morpho.c:103
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:50
chord_set::Lnum
int Lnum
Definition: vf_morpho.c:89
AV_PIX_FMT_YUV444P10
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:407
AV_PIX_FMT_YUVJ411P
@ 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:248
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_morpho.c:972
C
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i you should get a foobar png with Lena edge detected That s your new playground is ready Some little details about what s going which in turn will define variables for the build system and the C
Definition: writing_filters.txt:58
avassert.h
av_cold
#define av_cold
Definition: attributes.h:90
AV_PIX_FMT_YUV422P16
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:416
do_morpho
static int do_morpho(FFFrameSync *fs)
Definition: vf_morpho.c:788
MorphoContext::planes
int planes
Definition: vf_morpho.c:108
AV_PIX_FMT_YUVJ422P
@ 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:79
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:424
width
#define width
maxinplace16_fun
static void maxinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition: vf_morpho.c:252
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:257
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:425
AV_PIX_FMT_YUVA420P
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:101
mininplace16_fun
static void mininplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition: vf_morpho.c:215
AV_PIX_FMT_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:417
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:51
morpho_inputs
static const AVFilterPad morpho_inputs[]
Definition: vf_morpho.c:993
difference2
static void difference2(IPlane *g, IPlane *f)
Definition: vf_morpho.c:499
g
const char * g
Definition: vf_curves.c:117
LUT::arr
uint8_t *** arr
Definition: vf_morpho.c:66
MorphoContext::got_structure
int got_structure[4]
Definition: vf_morpho.c:119
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
AV_PIX_FMT_YUVA444P12
#define AV_PIX_FMT_YUVA444P12
Definition: pixfmt.h:445
AV_PIX_FMT_YUV420P9
#define AV_PIX_FMT_YUV420P9
Definition: pixfmt.h:401
AV_PIX_FMT_YUV420P16
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:415
ctx
AVFormatContext * ctx
Definition: movenc.c:48
chord_set::maxX
int maxX
Definition: vf_morpho.c:92
insert_chord_set
static int insert_chord_set(chord_set *chords, chord c)
Definition: vf_morpho.c:505
AV_PIX_FMT_GRAY14
#define AV_PIX_FMT_GRAY14
Definition: pixfmt.h:387
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:141
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
f
#define f(width, name)
Definition: cbs_vp9.c:255
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:191
AV_PIX_FMT_YUVJ444P
@ 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:80
planes
static const struct @321 planes[]
AV_PIX_FMT_GRAY10
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:385
compute_max_row
static void compute_max_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
Definition: vf_morpho.c:400
av_realloc_f
#define av_realloc_f(p, o, n)
Definition: tableprint_vlc.h:33
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:423
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
MorphoContext::plane_g
int64_t * plane_g
Definition: vf_morpho.c:123
NULL
#define NULL
Definition: coverity.c:32
IPlane::diff_in_place
void(* diff_in_place)(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:60
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:537
fs
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:259
chord
Definition: vf_morpho.c:76
config_input_structure
static int config_input_structure(AVFilterLink *inlink)
Definition: vf_morpho.c:766
maxinplace_fun
static void maxinplace_fun(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:187
diff16_fun
static void diff16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition: vf_morpho.c:224
AV_PIX_FMT_YUVJ420P
@ 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:78
src
#define src
Definition: vp8dsp.c:255
morpho_outputs
static const AVFilterPad morpho_outputs[]
Definition: vf_morpho.c:1006
MorphoContext::h
IPlane h[4]
Definition: vf_morpho.c:104
CLOSE
@ CLOSE
Definition: vf_morpho.c:41
AV_PIX_FMT_YUV422P10
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:405
FLAGS
#define FLAGS
Definition: vf_morpho.c:127
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
LUT::type_size
int type_size
Definition: vf_morpho.c:73
TOPHAT
@ TOPHAT
Definition: vf_morpho.c:43
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:419
MorphoContext::Ty
LUT Ty[2][4]
Definition: vf_morpho.c:105
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
IPlane::depth
int depth
Definition: vf_morpho.c:52
init_chordset
static int init_chordset(chord_set *chords)
Definition: vf_morpho.c:540
chord_set::size
int size
Definition: vf_morpho.c:85
chord::y
int y
Definition: vf_morpho.c:78
chord_set::minY
int minY
Definition: vf_morpho.c:93
chord_set::C
chord * C
Definition: vf_morpho.c:84
free_lut
static void free_lut(LUT *table)
Definition: vf_morpho.c:297
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
ff_framesync_init_dualinput
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:353
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:187
LUT
Definition: vf_morpho.c:63
LUT::I
int I
Definition: vf_morpho.c:70
AV_PIX_FMT_YUV422P12
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:409
free_iplane
static void free_iplane(IPlane *imp)
Definition: vf_morpho.c:719
read_iplane
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:724
AV_PIX_FMT_YUV444P12
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:411
IPlane::img
uint8_t ** img
Definition: vf_morpho.c:49
line_dilate
static void line_dilate(IPlane *g, LUT *Ty, chord_set *SE, int y, int tid)
Definition: vf_morpho.c:441
ff_filter_process_command
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:882
MorphoContext::nb_planes
int nb_planes
Definition: vf_morpho.c:117
chord_set
Definition: vf_morpho.c:83
height
#define height
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
AV_PIX_FMT_YUVA444P
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:167
MorphoContext::structures
int structures
Definition: vf_morpho.c:109
AV_PIX_FMT_YUVA444P10
#define AV_PIX_FMT_YUVA444P10
Definition: pixfmt.h:443
internal.h
chord::l
int l
Definition: vf_morpho.c:79
LUT::min_r
int min_r
Definition: vf_morpho.c:68
build_chord_set
static int build_chord_set(IPlane *SE, chord_set *chords)
Definition: vf_morpho.c:575
MorphoContext::planewidth
int planewidth[4]
Definition: vf_morpho.c:111
max_fun
static void max_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:181
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
MorphoContext::g
IPlane g[4]
Definition: vf_morpho.c:104
OFFSET
#define OFFSET(x)
Definition: vf_morpho.c:126
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_morpho.c:939
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:421
diffinplace16_fun
static void diffinplace16_fun(uint8_t *aa, const uint8_t *bb, int x)
Definition: vf_morpho.c:233
SE
#define SE
Definition: dvdsubenc.c:482
LUT::pre_pad_x
int pre_pad_x
Definition: vf_morpho.c:72
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AV_PIX_FMT_YUVJ440P
@ 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:100
IPlane::w
int w
Definition: vf_morpho.c:50
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:56
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:271
AV_PIX_FMT_YUV444P9
#define AV_PIX_FMT_YUV444P9
Definition: pixfmt.h:403
chord::x
int x
Definition: vf_morpho.c:77
AVFilter
Filter definition.
Definition: avfilter.h:165
max16_fun
static void max16_fun(uint8_t *cc, const uint8_t *aa, const uint8_t *bb, int x)
Definition: vf_morpho.c:242
MorphoContext::temp
AVFrame * temp
Definition: vf_morpho.c:121
ret
ret
Definition: filter_design.txt:187
AV_PIX_FMT_YUVA444P9
#define AV_PIX_FMT_YUVA444P9
Definition: pixfmt.h:440
OPEN
@ OPEN
Definition: vf_morpho.c:40
update_max_lut
static void update_max_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
Definition: vf_morpho.c:421
AV_PIX_FMT_YUV420P12
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:408
circular_swap
static void circular_swap(LUT *Ty)
Definition: vf_morpho.c:343
AV_PIX_FMT_YUV422P14
#define AV_PIX_FMT_YUV422P14
Definition: pixfmt.h:413
framesync.h
mode
mode
Definition: ebur128.h:83
diff_fun
static void diff_fun(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:193
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
AV_PIX_FMT_YUVA422P12
#define AV_PIX_FMT_YUVA422P12
Definition: pixfmt.h:444
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
avfilter.h
MorphoContext::splanewidth
int splanewidth[4]
Definition: vf_morpho.c:113
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_morpho.c:750
MorphoContext::SE
chord_set SE[4]
Definition: vf_morpho.c:102
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
AVFilterContext
An instance of a filter.
Definition: avfilter.h:402
chord_set::maxY
int maxY
Definition: vf_morpho.c:94
MorphModes
MorphModes
Definition: vf_morpho.c:37
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:158
comp_chord
static int comp_chord(const void *p, const void *q)
Definition: vf_morpho.c:566
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
MorphoContext::plane_f
int64_t * plane_f
Definition: vf_morpho.c:123
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
min_fun
static void min_fun(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:169
compute_max_lut
static int compute_max_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
Definition: vf_morpho.c:429
IPlane::type_size
int type_size
Definition: vf_morpho.c:53
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:192
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
comp_chord_length
static int comp_chord_length(const void *p, const void *q)
Definition: vf_morpho.c:557
AV_PIX_FMT_YUV411P
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
BLACKHAT
@ BLACKHAT
Definition: vf_morpho.c:44
update_min_lut
static void update_min_lut(IPlane *f, LUT *Ty, chord_set *SE, int y, int tid, int num)
Definition: vf_morpho.c:380
d
d
Definition: ffmpeg_filter.c:153
AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
#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:154
imgutils.h
AVFrame::linesize
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:355
AV_PIX_FMT_YUV410P
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
IPlane::max_out_place
void(* max_out_place)(uint8_t *c, const uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:55
AV_PIX_FMT_YUV440P12
#define AV_PIX_FMT_YUV440P12
Definition: pixfmt.h:410
h
h
Definition: vp9dsp_template.c:2038
difference
static void difference(IPlane *g, IPlane *f)
Definition: vf_morpho.c:493
AV_PIX_FMT_YUV444P14
#define AV_PIX_FMT_YUV444P14
Definition: pixfmt.h:414
IPlane::max_in_place
void(* max_in_place)(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:58
ff_framesync_activate
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition: framesync.c:336
ff_framesync_dualinput_get
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:371
AV_PIX_FMT_GRAY12
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:386
MorphoContext::type_size
int type_size
Definition: vf_morpho.c:116
erode
static int erode(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty)
Definition: vf_morpho.c:478
compute_min_lut
static int compute_min_lut(LUT *Ty, IPlane *f, chord_set *SE, int y, int num)
Definition: vf_morpho.c:388
ERODE
@ ERODE
Definition: vf_morpho.c:38
MorphoContext::fs
FFFrameSync fs
Definition: vf_morpho.c:100
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:233
morpho_options
static const AVOption morpho_options[]
Definition: vf_morpho.c:129
chord_set::minX
int minX
Definition: vf_morpho.c:91
AV_PIX_FMT_YUVA422P
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition: pixfmt.h:166
AV_PIX_FMT_YUV420P14
#define AV_PIX_FMT_YUV420P14
Definition: pixfmt.h:412
compute_min_row
static void compute_min_row(IPlane *f, LUT *Ty, chord_set *SE, int r, int y)
Definition: vf_morpho.c:359
IPlane::diff_rin_place
void(* diff_rin_place)(uint8_t *a, const uint8_t *b, int x)
Definition: vf_morpho.c:57
dilate
static int dilate(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty)
Definition: vf_morpho.c:463
min
float min
Definition: vorbis_enc_data.h:429