FFmpeg
vf_paletteuse.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Stupeflix
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * Use a palette to downsample an input video stream.
24  */
25 
26 #include "libavutil/bprint.h"
27 #include "libavutil/internal.h"
28 #include "libavutil/opt.h"
29 #include "libavutil/qsort.h"
30 #include "avfilter.h"
31 #include "framesync.h"
32 #include "internal.h"
33 
42 };
43 
49 };
50 
51 enum diff_mode {
55 };
56 
57 struct color_node {
58  uint8_t val[4];
59  uint8_t palette_id;
60  int split;
62 };
63 
64 #define NBITS 5
65 #define CACHE_SIZE (1<<(4*NBITS))
66 
67 struct cached_color {
68  uint32_t color;
69  uint8_t pal_entry;
70 };
71 
72 struct cache_node {
75 };
76 
77 struct PaletteUseContext;
78 
80  int x_start, int y_start, int width, int height);
81 
82 typedef struct PaletteUseContext {
83  const AVClass *class;
85  struct cache_node cache[CACHE_SIZE]; /* lookup cache */
86  struct color_node map[AVPALETTE_COUNT]; /* 3D-Tree (KD-Tree with K=3) for reverse colormap */
88  int transparency_index; /* index in the palette of transparency. -1 if there is no transparency in the palette. */
90  int use_alpha;
92  int dither;
93  int new;
96  int ordered_dither[8*8];
97  int diff_mode;
100 
101  /* debug options */
105  uint64_t total_mean_err;
108 
109 #define OFFSET(x) offsetof(PaletteUseContext, x)
110 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
111 static const AVOption paletteuse_options[] = {
112  { "dither", "select dithering mode", OFFSET(dither), AV_OPT_TYPE_INT, {.i64=DITHERING_SIERRA2_4A}, 0, NB_DITHERING-1, FLAGS, "dithering_mode" },
113  { "bayer", "ordered 8x8 bayer dithering (deterministic)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_BAYER}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
114  { "heckbert", "dithering as defined by Paul Heckbert in 1982 (simple error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_HECKBERT}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
115  { "floyd_steinberg", "Floyd and Steingberg dithering (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_FLOYD_STEINBERG}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
116  { "sierra2", "Frankie Sierra dithering v2 (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_SIERRA2}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
117  { "sierra2_4a", "Frankie Sierra dithering v2 \"Lite\" (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_SIERRA2_4A}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
118  { "bayer_scale", "set scale for bayer dithering", OFFSET(bayer_scale), AV_OPT_TYPE_INT, {.i64=2}, 0, 5, FLAGS },
119  { "diff_mode", "set frame difference mode", OFFSET(diff_mode), AV_OPT_TYPE_INT, {.i64=DIFF_MODE_NONE}, 0, NB_DIFF_MODE-1, FLAGS, "diff_mode" },
120  { "rectangle", "process smallest different rectangle", 0, AV_OPT_TYPE_CONST, {.i64=DIFF_MODE_RECTANGLE}, INT_MIN, INT_MAX, FLAGS, "diff_mode" },
121  { "new", "take new palette for each output frame", OFFSET(new), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
122  { "alpha_threshold", "set the alpha threshold for transparency", OFFSET(trans_thresh), AV_OPT_TYPE_INT, {.i64=128}, 0, 255, FLAGS },
123  { "use_alpha", "use alpha channel for mapping", OFFSET(use_alpha), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
124 
125  /* following are the debug options, not part of the official API */
126  { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
127  { "color_search", "set reverse colormap color search method", OFFSET(color_search_method), AV_OPT_TYPE_INT, {.i64=COLOR_SEARCH_NNS_ITERATIVE}, 0, NB_COLOR_SEARCHES-1, FLAGS, "search" },
128  { "nns_iterative", "iterative search", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_ITERATIVE}, INT_MIN, INT_MAX, FLAGS, "search" },
129  { "nns_recursive", "recursive search", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_RECURSIVE}, INT_MIN, INT_MAX, FLAGS, "search" },
130  { "bruteforce", "brute-force into the palette", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_BRUTEFORCE}, INT_MIN, INT_MAX, FLAGS, "search" },
131  { "mean_err", "compute and print mean error", OFFSET(calc_mean_err), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
132  { "debug_accuracy", "test color search accuracy", OFFSET(debug_accuracy), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
133  { NULL }
134 };
135 
136 AVFILTER_DEFINE_CLASS(paletteuse);
137 
138 static int load_apply_palette(FFFrameSync *fs);
139 
141 {
142  static const enum AVPixelFormat in_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
143  static const enum AVPixelFormat inpal_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
144  static const enum AVPixelFormat out_fmts[] = {AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE};
145  int ret;
146  if ((ret = ff_formats_ref(ff_make_format_list(in_fmts),
147  &ctx->inputs[0]->outcfg.formats)) < 0 ||
148  (ret = ff_formats_ref(ff_make_format_list(inpal_fmts),
149  &ctx->inputs[1]->outcfg.formats)) < 0 ||
151  &ctx->outputs[0]->incfg.formats)) < 0)
152  return ret;
153  return 0;
154 }
155 
156 static av_always_inline uint32_t dither_color(uint32_t px, int er, int eg,
157  int eb, int scale, int shift)
158 {
159  return px >> 24 << 24
160  | av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<<shift))) << 16
161  | av_clip_uint8((px >> 8 & 0xff) + ((eg * scale) / (1<<shift))) << 8
162  | av_clip_uint8((px & 0xff) + ((eb * scale) / (1<<shift)));
163 }
164 
165 static av_always_inline int diff(const uint8_t *c1, const uint8_t *c2, const PaletteUseContext *s)
166 {
167  // XXX: try L*a*b with CIE76 (dL*dL + da*da + db*db)
168  const int da = c1[0] - c2[0];
169  const int dr = c1[1] - c2[1];
170  const int dg = c1[2] - c2[2];
171  const int db = c1[3] - c2[3];
172 
173  if (s->use_alpha)
174  return da*da + dr*dr + dg*dg + db*db;
175 
176  if (c1[0] < s->trans_thresh && c2[0] < s->trans_thresh) {
177  return 0;
178  } else if (c1[0] >= s->trans_thresh && c2[0] >= s->trans_thresh) {
179  return dr*dr + dg*dg + db*db;
180  } else {
181  return 255*255 + 255*255 + 255*255;
182  }
183 }
184 
185 static av_always_inline uint8_t colormap_nearest_bruteforce(const PaletteUseContext *s, const uint8_t *argb)
186 {
187  int i, pal_id = -1, min_dist = INT_MAX;
188 
189  for (i = 0; i < AVPALETTE_COUNT; i++) {
190  const uint32_t c = s->palette[i];
191 
192  if (s->use_alpha || c >> 24 >= s->trans_thresh) { // ignore transparent entry
193  const uint8_t palargb[] = {
194  s->palette[i]>>24 & 0xff,
195  s->palette[i]>>16 & 0xff,
196  s->palette[i]>> 8 & 0xff,
197  s->palette[i] & 0xff,
198  };
199  const int d = diff(palargb, argb, s);
200  if (d < min_dist) {
201  pal_id = i;
202  min_dist = d;
203  }
204  }
205  }
206  return pal_id;
207 }
208 
209 /* Recursive form, simpler but a bit slower. Kept for reference. */
211  int node_pos;
212  int dist_sqd;
213 };
214 
216  const struct color_node *map,
217  const int node_pos,
218  const uint8_t *target,
219  struct nearest_color *nearest)
220 {
221  const struct color_node *kd = map + node_pos;
222  const int split = kd->split;
223  int dx, nearer_kd_id, further_kd_id;
224  const uint8_t *current = kd->val;
225  const int current_to_target = diff(target, current, s);
226 
227  if (current_to_target < nearest->dist_sqd) {
228  nearest->node_pos = node_pos;
229  nearest->dist_sqd = current_to_target;
230  }
231 
232  if (kd->left_id != -1 || kd->right_id != -1) {
233  dx = target[split] - current[split];
234 
235  if (dx <= 0) nearer_kd_id = kd->left_id, further_kd_id = kd->right_id;
236  else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
237 
238  if (nearer_kd_id != -1)
239  colormap_nearest_node(s, map, nearer_kd_id, target, nearest);
240 
241  if (further_kd_id != -1 && dx*dx < nearest->dist_sqd)
242  colormap_nearest_node(s, map, further_kd_id, target, nearest);
243  }
244 }
245 
246 static av_always_inline uint8_t colormap_nearest_recursive(const PaletteUseContext *s, const struct color_node *node, const uint8_t *rgb)
247 {
248  struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1};
249  colormap_nearest_node(s, node, 0, rgb, &res);
250  return node[res.node_pos].palette_id;
251 }
252 
253 struct stack_node {
254  int color_id;
255  int dx2;
256 };
257 
258 static av_always_inline uint8_t colormap_nearest_iterative(const PaletteUseContext *s, const struct color_node *root, const uint8_t *target)
259 {
260  int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0;
261  struct stack_node nodes[16];
262  struct stack_node *node = &nodes[0];
263 
264  for (;;) {
265 
266  const struct color_node *kd = &root[cur_color_id];
267  const uint8_t *current = kd->val;
268  const int current_to_target = diff(target, current, s);
269 
270  /* Compare current color node to the target and update our best node if
271  * it's actually better. */
272  if (current_to_target < best_dist) {
273  best_node_id = cur_color_id;
274  if (!current_to_target)
275  goto end; // exact match, we can return immediately
276  best_dist = current_to_target;
277  }
278 
279  /* Check if it's not a leaf */
280  if (kd->left_id != -1 || kd->right_id != -1) {
281  const int split = kd->split;
282  const int dx = target[split] - current[split];
283  int nearer_kd_id, further_kd_id;
284 
285  /* Define which side is the most interesting. */
286  if (dx <= 0) nearer_kd_id = kd->left_id, further_kd_id = kd->right_id;
287  else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
288 
289  if (nearer_kd_id != -1) {
290  if (further_kd_id != -1) {
291  /* Here, both paths are defined, so we push a state for
292  * when we are going back. */
293  node->color_id = further_kd_id;
294  node->dx2 = dx*dx;
295  pos++;
296  node++;
297  }
298  /* We can now update current color with the most probable path
299  * (no need to create a state since there is nothing to save
300  * anymore). */
301  cur_color_id = nearer_kd_id;
302  continue;
303  } else if (dx*dx < best_dist) {
304  /* The nearest path isn't available, so there is only one path
305  * possible and it's the least probable. We enter it only if the
306  * distance from the current point to the hyper rectangle is
307  * less than our best distance. */
308  cur_color_id = further_kd_id;
309  continue;
310  }
311  }
312 
313  /* Unstack as much as we can, typically as long as the least probable
314  * branch aren't actually probable. */
315  do {
316  if (--pos < 0)
317  goto end;
318  node--;
319  } while (node->dx2 >= best_dist);
320 
321  /* We got a node where the least probable branch might actually contain
322  * a relevant color. */
323  cur_color_id = node->color_id;
324  }
325 
326 end:
327  return root[best_node_id].palette_id;
328 }
329 
330 #define COLORMAP_NEAREST(s, search, root, target) \
331  search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(s, root, target) : \
332  search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(s, root, target) : \
333  colormap_nearest_bruteforce(s, target)
334 
335 /**
336  * Check if the requested color is in the cache already. If not, find it in the
337  * color tree and cache it.
338  * Note: a, r, g, and b are the components of color, but are passed as well to avoid
339  * recomputing them (they are generally computed by the caller for other uses).
340  */
342  uint8_t a, uint8_t r, uint8_t g, uint8_t b,
343  const enum color_search_method search_method)
344 {
345  int i;
346  const uint8_t argb_elts[] = {a, r, g, b};
347  const uint8_t rhash = r & ((1<<NBITS)-1);
348  const uint8_t ghash = g & ((1<<NBITS)-1);
349  const uint8_t bhash = b & ((1<<NBITS)-1);
350  const unsigned hash = rhash<<(NBITS*2) | ghash<<NBITS | bhash;
351  struct cache_node *node = &s->cache[hash];
352  struct cached_color *e;
353 
354  // first, check for transparency
355  if (a < s->trans_thresh && s->transparency_index >= 0) {
356  return s->transparency_index;
357  }
358 
359  for (i = 0; i < node->nb_entries; i++) {
360  e = &node->entries[i];
361  if (e->color == color)
362  return e->pal_entry;
363  }
364 
365  e = av_dynarray2_add((void**)&node->entries, &node->nb_entries,
366  sizeof(*node->entries), NULL);
367  if (!e)
368  return AVERROR(ENOMEM);
369  e->color = color;
370  e->pal_entry = COLORMAP_NEAREST(s, search_method, s->map, argb_elts);
371 
372  return e->pal_entry;
373 }
374 
376  uint32_t c, int *ea, int *er, int *eg, int *eb,
377  const enum color_search_method search_method)
378 {
379  const uint8_t a = c >> 24 & 0xff;
380  const uint8_t r = c >> 16 & 0xff;
381  const uint8_t g = c >> 8 & 0xff;
382  const uint8_t b = c & 0xff;
383  uint32_t dstc;
384  const int dstx = color_get(s, c, a, r, g, b, search_method);
385  if (dstx < 0)
386  return dstx;
387  dstc = s->palette[dstx];
388  if (dstx == s->transparency_index) {
389  *ea =*er = *eg = *eb = 0;
390  } else {
391  *ea = (int)a - (int)(dstc >> 24 & 0xff);
392  *er = (int)r - (int)(dstc >> 16 & 0xff);
393  *eg = (int)g - (int)(dstc >> 8 & 0xff);
394  *eb = (int)b - (int)(dstc & 0xff);
395  }
396  return dstx;
397 }
398 
400  int x_start, int y_start, int w, int h,
401  enum dithering_mode dither,
402  const enum color_search_method search_method)
403 {
404  int x, y;
405  const int src_linesize = in ->linesize[0] >> 2;
406  const int dst_linesize = out->linesize[0];
407  uint32_t *src = ((uint32_t *)in ->data[0]) + y_start*src_linesize;
408  uint8_t *dst = out->data[0] + y_start*dst_linesize;
409 
410  w += x_start;
411  h += y_start;
412 
413  for (y = y_start; y < h; y++) {
414  for (x = x_start; x < w; x++) {
415  int ea, er, eg, eb;
416 
417  if (dither == DITHERING_BAYER) {
418  const int d = s->ordered_dither[(y & 7)<<3 | (x & 7)];
419  const uint8_t a8 = src[x] >> 24 & 0xff;
420  const uint8_t r8 = src[x] >> 16 & 0xff;
421  const uint8_t g8 = src[x] >> 8 & 0xff;
422  const uint8_t b8 = src[x] & 0xff;
423  const uint8_t r = av_clip_uint8(r8 + d);
424  const uint8_t g = av_clip_uint8(g8 + d);
425  const uint8_t b = av_clip_uint8(b8 + d);
426  const uint32_t color_new = (unsigned)(a8) << 24 | r << 16 | g << 8 | b;
427  const int color = color_get(s, color_new, a8, r, g, b, search_method);
428 
429  if (color < 0)
430  return color;
431  dst[x] = color;
432 
433  } else if (dither == DITHERING_HECKBERT) {
434  const int right = x < w - 1, down = y < h - 1;
435  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
436 
437  if (color < 0)
438  return color;
439  dst[x] = color;
440 
441  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 3, 3);
442  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 3, 3);
443  if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 2, 3);
444 
445  } else if (dither == DITHERING_FLOYD_STEINBERG) {
446  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
447  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
448 
449  if (color < 0)
450  return color;
451  dst[x] = color;
452 
453  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 7, 4);
454  if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 3, 4);
455  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 5, 4);
456  if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 1, 4);
457 
458  } else if (dither == DITHERING_SIERRA2) {
459  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
460  const int right2 = x < w - 2, left2 = x > x_start + 1;
461  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
462 
463  if (color < 0)
464  return color;
465  dst[x] = color;
466 
467  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 4, 4);
468  if (right2) src[ x + 2] = dither_color(src[ x + 2], er, eg, eb, 3, 4);
469 
470  if (down) {
471  if (left2) src[ src_linesize + x - 2] = dither_color(src[ src_linesize + x - 2], er, eg, eb, 1, 4);
472  if (left) src[ src_linesize + x - 1] = dither_color(src[ src_linesize + x - 1], er, eg, eb, 2, 4);
473  if (1) src[ src_linesize + x ] = dither_color(src[ src_linesize + x ], er, eg, eb, 3, 4);
474  if (right) src[ src_linesize + x + 1] = dither_color(src[ src_linesize + x + 1], er, eg, eb, 2, 4);
475  if (right2) src[ src_linesize + x + 2] = dither_color(src[ src_linesize + x + 2], er, eg, eb, 1, 4);
476  }
477 
478  } else if (dither == DITHERING_SIERRA2_4A) {
479  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
480  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
481 
482  if (color < 0)
483  return color;
484  dst[x] = color;
485 
486  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 2, 2);
487  if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 1, 2);
488  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 1, 2);
489 
490  } else {
491  const uint8_t a = src[x] >> 24 & 0xff;
492  const uint8_t r = src[x] >> 16 & 0xff;
493  const uint8_t g = src[x] >> 8 & 0xff;
494  const uint8_t b = src[x] & 0xff;
495  const int color = color_get(s, src[x], a, r, g, b, search_method);
496 
497  if (color < 0)
498  return color;
499  dst[x] = color;
500  }
501  }
502  src += src_linesize;
503  dst += dst_linesize;
504  }
505  return 0;
506 }
507 
508 #define INDENT 4
509 static void disp_node(AVBPrint *buf,
510  const struct color_node *map,
511  int parent_id, int node_id,
512  int depth)
513 {
514  const struct color_node *node = &map[node_id];
515  const uint32_t fontcolor = node->val[1] > 0x50 &&
516  node->val[2] > 0x50 &&
517  node->val[3] > 0x50 ? 0 : 0xffffff;
518  const int rgb_comp = node->split - 1;
519  av_bprintf(buf, "%*cnode%d ["
520  "label=\"%c%02X%c%02X%c%02X%c\" "
521  "fillcolor=\"#%02x%02x%02x\" "
522  "fontcolor=\"#%06"PRIX32"\"]\n",
523  depth*INDENT, ' ', node->palette_id,
524  "[ "[rgb_comp], node->val[1],
525  "][ "[rgb_comp], node->val[2],
526  " ]["[rgb_comp], node->val[3],
527  " ]"[rgb_comp],
528  node->val[1], node->val[2], node->val[3],
529  fontcolor);
530  if (parent_id != -1)
531  av_bprintf(buf, "%*cnode%d -> node%d\n", depth*INDENT, ' ',
532  map[parent_id].palette_id, node->palette_id);
533  if (node->left_id != -1) disp_node(buf, map, node_id, node->left_id, depth + 1);
534  if (node->right_id != -1) disp_node(buf, map, node_id, node->right_id, depth + 1);
535 }
536 
537 // debug_kdtree=kdtree.dot -> dot -Tpng kdtree.dot > kdtree.png
538 static int disp_tree(const struct color_node *node, const char *fname)
539 {
540  AVBPrint buf;
541  FILE *f = av_fopen_utf8(fname, "w");
542 
543  if (!f) {
544  int ret = AVERROR(errno);
545  av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n",
546  fname, av_err2str(ret));
547  return ret;
548  }
549 
551 
552  av_bprintf(&buf, "digraph {\n");
553  av_bprintf(&buf, " node [style=filled fontsize=10 shape=box]\n");
554  disp_node(&buf, node, -1, 0, 0);
555  av_bprintf(&buf, "}\n");
556 
557  fwrite(buf.str, 1, buf.len, f);
558  fclose(f);
559  av_bprint_finalize(&buf, NULL);
560  return 0;
561 }
562 
564 {
565  int r, g, b, ret = 0;
566 
567  for (r = 0; r < 256; r++) {
568  for (g = 0; g < 256; g++) {
569  for (b = 0; b < 256; b++) {
570  const uint8_t argb[] = {0xff, r, g, b};
571  const int r1 = COLORMAP_NEAREST(s, s->color_search_method, s->map, argb);
572  const int r2 = colormap_nearest_bruteforce(s, argb);
573  if (r1 != r2) {
574  const uint32_t c1 = s->palette[r1];
575  const uint32_t c2 = s->palette[r2];
576  const uint8_t a1 = s->use_alpha ? c1>>24 & 0xff : 0xff;
577  const uint8_t a2 = s->use_alpha ? c2>>24 & 0xff : 0xff;
578  const uint8_t palargb1[] = { a1, c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff };
579  const uint8_t palargb2[] = { a2, c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff };
580  const int d1 = diff(palargb1, argb, s);
581  const int d2 = diff(palargb2, argb, s);
582  if (d1 != d2) {
583  if (s->use_alpha)
585  "/!\\ %02X%02X%02X: %d ! %d (%08"PRIX32" ! %08"PRIX32") / dist: %d ! %d\n",
586  r, g, b, r1, r2, c1, c2, d1, d2);
587  else
589  "/!\\ %02X%02X%02X: %d ! %d (%06"PRIX32" ! %06"PRIX32") / dist: %d ! %d\n",
590  r, g, b, r1, r2, c1 & 0xffffff, c2 & 0xffffff, d1, d2);
591  ret = 1;
592  }
593  }
594  }
595  }
596  }
597  return ret;
598 }
599 
600 struct color {
601  uint32_t value;
602  uint8_t pal_id;
603 };
604 
605 struct color_rect {
606  uint8_t min[4];
607  uint8_t max[4];
608 };
609 
610 typedef int (*cmp_func)(const void *, const void *);
611 
612 #define DECLARE_CMP_FUNC(name, pos) \
613 static int cmp_##name(const void *pa, const void *pb) \
614 { \
615  const struct color *a = pa; \
616  const struct color *b = pb; \
617  return (int)(a->value >> (8 * (3 - (pos))) & 0xff) \
618  - (int)(b->value >> (8 * (3 - (pos))) & 0xff); \
619 }
620 
625 
626 static const cmp_func cmp_funcs[] = {cmp_a, cmp_r, cmp_g, cmp_b};
627 
628 static int get_next_color(const uint8_t *color_used, const PaletteUseContext *s,
629  int *component, const struct color_rect *box)
630 {
631  int wa, wr, wg, wb;
632  int i, longest = 0;
633  unsigned nb_color = 0;
634  struct color_rect ranges;
635  struct color tmp_pal[256];
636  cmp_func cmpf;
637 
638  ranges.min[0] = ranges.min[1] = ranges.min[2] = ranges.min[3]= 0xff;
639  ranges.max[0] = ranges.max[1] = ranges.max[2] = ranges.max[3]= 0x00;
640 
641  for (i = 0; i < AVPALETTE_COUNT; i++) {
642  const uint32_t c = s->palette[i];
643  const uint8_t a = c >> 24 & 0xff;
644  const uint8_t r = c >> 16 & 0xff;
645  const uint8_t g = c >> 8 & 0xff;
646  const uint8_t b = c & 0xff;
647 
648  if (!s->use_alpha && a < s->trans_thresh) {
649  continue;
650  }
651 
652  if (color_used[i] || (a != 0xff && !s->use_alpha) ||
653  r < box->min[1] || g < box->min[2] || b < box->min[3] ||
654  r > box->max[1] || g > box->max[2] || b > box->max[3])
655  continue;
656 
657  if (s->use_alpha && (a < box->min[0] || a > box->max[0]))
658  continue;
659 
660  if (a < ranges.min[0]) ranges.min[0] = a;
661  if (r < ranges.min[1]) ranges.min[1] = r;
662  if (g < ranges.min[2]) ranges.min[2] = g;
663  if (b < ranges.min[3]) ranges.min[3] = b;
664 
665  if (a > ranges.max[0]) ranges.max[0] = a;
666  if (r > ranges.max[1]) ranges.max[1] = r;
667  if (g > ranges.max[2]) ranges.max[2] = g;
668  if (b > ranges.max[3]) ranges.max[3] = b;
669 
670  tmp_pal[nb_color].value = c;
671  tmp_pal[nb_color].pal_id = i;
672 
673  nb_color++;
674  }
675 
676  if (!nb_color)
677  return -1;
678 
679  /* define longest axis that will be the split component */
680  wa = ranges.max[0] - ranges.min[0];
681  wr = ranges.max[1] - ranges.min[1];
682  wg = ranges.max[2] - ranges.min[2];
683  wb = ranges.max[3] - ranges.min[3];
684 
685  if (s->use_alpha) {
686  if (wa >= wr && wa >= wb && wa >= wg) longest = 0;
687  if (wr >= wg && wr >= wb && wr >= wa) longest = 1;
688  if (wg >= wr && wg >= wb && wg >= wa) longest = 2;
689  if (wb >= wr && wb >= wg && wb >= wa) longest = 3;
690  } else {
691  if (wr >= wg && wr >= wb) longest = 1;
692  if (wg >= wr && wg >= wb) longest = 2;
693  if (wb >= wr && wb >= wg) longest = 3;
694  }
695 
696  cmpf = cmp_funcs[longest];
697  *component = longest;
698 
699  /* sort along this axis to get median */
700  AV_QSORT(tmp_pal, nb_color, struct color, cmpf);
701 
702  return tmp_pal[nb_color >> 1].pal_id;
703 }
704 
705 static int colormap_insert(struct color_node *map,
706  uint8_t *color_used,
707  int *nb_used,
708  const PaletteUseContext *s,
709  const struct color_rect *box)
710 {
711  uint32_t c;
712  int component, cur_id;
713  int node_left_id = -1, node_right_id = -1;
714  struct color_node *node;
715  struct color_rect box1, box2;
716  const int pal_id = get_next_color(color_used, s, &component, box);
717 
718  if (pal_id < 0)
719  return -1;
720 
721  /* create new node with that color */
722  cur_id = (*nb_used)++;
723  c = s->palette[pal_id];
724  node = &map[cur_id];
725  node->split = component;
726  node->palette_id = pal_id;
727  node->val[0] = c>>24 & 0xff;
728  node->val[1] = c>>16 & 0xff;
729  node->val[2] = c>> 8 & 0xff;
730  node->val[3] = c & 0xff;
731 
732  color_used[pal_id] = 1;
733 
734  /* get the two boxes this node creates */
735  box1 = box2 = *box;
736  box1.max[component] = node->val[component];
737  box2.min[component] = FFMIN(node->val[component] + 1, 255);
738 
739  node_left_id = colormap_insert(map, color_used, nb_used, s, &box1);
740 
741  if (box2.min[component] <= box2.max[component])
742  node_right_id = colormap_insert(map, color_used, nb_used, s, &box2);
743 
744  node->left_id = node_left_id;
745  node->right_id = node_right_id;
746 
747  return cur_id;
748 }
749 
750 static int cmp_pal_entry(const void *a, const void *b)
751 {
752  const int c1 = *(const uint32_t *)a & 0xffffff;
753  const int c2 = *(const uint32_t *)b & 0xffffff;
754  return c1 - c2;
755 }
756 
757 static int cmp_pal_entry_alpha(const void *a, const void *b)
758 {
759  const int c1 = *(const uint32_t *)a;
760  const int c2 = *(const uint32_t *)b;
761  return c1 - c2;
762 }
763 
765 {
766  int i, nb_used = 0;
767  uint8_t color_used[AVPALETTE_COUNT] = {0};
768  uint32_t last_color = 0;
769  struct color_rect box;
770 
771  if (!s->use_alpha && s->transparency_index >= 0) {
772  FFSWAP(uint32_t, s->palette[s->transparency_index], s->palette[255]);
773  }
774 
775  /* disable transparent colors and dups */
776  qsort(s->palette, AVPALETTE_COUNT-(s->transparency_index >= 0), sizeof(*s->palette),
777  s->use_alpha ? cmp_pal_entry_alpha : cmp_pal_entry);
778 
779  for (i = 0; i < AVPALETTE_COUNT; i++) {
780  const uint32_t c = s->palette[i];
781  if (i != 0 && c == last_color) {
782  color_used[i] = 1;
783  continue;
784  }
785  last_color = c;
786  if (!s->use_alpha && c >> 24 < s->trans_thresh) {
787  color_used[i] = 1; // ignore transparent color(s)
788  continue;
789  }
790  }
791 
792  box.min[0] = box.min[1] = box.min[2] = box.min[3] = 0x00;
793  box.max[0] = box.max[1] = box.max[2] = box.max[3] = 0xff;
794 
795  colormap_insert(s->map, color_used, &nb_used, s, &box);
796 
797  if (s->dot_filename)
798  disp_tree(s->map, s->dot_filename);
799 
800  if (s->debug_accuracy) {
801  if (!debug_accuracy(s))
802  av_log(NULL, AV_LOG_INFO, "Accuracy check passed\n");
803  }
804 }
805 
806 static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1,
807  const AVFrame *in2, int frame_count)
808 {
809  int x, y;
810  const uint32_t *palette = s->palette;
811  uint32_t *src1 = (uint32_t *)in1->data[0];
812  uint8_t *src2 = in2->data[0];
813  const int src1_linesize = in1->linesize[0] >> 2;
814  const int src2_linesize = in2->linesize[0];
815  const float div = in1->width * in1->height * (s->use_alpha ? 4 : 3);
816  unsigned mean_err = 0;
817 
818  for (y = 0; y < in1->height; y++) {
819  for (x = 0; x < in1->width; x++) {
820  const uint32_t c1 = src1[x];
821  const uint32_t c2 = palette[src2[x]];
822  const uint8_t a1 = s->use_alpha ? c1>>24 & 0xff : 0xff;
823  const uint8_t a2 = s->use_alpha ? c2>>24 & 0xff : 0xff;
824  const uint8_t argb1[] = {a1, c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff};
825  const uint8_t argb2[] = {a2, c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff};
826  mean_err += diff(argb1, argb2, s);
827  }
828  src1 += src1_linesize;
829  src2 += src2_linesize;
830  }
831 
832  s->total_mean_err += mean_err;
833 
834  av_log(NULL, AV_LOG_INFO, "MEP:%.3f TotalMEP:%.3f\n",
835  mean_err / div, s->total_mean_err / (div * frame_count));
836 }
837 
839  const AVFrame *prv_src, const AVFrame *cur_src,
840  const AVFrame *prv_dst, AVFrame *cur_dst,
841  int *xp, int *yp, int *wp, int *hp)
842 {
843  int x_start = 0, y_start = 0;
844  int width = cur_src->width;
845  int height = cur_src->height;
846 
847  if (prv_src->data[0] && diff_mode == DIFF_MODE_RECTANGLE) {
848  int y;
849  int x_end = cur_src->width - 1,
850  y_end = cur_src->height - 1;
851  const uint32_t *prv_srcp = (const uint32_t *)prv_src->data[0];
852  const uint32_t *cur_srcp = (const uint32_t *)cur_src->data[0];
853  const uint8_t *prv_dstp = prv_dst->data[0];
854  uint8_t *cur_dstp = cur_dst->data[0];
855 
856  const int prv_src_linesize = prv_src->linesize[0] >> 2;
857  const int cur_src_linesize = cur_src->linesize[0] >> 2;
858  const int prv_dst_linesize = prv_dst->linesize[0];
859  const int cur_dst_linesize = cur_dst->linesize[0];
860 
861  /* skip common lines */
862  while (y_start < y_end && !memcmp(prv_srcp + y_start*prv_src_linesize,
863  cur_srcp + y_start*cur_src_linesize,
864  cur_src->width * 4)) {
865  memcpy(cur_dstp + y_start*cur_dst_linesize,
866  prv_dstp + y_start*prv_dst_linesize,
867  cur_dst->width);
868  y_start++;
869  }
870  while (y_end > y_start && !memcmp(prv_srcp + y_end*prv_src_linesize,
871  cur_srcp + y_end*cur_src_linesize,
872  cur_src->width * 4)) {
873  memcpy(cur_dstp + y_end*cur_dst_linesize,
874  prv_dstp + y_end*prv_dst_linesize,
875  cur_dst->width);
876  y_end--;
877  }
878 
879  height = y_end + 1 - y_start;
880 
881  /* skip common columns */
882  while (x_start < x_end) {
883  int same_column = 1;
884  for (y = y_start; y <= y_end; y++) {
885  if (prv_srcp[y*prv_src_linesize + x_start] != cur_srcp[y*cur_src_linesize + x_start]) {
886  same_column = 0;
887  break;
888  }
889  }
890  if (!same_column)
891  break;
892  x_start++;
893  }
894  while (x_end > x_start) {
895  int same_column = 1;
896  for (y = y_start; y <= y_end; y++) {
897  if (prv_srcp[y*prv_src_linesize + x_end] != cur_srcp[y*cur_src_linesize + x_end]) {
898  same_column = 0;
899  break;
900  }
901  }
902  if (!same_column)
903  break;
904  x_end--;
905  }
906  width = x_end + 1 - x_start;
907 
908  if (x_start) {
909  for (y = y_start; y <= y_end; y++)
910  memcpy(cur_dstp + y*cur_dst_linesize,
911  prv_dstp + y*prv_dst_linesize, x_start);
912  }
913  if (x_end != cur_src->width - 1) {
914  const int copy_len = cur_src->width - 1 - x_end;
915  for (y = y_start; y <= y_end; y++)
916  memcpy(cur_dstp + y*cur_dst_linesize + x_end + 1,
917  prv_dstp + y*prv_dst_linesize + x_end + 1,
918  copy_len);
919  }
920  }
921  *xp = x_start;
922  *yp = y_start;
923  *wp = width;
924  *hp = height;
925 }
926 
928 {
929  int x, y, w, h, ret;
930  AVFilterContext *ctx = inlink->dst;
931  PaletteUseContext *s = ctx->priv;
932  AVFilterLink *outlink = inlink->dst->outputs[0];
933 
934  AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
935  if (!out) {
936  *outf = NULL;
937  return AVERROR(ENOMEM);
938  }
940 
941  set_processing_window(s->diff_mode, s->last_in, in,
942  s->last_out, out, &x, &y, &w, &h);
943  av_frame_unref(s->last_in);
944  av_frame_unref(s->last_out);
945  if ((ret = av_frame_ref(s->last_in, in)) < 0 ||
946  (ret = av_frame_ref(s->last_out, out)) < 0 ||
947  (ret = av_frame_make_writable(s->last_in)) < 0) {
948  av_frame_free(&out);
949  *outf = NULL;
950  return ret;
951  }
952 
953  ff_dlog(ctx, "%dx%d rect: (%d;%d) -> (%d,%d) [area:%dx%d]\n",
954  w, h, x, y, x+w, y+h, in->width, in->height);
955 
956  ret = s->set_frame(s, out, in, x, y, w, h);
957  if (ret < 0) {
958  av_frame_free(&out);
959  *outf = NULL;
960  return ret;
961  }
962  memcpy(out->data[1], s->palette, AVPALETTE_SIZE);
963  if (s->calc_mean_err)
964  debug_mean_error(s, in, out, inlink->frame_count_out);
965  *outf = out;
966  return 0;
967 }
968 
969 static int config_output(AVFilterLink *outlink)
970 {
971  int ret;
972  AVFilterContext *ctx = outlink->src;
973  PaletteUseContext *s = ctx->priv;
974 
976  if (ret < 0)
977  return ret;
978  s->fs.opt_repeatlast = 1; // only 1 frame in the palette
979  s->fs.in[1].before = s->fs.in[1].after = EXT_INFINITY;
980  s->fs.on_event = load_apply_palette;
981 
982  outlink->w = ctx->inputs[0]->w;
983  outlink->h = ctx->inputs[0]->h;
984 
985  outlink->time_base = ctx->inputs[0]->time_base;
986  if ((ret = ff_framesync_configure(&s->fs)) < 0)
987  return ret;
988  return 0;
989 }
990 
992 {
993  AVFilterContext *ctx = inlink->dst;
994 
995  if (inlink->w * inlink->h != AVPALETTE_COUNT) {
997  "Palette input must contain exactly %d pixels. "
998  "Specified input has %dx%d=%d pixels\n",
999  AVPALETTE_COUNT, inlink->w, inlink->h,
1000  inlink->w * inlink->h);
1001  return AVERROR(EINVAL);
1002  }
1003  return 0;
1004 }
1005 
1006 static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame)
1007 {
1008  int i, x, y;
1009  const uint32_t *p = (const uint32_t *)palette_frame->data[0];
1010  const int p_linesize = palette_frame->linesize[0] >> 2;
1011 
1012  s->transparency_index = -1;
1013 
1014  if (s->new) {
1015  memset(s->palette, 0, sizeof(s->palette));
1016  memset(s->map, 0, sizeof(s->map));
1017  for (i = 0; i < CACHE_SIZE; i++)
1018  av_freep(&s->cache[i].entries);
1019  memset(s->cache, 0, sizeof(s->cache));
1020  }
1021 
1022  i = 0;
1023  for (y = 0; y < palette_frame->height; y++) {
1024  for (x = 0; x < palette_frame->width; x++) {
1025  s->palette[i] = p[x];
1026  if (!s->use_alpha && p[x]>>24 < s->trans_thresh) {
1027  s->transparency_index = i; // we are assuming at most one transparent color in palette
1028  }
1029  i++;
1030  }
1031  p += p_linesize;
1032  }
1033 
1034  load_colormap(s);
1035 
1036  if (!s->new)
1037  s->palette_loaded = 1;
1038 }
1039 
1041 {
1042  AVFilterContext *ctx = fs->parent;
1043  AVFilterLink *inlink = ctx->inputs[0];
1044  PaletteUseContext *s = ctx->priv;
1045  AVFrame *master, *second, *out = NULL;
1046  int ret;
1047 
1048  // writable for error diffusal dithering
1050  if (ret < 0)
1051  return ret;
1052  if (!master || !second) {
1054  return AVERROR_BUG;
1055  }
1056  if (!s->palette_loaded) {
1057  load_palette(s, second);
1058  }
1061  if (ret < 0)
1062  return ret;
1063  return ff_filter_frame(ctx->outputs[0], out);
1064 }
1065 
1066 #define DEFINE_SET_FRAME(color_search, name, value) \
1067 static int set_frame_##name(PaletteUseContext *s, AVFrame *out, AVFrame *in, \
1068  int x_start, int y_start, int w, int h) \
1069 { \
1070  return set_frame(s, out, in, x_start, y_start, w, h, value, color_search); \
1071 }
1072 
1073 #define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro) \
1074  DEFINE_SET_FRAME(color_search_macro, color_search##_##none, DITHERING_NONE) \
1075  DEFINE_SET_FRAME(color_search_macro, color_search##_##bayer, DITHERING_BAYER) \
1076  DEFINE_SET_FRAME(color_search_macro, color_search##_##heckbert, DITHERING_HECKBERT) \
1077  DEFINE_SET_FRAME(color_search_macro, color_search##_##floyd_steinberg, DITHERING_FLOYD_STEINBERG) \
1078  DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2, DITHERING_SIERRA2) \
1079  DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2_4a, DITHERING_SIERRA2_4A) \
1080 
1084 
1085 #define DITHERING_ENTRIES(color_search) { \
1086  set_frame_##color_search##_none, \
1087  set_frame_##color_search##_bayer, \
1088  set_frame_##color_search##_heckbert, \
1089  set_frame_##color_search##_floyd_steinberg, \
1090  set_frame_##color_search##_sierra2, \
1091  set_frame_##color_search##_sierra2_4a, \
1092 }
1093 
1095  DITHERING_ENTRIES(nns_iterative),
1096  DITHERING_ENTRIES(nns_recursive),
1097  DITHERING_ENTRIES(bruteforce),
1098 };
1099 
1100 static int dither_value(int p)
1101 {
1102  const int q = p ^ (p >> 3);
1103  return (p & 4) >> 2 | (q & 4) >> 1 \
1104  | (p & 2) << 1 | (q & 2) << 2 \
1105  | (p & 1) << 4 | (q & 1) << 5;
1106 }
1107 
1109 {
1110  PaletteUseContext *s = ctx->priv;
1111 
1112  s->last_in = av_frame_alloc();
1113  s->last_out = av_frame_alloc();
1114  if (!s->last_in || !s->last_out)
1115  return AVERROR(ENOMEM);
1116 
1117  s->set_frame = set_frame_lut[s->color_search_method][s->dither];
1118 
1119  if (s->dither == DITHERING_BAYER) {
1120  int i;
1121  const int delta = 1 << (5 - s->bayer_scale); // to avoid too much luma
1122 
1123  for (i = 0; i < FF_ARRAY_ELEMS(s->ordered_dither); i++)
1124  s->ordered_dither[i] = (dither_value(i) >> s->bayer_scale) - delta;
1125  }
1126 
1127  return 0;
1128 }
1129 
1131 {
1132  PaletteUseContext *s = ctx->priv;
1133  return ff_framesync_activate(&s->fs);
1134 }
1135 
1137 {
1138  int i;
1139  PaletteUseContext *s = ctx->priv;
1140 
1141  ff_framesync_uninit(&s->fs);
1142  for (i = 0; i < CACHE_SIZE; i++)
1143  av_freep(&s->cache[i].entries);
1144  av_frame_free(&s->last_in);
1145  av_frame_free(&s->last_out);
1146 }
1147 
1148 static const AVFilterPad paletteuse_inputs[] = {
1149  {
1150  .name = "default",
1151  .type = AVMEDIA_TYPE_VIDEO,
1152  },{
1153  .name = "palette",
1154  .type = AVMEDIA_TYPE_VIDEO,
1155  .config_props = config_input_palette,
1156  },
1157 };
1158 
1160  {
1161  .name = "default",
1162  .type = AVMEDIA_TYPE_VIDEO,
1163  .config_props = config_output,
1164  },
1165 };
1166 
1168  .name = "paletteuse",
1169  .description = NULL_IF_CONFIG_SMALL("Use a palette to downsample an input video stream."),
1170  .priv_size = sizeof(PaletteUseContext),
1171  .init = init,
1172  .uninit = uninit,
1173  .activate = activate,
1177  .priv_class = &paletteuse_class,
1178 };
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
cached_color::color
uint32_t color
Definition: vf_paletteuse.c:68
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:119
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
config_input_palette
static int config_input_palette(AVFilterLink *inlink)
Definition: vf_paletteuse.c:991
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
PaletteUseContext::use_alpha
int use_alpha
Definition: vf_paletteuse.c:90
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_paletteuse.c:140
cmp_pal_entry_alpha
static int cmp_pal_entry_alpha(const void *a, const void *b)
Definition: vf_paletteuse.c:757
PaletteUseContext::dot_filename
char * dot_filename
Definition: vf_paletteuse.c:102
r
const char * r
Definition: vf_curves.c:116
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
ff_make_format_list
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:381
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:234
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:285
debug_mean_error
static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1, const AVFrame *in2, int frame_count)
Definition: vf_paletteuse.c:806
out
FILE * out
Definition: movenc.c:54
color
Definition: vf_paletteuse.c:600
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:68
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1018
diff
static av_always_inline int diff(const uint8_t *c1, const uint8_t *c2, const PaletteUseContext *s)
Definition: vf_paletteuse.c:165
src1
const pixel * src1
Definition: h264pred_template.c:421
PaletteUseContext::last_out
AVFrame * last_out
Definition: vf_paletteuse.c:99
dither_color
static av_always_inline uint32_t dither_color(uint32_t px, int er, int eg, int eb, int scale, int shift)
Definition: vf_paletteuse.c:156
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
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
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_paletteuse.c:1108
set_frame_func
int(* set_frame_func)(struct PaletteUseContext *s, AVFrame *out, AVFrame *in, int x_start, int y_start, int width, int height)
Definition: vf_paletteuse.c:79
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:317
av_frame_make_writable
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
Definition: frame.c:490
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_paletteuse.c:1136
AVFrame::width
int width
Definition: frame.h:389
w
uint8_t w
Definition: llviddspenc.c:38
av_dynarray2_add
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
Definition: mem.c:350
AVOption
AVOption.
Definition: opt.h:247
b
#define b
Definition: input.c:40
FILTER_QUERY_FUNC
#define FILTER_QUERY_FUNC(func)
Definition: internal.h:168
stack_node::dx2
int dx2
Definition: vf_paletteuse.c:255
data
const char data[16]
Definition: mxf.c:143
PaletteUseContext::set_frame
set_frame_func set_frame
Definition: vf_paletteuse.c:94
disp_tree
static int disp_tree(const struct color_node *node, const char *fname)
Definition: vf_paletteuse.c:538
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:169
c1
static const uint64_t c1
Definition: murmur3.c:51
FFFrameSync
Frame sync structure.
Definition: framesync.h:146
EXT_INFINITY
@ EXT_INFINITY
Extend the frame to infinity.
Definition: framesync.h:75
hash
uint8_t hash[HASH_SIZE]
Definition: movenc.c:57
PaletteUseContext::palette_loaded
int palette_loaded
Definition: vf_paletteuse.c:91
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:338
stack_node::color_id
int color_id
Definition: vf_paletteuse.c:254
DIFF_MODE_NONE
@ DIFF_MODE_NONE
Definition: vf_paletteuse.c:52
rgb
Definition: rpzaenc.c:59
NB_DITHERING
@ NB_DITHERING
Definition: vf_paletteuse.c:41
dither_value
static int dither_value(int p)
Definition: vf_paletteuse.c:1100
COLOR_SEARCH_BRUTEFORCE
@ COLOR_SEARCH_BRUTEFORCE
Definition: vf_paletteuse.c:47
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1388
apply_palette
static int apply_palette(AVFilterLink *inlink, AVFrame *in, AVFrame **outf)
Definition: vf_paletteuse.c:927
PaletteUseContext::cache
struct cache_node cache[CACHE_SIZE]
Definition: vf_paletteuse.c:85
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:50
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:97
a1
#define a1
Definition: regdef.h:47
colormap_nearest_bruteforce
static av_always_inline uint8_t colormap_nearest_bruteforce(const PaletteUseContext *s, const uint8_t *argb)
Definition: vf_paletteuse.c:185
PaletteUseContext::ordered_dither
int ordered_dither[8 *8]
Definition: vf_paletteuse.c:96
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
set_processing_window
static void set_processing_window(enum diff_mode diff_mode, const AVFrame *prv_src, const AVFrame *cur_src, const AVFrame *prv_dst, AVFrame *cur_dst, int *xp, int *yp, int *wp, int *hp)
Definition: vf_paletteuse.c:838
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
av_fopen_utf8
FILE * av_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
Definition: file_open.c:158
INDENT
#define INDENT
Definition: vf_paletteuse.c:508
color_rect
Definition: vf_paletteuse.c:605
DEFINE_SET_FRAME_COLOR_SEARCH
#define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro)
Definition: vf_paletteuse.c:1073
PaletteUseContext::bayer_scale
int bayer_scale
Definition: vf_paletteuse.c:95
width
#define width
s
#define s(width, name)
Definition: cbs_vp9.c:257
dithering_mode
dithering_mode
Definition: vf_paletteuse.c:34
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_paletteuse.c:969
g
const char * g
Definition: vf_curves.c:117
ff_formats_ref
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:555
color_node::right_id
int right_id
Definition: vf_paletteuse.c:61
DITHERING_HECKBERT
@ DITHERING_HECKBERT
Definition: vf_paletteuse.c:37
stack_node
Definition: vf_paletteuse.c:253
nearest_color::dist_sqd
int dist_sqd
Definition: vf_paletteuse.c:212
ctx
AVFormatContext * ctx
Definition: movenc.c:48
set_frame_lut
static const set_frame_func set_frame_lut[NB_COLOR_SEARCHES][NB_DITHERING]
Definition: vf_paletteuse.c:1094
f
#define f(width, name)
Definition: cbs_vp9.c:255
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:191
debug_accuracy
static int debug_accuracy(const PaletteUseContext *s)
Definition: vf_paletteuse.c:563
if
if(ret)
Definition: filter_design.txt:179
color_node::palette_id
uint8_t palette_id
Definition: vf_paletteuse.c:59
load_apply_palette
static int load_apply_palette(FFFrameSync *fs)
Definition: vf_paletteuse.c:1040
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
ff_vf_paletteuse
const AVFilter ff_vf_paletteuse
Definition: vf_paletteuse.c:1167
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
PaletteUseContext::dither
int dither
Definition: vf_paletteuse.c:92
fs
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:259
colormap_insert
static int colormap_insert(struct color_node *map, uint8_t *color_used, int *nb_used, const PaletteUseContext *s, const struct color_rect *box)
Definition: vf_paletteuse.c:705
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
DITHERING_ENTRIES
#define DITHERING_ENTRIES(color_search)
Definition: vf_paletteuse.c:1085
PaletteUseContext
Definition: vf_paletteuse.c:82
get_dst_color_err
static av_always_inline int get_dst_color_err(PaletteUseContext *s, uint32_t c, int *ea, int *er, int *eg, int *eb, const enum color_search_method search_method)
Definition: vf_paletteuse.c:375
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
cmp_funcs
static const cmp_func cmp_funcs[]
Definition: vf_paletteuse.c:626
AVPALETTE_COUNT
#define AVPALETTE_COUNT
Definition: pixfmt.h:33
get_next_color
static int get_next_color(const uint8_t *color_used, const PaletteUseContext *s, int *component, const struct color_rect *box)
Definition: vf_paletteuse.c:628
disp_node
static void disp_node(AVBPrint *buf, const struct color_node *map, int parent_id, int node_id, int depth)
Definition: vf_paletteuse.c:509
DITHERING_NONE
@ DITHERING_NONE
Definition: vf_paletteuse.c:35
paletteuse_options
static const AVOption paletteuse_options[]
Definition: vf_paletteuse.c:111
ff_dlog
#define ff_dlog(a,...)
Definition: tableprint_vlc.h:29
PaletteUseContext::trans_thresh
int trans_thresh
Definition: vf_paletteuse.c:89
qsort.h
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
master
const char * master
Definition: vf_curves.c:119
av_frame_ref
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:325
nearest_color
Definition: vf_paletteuse.c:210
DITHERING_BAYER
@ DITHERING_BAYER
Definition: vf_paletteuse.c:36
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
DITHERING_FLOYD_STEINBERG
@ DITHERING_FLOYD_STEINBERG
Definition: vf_paletteuse.c:38
PaletteUseContext::palette
uint32_t palette[AVPALETTE_COUNT]
Definition: vf_paletteuse.c:87
color
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:92
DITHERING_SIERRA2
@ DITHERING_SIERRA2
Definition: vf_paletteuse.c:39
PaletteUseContext::fs
FFFrameSync fs
Definition: vf_paletteuse.c:84
split
static char * split(char *message, char delim)
Definition: af_channelmap.c:81
height
#define height
AV_PIX_FMT_RGB32
#define AV_PIX_FMT_RGB32
Definition: pixfmt.h:377
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
color_get
static av_always_inline int color_get(PaletteUseContext *s, uint32_t color, uint8_t a, uint8_t r, uint8_t g, uint8_t b, const enum color_search_method search_method)
Check if the requested color is in the cache already.
Definition: vf_paletteuse.c:341
DITHERING_SIERRA2_4A
@ DITHERING_SIERRA2_4A
Definition: vf_paletteuse.c:40
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
PaletteUseContext::transparency_index
int transparency_index
Definition: vf_paletteuse.c:88
internal.h
DECLARE_CMP_FUNC
#define DECLARE_CMP_FUNC(name, pos)
Definition: vf_paletteuse.c:612
activate
static int activate(AVFilterContext *ctx)
Definition: vf_paletteuse.c:1130
OFFSET
#define OFFSET(x)
Definition: vf_paletteuse.c:109
bprint.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
cache_node
Definition: vf_paletteuse.c:72
AV_QSORT
#define AV_QSORT(p, num, type, cmp)
Quicksort This sort is fast, and fully inplace but not stable and it is possible to construct input t...
Definition: qsort.h:33
internal.h
src2
const pixel * src2
Definition: h264pred_template.c:422
a2
#define a2
Definition: regdef.h:48
cmp_pal_entry
static int cmp_pal_entry(const void *a, const void *b)
Definition: vf_paletteuse.c:750
delta
float delta
Definition: vorbis_enc_data.h:430
av_always_inline
#define av_always_inline
Definition: attributes.h:49
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
cache_node::entries
struct cached_color * entries
Definition: vf_paletteuse.c:73
av_frame_unref
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:435
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:56
PaletteUseContext::diff_mode
int diff_mode
Definition: vf_paletteuse.c:97
color_node::split
int split
Definition: vf_paletteuse.c:60
cached_color::pal_entry
uint8_t pal_entry
Definition: vf_paletteuse.c:69
load_colormap
static void load_colormap(PaletteUseContext *s)
Definition: vf_paletteuse.c:764
PaletteUseContext::total_mean_err
uint64_t total_mean_err
Definition: vf_paletteuse.c:105
diff_mode
diff_mode
Definition: vf_paletteuse.c:51
FLAGS
#define FLAGS
Definition: vf_paletteuse.c:110
AVFilter
Filter definition.
Definition: avfilter.h:165
cache_node::nb_entries
int nb_entries
Definition: vf_paletteuse.c:74
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
ret
ret
Definition: filter_design.txt:187
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
PaletteUseContext::color_search_method
int color_search_method
Definition: vf_paletteuse.c:103
pos
unsigned int pos
Definition: spdifenc.c:412
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:93
set_frame
static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFrame *in, int x_start, int y_start, int w, int h, enum dithering_mode dither, const enum color_search_method search_method)
Definition: vf_paletteuse.c:399
colormap_nearest_iterative
static av_always_inline uint8_t colormap_nearest_iterative(const PaletteUseContext *s, const struct color_node *root, const uint8_t *target)
Definition: vf_paletteuse.c:258
left
Tag MUST be and< 10hcoeff half pel interpolation filter coefficients, hcoeff[0] are the 2 middle coefficients[1] are the next outer ones and so on, resulting in a filter like:...eff[2], hcoeff[1], hcoeff[0], hcoeff[0], hcoeff[1], hcoeff[2] ... the sign of the coefficients is not explicitly stored but alternates after each coeff and coeff[0] is positive, so ...,+,-,+,-,+,+,-,+,-,+,... hcoeff[0] is not explicitly stored but found by subtracting the sum of all stored coefficients with signs from 32 hcoeff[0]=32 - hcoeff[1] - hcoeff[2] - ... a good choice for hcoeff and htaps is htaps=6 hcoeff={40,-10, 2} an alternative which requires more computations at both encoder and decoder side and may or may not be better is htaps=8 hcoeff={42,-14, 6,-2}ref_frames minimum of the number of available reference frames and max_ref_frames for example the first frame after a key frame always has ref_frames=1spatial_decomposition_type wavelet type 0 is a 9/7 symmetric compact integer wavelet 1 is a 5/3 symmetric compact integer wavelet others are reserved stored as delta from last, last is reset to 0 if always_reset||keyframeqlog quality(logarithmic quantizer scale) stored as delta from last, last is reset to 0 if always_reset||keyframemv_scale stored as delta from last, last is reset to 0 if always_reset||keyframe FIXME check that everything works fine if this changes between framesqbias dequantization bias stored as delta from last, last is reset to 0 if always_reset||keyframeblock_max_depth maximum depth of the block tree stored as delta from last, last is reset to 0 if always_reset||keyframequant_table quantization tableHighlevel bitstream structure:==============================--------------------------------------------|Header|--------------------------------------------|------------------------------------|||Block0||||split?||||yes no||||......... intra?||||:Block01 :yes no||||:Block02 :....... ..........||||:Block03 ::y DC ::ref index:||||:Block04 ::cb DC ::motion x :||||......... :cr DC ::motion y :||||....... ..........|||------------------------------------||------------------------------------|||Block1|||...|--------------------------------------------|------------ ------------ ------------|||Y subbands||Cb subbands||Cr subbands||||--- ---||--- ---||--- ---|||||LL0||HL0||||LL0||HL0||||LL0||HL0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||LH0||HH0||||LH0||HH0||||LH0||HH0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HL1||LH1||||HL1||LH1||||HL1||LH1|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HH1||HL2||||HH1||HL2||||HH1||HL2|||||...||...||...|||------------ ------------ ------------|--------------------------------------------Decoding process:=================------------|||Subbands|------------||||------------|Intra DC||||LL0 subband prediction ------------|\ Dequantization ------------------- \||Reference frames|\ IDWT|------- -------|Motion \|||Frame 0||Frame 1||Compensation . OBMC v -------|------- -------|--------------. \------> Frame n output Frame Frame<----------------------------------/|...|------------------- Range Coder:============Binary Range Coder:------------------- The implemented range coder is an adapted version based upon "Range encoding: an algorithm for removing redundancy from a digitised message." by G. N. N. Martin. The symbols encoded by the Snow range coder are bits(0|1). The associated probabilities are not fix but change depending on the symbol mix seen so far. bit seen|new state ---------+----------------------------------------------- 0|256 - state_transition_table[256 - old_state];1|state_transition_table[old_state];state_transition_table={ 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194, 195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225, 226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0};FIXME Range Coding of integers:------------------------- FIXME Neighboring Blocks:===================left and top are set to the respective blocks unless they are outside of the image in which case they are set to the Null block top-left is set to the top left block unless it is outside of the image in which case it is set to the left block if this block has no larger parent block or it is at the left side of its parent block and the top right block is not outside of the image then the top right block is used for top-right else the top-left block is used Null block y, cb, cr are 128 level, ref, mx and my are 0 Motion Vector Prediction:=========================1. the motion vectors of all the neighboring blocks are scaled to compensate for the difference of reference frames scaled_mv=(mv *(256 *(current_reference+1)/(mv.reference+1))+128)> the median of the scaled left
Definition: snow.txt:386
NBITS
#define NBITS
Definition: vf_paletteuse.c:64
AVFrame::height
int height
Definition: frame.h:389
c2
static const uint64_t c2
Definition: murmur3.c:52
framesync.h
DIFF_MODE_RECTANGLE
@ DIFF_MODE_RECTANGLE
Definition: vf_paletteuse.c:53
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
COLOR_SEARCH_NNS_ITERATIVE
@ COLOR_SEARCH_NNS_ITERATIVE
Definition: vf_paletteuse.c:45
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
avfilter.h
cmp_func
int(* cmp_func)(const void *, const void *)
Definition: vf_paletteuse.c:610
PaletteUseContext::map
struct color_node map[AVPALETTE_COUNT]
Definition: vf_paletteuse.c:86
COLOR_SEARCH_NNS_RECURSIVE
@ COLOR_SEARCH_NNS_RECURSIVE
Definition: vf_paletteuse.c:46
colormap_nearest_node
static void colormap_nearest_node(const PaletteUseContext *s, const struct color_node *map, const int node_pos, const uint8_t *target, struct nearest_color *nearest)
Definition: vf_paletteuse.c:215
PaletteUseContext::debug_accuracy
int debug_accuracy
Definition: vf_paletteuse.c:106
color_rect::min
uint8_t min[4]
Definition: vf_paletteuse.c:606
COLORMAP_NEAREST
#define COLORMAP_NEAREST(s, search, root, target)
Definition: vf_paletteuse.c:330
colormap_nearest_recursive
static av_always_inline uint8_t colormap_nearest_recursive(const PaletteUseContext *s, const struct color_node *node, const uint8_t *rgb)
Definition: vf_paletteuse.c:246
av_clip_uint8
#define av_clip_uint8
Definition: common.h:102
AVFilterContext
An instance of a filter.
Definition: avfilter.h:402
shift
static int shift(int a, int b)
Definition: sonic.c:84
color_node::val
uint8_t val[4]
Definition: vf_paletteuse.c:58
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
CACHE_SIZE
#define CACHE_SIZE
Definition: vf_paletteuse.c:65
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
color::pal_id
uint8_t pal_id
Definition: vf_paletteuse.c:602
NB_COLOR_SEARCHES
@ NB_COLOR_SEARCHES
Definition: vf_paletteuse.c:48
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:241
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:192
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
color::value
uint32_t value
Definition: vf_paletteuse.c:601
d
d
Definition: ffmpeg_filter.c:153
paletteuse_outputs
static const AVFilterPad paletteuse_outputs[]
Definition: vf_paletteuse.c:1159
PaletteUseContext::calc_mean_err
int calc_mean_err
Definition: vf_paletteuse.c:104
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
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:362
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
h
h
Definition: vp9dsp_template.c:2038
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
color_node::left_id
int left_id
Definition: vf_paletteuse.c:61
color_node
Definition: vf_paletteuse.c:57
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(paletteuse)
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:228
ff_framesync_dualinput_get_writable
int ff_framesync_dualinput_get_writable(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Same as ff_framesync_dualinput_get(), but make sure that f0 is writable.
Definition: framesync.c:391
color_rect::max
uint8_t max[4]
Definition: vf_paletteuse.c:607
int
int
Definition: ffmpeg_filter.c:153
PaletteUseContext::last_in
AVFrame * last_in
Definition: vf_paletteuse.c:98
nearest_color::node_pos
int node_pos
Definition: vf_paletteuse.c:211
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:233
paletteuse_inputs
static const AVFilterPad paletteuse_inputs[]
Definition: vf_paletteuse.c:1148
load_palette
static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame)
Definition: vf_paletteuse.c:1006
cached_color
Definition: vf_paletteuse.c:67
color_search_method
color_search_method
Definition: vf_paletteuse.c:44
min
float min
Definition: vorbis_enc_data.h:429
NB_DIFF_MODE
@ NB_DIFF_MODE
Definition: vf_paletteuse.c:54
dither
static const uint8_t dither[8][8]
Definition: vf_fspp.c:58