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