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 int color = color_get(s, src[x], a8, r, g, b, search_method);
427 
428  if (color < 0)
429  return color;
430  dst[x] = color;
431 
432  } else if (dither == DITHERING_HECKBERT) {
433  const int right = x < w - 1, down = y < h - 1;
434  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
435 
436  if (color < 0)
437  return color;
438  dst[x] = color;
439 
440  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 3, 3);
441  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 3, 3);
442  if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 2, 3);
443 
444  } else if (dither == DITHERING_FLOYD_STEINBERG) {
445  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
446  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
447 
448  if (color < 0)
449  return color;
450  dst[x] = color;
451 
452  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 7, 4);
453  if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 3, 4);
454  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 5, 4);
455  if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 1, 4);
456 
457  } else if (dither == DITHERING_SIERRA2) {
458  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
459  const int right2 = x < w - 2, left2 = x > x_start + 1;
460  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
461 
462  if (color < 0)
463  return color;
464  dst[x] = color;
465 
466  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 4, 4);
467  if (right2) src[ x + 2] = dither_color(src[ x + 2], er, eg, eb, 3, 4);
468 
469  if (down) {
470  if (left2) src[ src_linesize + x - 2] = dither_color(src[ src_linesize + x - 2], er, eg, eb, 1, 4);
471  if (left) src[ src_linesize + x - 1] = dither_color(src[ src_linesize + x - 1], er, eg, eb, 2, 4);
472  if (1) src[ src_linesize + x ] = dither_color(src[ src_linesize + x ], er, eg, eb, 3, 4);
473  if (right) src[ src_linesize + x + 1] = dither_color(src[ src_linesize + x + 1], er, eg, eb, 2, 4);
474  if (right2) src[ src_linesize + x + 2] = dither_color(src[ src_linesize + x + 2], er, eg, eb, 1, 4);
475  }
476 
477  } else if (dither == DITHERING_SIERRA2_4A) {
478  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
479  const int color = get_dst_color_err(s, src[x], &ea, &er, &eg, &eb, search_method);
480 
481  if (color < 0)
482  return color;
483  dst[x] = color;
484 
485  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 2, 2);
486  if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 1, 2);
487  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 1, 2);
488 
489  } else {
490  const uint8_t a = src[x] >> 24 & 0xff;
491  const uint8_t r = src[x] >> 16 & 0xff;
492  const uint8_t g = src[x] >> 8 & 0xff;
493  const uint8_t b = src[x] & 0xff;
494  const int color = color_get(s, src[x], a, r, g, b, search_method);
495 
496  if (color < 0)
497  return color;
498  dst[x] = color;
499  }
500  }
501  src += src_linesize;
502  dst += dst_linesize;
503  }
504  return 0;
505 }
506 
507 #define INDENT 4
508 static void disp_node(AVBPrint *buf,
509  const struct color_node *map,
510  int parent_id, int node_id,
511  int depth)
512 {
513  const struct color_node *node = &map[node_id];
514  const uint32_t fontcolor = node->val[1] > 0x50 &&
515  node->val[2] > 0x50 &&
516  node->val[3] > 0x50 ? 0 : 0xffffff;
517  const int rgb_comp = node->split - 1;
518  av_bprintf(buf, "%*cnode%d ["
519  "label=\"%c%02X%c%02X%c%02X%c\" "
520  "fillcolor=\"#%02x%02x%02x\" "
521  "fontcolor=\"#%06"PRIX32"\"]\n",
522  depth*INDENT, ' ', node->palette_id,
523  "[ "[rgb_comp], node->val[1],
524  "][ "[rgb_comp], node->val[2],
525  " ]["[rgb_comp], node->val[3],
526  " ]"[rgb_comp],
527  node->val[1], node->val[2], node->val[3],
528  fontcolor);
529  if (parent_id != -1)
530  av_bprintf(buf, "%*cnode%d -> node%d\n", depth*INDENT, ' ',
531  map[parent_id].palette_id, node->palette_id);
532  if (node->left_id != -1) disp_node(buf, map, node_id, node->left_id, depth + 1);
533  if (node->right_id != -1) disp_node(buf, map, node_id, node->right_id, depth + 1);
534 }
535 
536 // debug_kdtree=kdtree.dot -> dot -Tpng kdtree.dot > kdtree.png
537 static int disp_tree(const struct color_node *node, const char *fname)
538 {
539  AVBPrint buf;
540  FILE *f = av_fopen_utf8(fname, "w");
541 
542  if (!f) {
543  int ret = AVERROR(errno);
544  av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n",
545  fname, av_err2str(ret));
546  return ret;
547  }
548 
550 
551  av_bprintf(&buf, "digraph {\n");
552  av_bprintf(&buf, " node [style=filled fontsize=10 shape=box]\n");
553  disp_node(&buf, node, -1, 0, 0);
554  av_bprintf(&buf, "}\n");
555 
556  fwrite(buf.str, 1, buf.len, f);
557  fclose(f);
558  av_bprint_finalize(&buf, NULL);
559  return 0;
560 }
561 
563 {
564  int r, g, b, ret = 0;
565 
566  for (r = 0; r < 256; r++) {
567  for (g = 0; g < 256; g++) {
568  for (b = 0; b < 256; b++) {
569  const uint8_t argb[] = {0xff, r, g, b};
570  const int r1 = COLORMAP_NEAREST(s, s->color_search_method, s->map, argb);
571  const int r2 = colormap_nearest_bruteforce(s, argb);
572  if (r1 != r2) {
573  const uint32_t c1 = s->palette[r1];
574  const uint32_t c2 = s->palette[r2];
575  const uint8_t a1 = s->use_alpha ? c1>>24 & 0xff : 0xff;
576  const uint8_t a2 = s->use_alpha ? c2>>24 & 0xff : 0xff;
577  const uint8_t palargb1[] = { a1, c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff };
578  const uint8_t palargb2[] = { a2, c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff };
579  const int d1 = diff(palargb1, argb, s);
580  const int d2 = diff(palargb2, argb, s);
581  if (d1 != d2) {
582  if (s->use_alpha)
584  "/!\\ %02X%02X%02X: %d ! %d (%08"PRIX32" ! %08"PRIX32") / dist: %d ! %d\n",
585  r, g, b, r1, r2, c1, c2, d1, d2);
586  else
588  "/!\\ %02X%02X%02X: %d ! %d (%06"PRIX32" ! %06"PRIX32") / dist: %d ! %d\n",
589  r, g, b, r1, r2, c1 & 0xffffff, c2 & 0xffffff, d1, d2);
590  ret = 1;
591  }
592  }
593  }
594  }
595  }
596  return ret;
597 }
598 
599 struct color {
600  uint32_t value;
601  uint8_t pal_id;
602 };
603 
604 struct color_rect {
605  uint8_t min[4];
606  uint8_t max[4];
607 };
608 
609 typedef int (*cmp_func)(const void *, const void *);
610 
611 #define DECLARE_CMP_FUNC(name, pos) \
612 static int cmp_##name(const void *pa, const void *pb) \
613 { \
614  const struct color *a = pa; \
615  const struct color *b = pb; \
616  return (int)(a->value >> (8 * (3 - (pos))) & 0xff) \
617  - (int)(b->value >> (8 * (3 - (pos))) & 0xff); \
618 }
619 
624 
625 static const cmp_func cmp_funcs[] = {cmp_a, cmp_r, cmp_g, cmp_b};
626 
627 static int get_next_color(const uint8_t *color_used, const PaletteUseContext *s,
628  int *component, const struct color_rect *box)
629 {
630  int wa, wr, wg, wb;
631  int i, longest = 0;
632  unsigned nb_color = 0;
633  struct color_rect ranges;
634  struct color tmp_pal[256];
635  cmp_func cmpf;
636 
637  ranges.min[0] = ranges.min[1] = ranges.min[2] = ranges.min[3]= 0xff;
638  ranges.max[0] = ranges.max[1] = ranges.max[2] = ranges.max[3]= 0x00;
639 
640  for (i = 0; i < AVPALETTE_COUNT; i++) {
641  const uint32_t c = s->palette[i];
642  const uint8_t a = c >> 24 & 0xff;
643  const uint8_t r = c >> 16 & 0xff;
644  const uint8_t g = c >> 8 & 0xff;
645  const uint8_t b = c & 0xff;
646 
647  if (!s->use_alpha && a < s->trans_thresh) {
648  continue;
649  }
650 
651  if (color_used[i] || (a != 0xff && !s->use_alpha) ||
652  r < box->min[1] || g < box->min[2] || b < box->min[3] ||
653  r > box->max[1] || g > box->max[2] || b > box->max[3])
654  continue;
655 
656  if (s->use_alpha && (a < box->min[0] || a > box->max[0]))
657  continue;
658 
659  if (a < ranges.min[0]) ranges.min[0] = a;
660  if (r < ranges.min[1]) ranges.min[1] = r;
661  if (g < ranges.min[2]) ranges.min[2] = g;
662  if (b < ranges.min[3]) ranges.min[3] = b;
663 
664  if (a > ranges.max[0]) ranges.max[0] = a;
665  if (r > ranges.max[1]) ranges.max[1] = r;
666  if (g > ranges.max[2]) ranges.max[2] = g;
667  if (b > ranges.max[3]) ranges.max[3] = b;
668 
669  tmp_pal[nb_color].value = c;
670  tmp_pal[nb_color].pal_id = i;
671 
672  nb_color++;
673  }
674 
675  if (!nb_color)
676  return -1;
677 
678  /* define longest axis that will be the split component */
679  wa = ranges.max[0] - ranges.min[0];
680  wr = ranges.max[1] - ranges.min[1];
681  wg = ranges.max[2] - ranges.min[2];
682  wb = ranges.max[3] - ranges.min[3];
683 
684  if (s->use_alpha) {
685  if (wa >= wr && wa >= wb && wa >= wg) longest = 0;
686  if (wr >= wg && wr >= wb && wr >= wa) longest = 1;
687  if (wg >= wr && wg >= wb && wg >= wa) longest = 2;
688  if (wb >= wr && wb >= wg && wb >= wa) longest = 3;
689  } else {
690  if (wr >= wg && wr >= wb) longest = 1;
691  if (wg >= wr && wg >= wb) longest = 2;
692  if (wb >= wr && wb >= wg) longest = 3;
693  }
694 
695  cmpf = cmp_funcs[longest];
696  *component = longest;
697 
698  /* sort along this axis to get median */
699  AV_QSORT(tmp_pal, nb_color, struct color, cmpf);
700 
701  return tmp_pal[nb_color >> 1].pal_id;
702 }
703 
704 static int colormap_insert(struct color_node *map,
705  uint8_t *color_used,
706  int *nb_used,
707  const PaletteUseContext *s,
708  const struct color_rect *box)
709 {
710  uint32_t c;
711  int component, cur_id;
712  int node_left_id = -1, node_right_id = -1;
713  struct color_node *node;
714  struct color_rect box1, box2;
715  const int pal_id = get_next_color(color_used, s, &component, box);
716 
717  if (pal_id < 0)
718  return -1;
719 
720  /* create new node with that color */
721  cur_id = (*nb_used)++;
722  c = s->palette[pal_id];
723  node = &map[cur_id];
724  node->split = component;
725  node->palette_id = pal_id;
726  node->val[0] = c>>24 & 0xff;
727  node->val[1] = c>>16 & 0xff;
728  node->val[2] = c>> 8 & 0xff;
729  node->val[3] = c & 0xff;
730 
731  color_used[pal_id] = 1;
732 
733  /* get the two boxes this node creates */
734  box1 = box2 = *box;
735  box1.max[component] = node->val[component];
736  box2.min[component] = FFMIN(node->val[component] + 1, 255);
737 
738  node_left_id = colormap_insert(map, color_used, nb_used, s, &box1);
739 
740  if (box2.min[component] <= box2.max[component])
741  node_right_id = colormap_insert(map, color_used, nb_used, s, &box2);
742 
743  node->left_id = node_left_id;
744  node->right_id = node_right_id;
745 
746  return cur_id;
747 }
748 
749 static int cmp_pal_entry(const void *a, const void *b)
750 {
751  const int c1 = *(const uint32_t *)a & 0xffffff;
752  const int c2 = *(const uint32_t *)b & 0xffffff;
753  return c1 - c2;
754 }
755 
756 static int cmp_pal_entry_alpha(const void *a, const void *b)
757 {
758  const int c1 = *(const uint32_t *)a;
759  const int c2 = *(const uint32_t *)b;
760  return c1 - c2;
761 }
762 
764 {
765  int i, nb_used = 0;
766  uint8_t color_used[AVPALETTE_COUNT] = {0};
767  uint32_t last_color = 0;
768  struct color_rect box;
769 
770  if (!s->use_alpha && s->transparency_index >= 0) {
771  FFSWAP(uint32_t, s->palette[s->transparency_index], s->palette[255]);
772  }
773 
774  /* disable transparent colors and dups */
775  qsort(s->palette, AVPALETTE_COUNT-(s->transparency_index >= 0), sizeof(*s->palette),
776  s->use_alpha ? cmp_pal_entry_alpha : cmp_pal_entry);
777 
778  for (i = 0; i < AVPALETTE_COUNT; i++) {
779  const uint32_t c = s->palette[i];
780  if (i != 0 && c == last_color) {
781  color_used[i] = 1;
782  continue;
783  }
784  last_color = c;
785  if (!s->use_alpha && c >> 24 < s->trans_thresh) {
786  color_used[i] = 1; // ignore transparent color(s)
787  continue;
788  }
789  }
790 
791  box.min[0] = box.min[1] = box.min[2] = box.min[3] = 0x00;
792  box.max[0] = box.max[1] = box.max[2] = box.max[3] = 0xff;
793 
794  colormap_insert(s->map, color_used, &nb_used, s, &box);
795 
796  if (s->dot_filename)
797  disp_tree(s->map, s->dot_filename);
798 
799  if (s->debug_accuracy) {
800  if (!debug_accuracy(s))
801  av_log(NULL, AV_LOG_INFO, "Accuracy check passed\n");
802  }
803 }
804 
805 static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1,
806  const AVFrame *in2, int frame_count)
807 {
808  int x, y;
809  const uint32_t *palette = s->palette;
810  uint32_t *src1 = (uint32_t *)in1->data[0];
811  uint8_t *src2 = in2->data[0];
812  const int src1_linesize = in1->linesize[0] >> 2;
813  const int src2_linesize = in2->linesize[0];
814  const float div = in1->width * in1->height * (s->use_alpha ? 4 : 3);
815  unsigned mean_err = 0;
816 
817  for (y = 0; y < in1->height; y++) {
818  for (x = 0; x < in1->width; x++) {
819  const uint32_t c1 = src1[x];
820  const uint32_t c2 = palette[src2[x]];
821  const uint8_t a1 = s->use_alpha ? c1>>24 & 0xff : 0xff;
822  const uint8_t a2 = s->use_alpha ? c2>>24 & 0xff : 0xff;
823  const uint8_t argb1[] = {a1, c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff};
824  const uint8_t argb2[] = {a2, c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff};
825  mean_err += diff(argb1, argb2, s);
826  }
827  src1 += src1_linesize;
828  src2 += src2_linesize;
829  }
830 
831  s->total_mean_err += mean_err;
832 
833  av_log(NULL, AV_LOG_INFO, "MEP:%.3f TotalMEP:%.3f\n",
834  mean_err / div, s->total_mean_err / (div * frame_count));
835 }
836 
838  const AVFrame *prv_src, const AVFrame *cur_src,
839  const AVFrame *prv_dst, AVFrame *cur_dst,
840  int *xp, int *yp, int *wp, int *hp)
841 {
842  int x_start = 0, y_start = 0;
843  int width = cur_src->width;
844  int height = cur_src->height;
845 
846  if (prv_src->data[0] && diff_mode == DIFF_MODE_RECTANGLE) {
847  int y;
848  int x_end = cur_src->width - 1,
849  y_end = cur_src->height - 1;
850  const uint32_t *prv_srcp = (const uint32_t *)prv_src->data[0];
851  const uint32_t *cur_srcp = (const uint32_t *)cur_src->data[0];
852  const uint8_t *prv_dstp = prv_dst->data[0];
853  uint8_t *cur_dstp = cur_dst->data[0];
854 
855  const int prv_src_linesize = prv_src->linesize[0] >> 2;
856  const int cur_src_linesize = cur_src->linesize[0] >> 2;
857  const int prv_dst_linesize = prv_dst->linesize[0];
858  const int cur_dst_linesize = cur_dst->linesize[0];
859 
860  /* skip common lines */
861  while (y_start < y_end && !memcmp(prv_srcp + y_start*prv_src_linesize,
862  cur_srcp + y_start*cur_src_linesize,
863  cur_src->width * 4)) {
864  memcpy(cur_dstp + y_start*cur_dst_linesize,
865  prv_dstp + y_start*prv_dst_linesize,
866  cur_dst->width);
867  y_start++;
868  }
869  while (y_end > y_start && !memcmp(prv_srcp + y_end*prv_src_linesize,
870  cur_srcp + y_end*cur_src_linesize,
871  cur_src->width * 4)) {
872  memcpy(cur_dstp + y_end*cur_dst_linesize,
873  prv_dstp + y_end*prv_dst_linesize,
874  cur_dst->width);
875  y_end--;
876  }
877 
878  height = y_end + 1 - y_start;
879 
880  /* skip common columns */
881  while (x_start < x_end) {
882  int same_column = 1;
883  for (y = y_start; y <= y_end; y++) {
884  if (prv_srcp[y*prv_src_linesize + x_start] != cur_srcp[y*cur_src_linesize + x_start]) {
885  same_column = 0;
886  break;
887  }
888  }
889  if (!same_column)
890  break;
891  x_start++;
892  }
893  while (x_end > x_start) {
894  int same_column = 1;
895  for (y = y_start; y <= y_end; y++) {
896  if (prv_srcp[y*prv_src_linesize + x_end] != cur_srcp[y*cur_src_linesize + x_end]) {
897  same_column = 0;
898  break;
899  }
900  }
901  if (!same_column)
902  break;
903  x_end--;
904  }
905  width = x_end + 1 - x_start;
906 
907  if (x_start) {
908  for (y = y_start; y <= y_end; y++)
909  memcpy(cur_dstp + y*cur_dst_linesize,
910  prv_dstp + y*prv_dst_linesize, x_start);
911  }
912  if (x_end != cur_src->width - 1) {
913  const int copy_len = cur_src->width - 1 - x_end;
914  for (y = y_start; y <= y_end; y++)
915  memcpy(cur_dstp + y*cur_dst_linesize + x_end + 1,
916  prv_dstp + y*prv_dst_linesize + x_end + 1,
917  copy_len);
918  }
919  }
920  *xp = x_start;
921  *yp = y_start;
922  *wp = width;
923  *hp = height;
924 }
925 
927 {
928  int x, y, w, h, ret;
929  AVFilterContext *ctx = inlink->dst;
930  PaletteUseContext *s = ctx->priv;
931  AVFilterLink *outlink = inlink->dst->outputs[0];
932 
933  AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
934  if (!out) {
935  *outf = NULL;
936  return AVERROR(ENOMEM);
937  }
939 
940  set_processing_window(s->diff_mode, s->last_in, in,
941  s->last_out, out, &x, &y, &w, &h);
942  av_frame_unref(s->last_in);
943  av_frame_unref(s->last_out);
944  if ((ret = av_frame_ref(s->last_in, in)) < 0 ||
945  (ret = av_frame_ref(s->last_out, out)) < 0 ||
946  (ret = av_frame_make_writable(s->last_in)) < 0) {
947  av_frame_free(&out);
948  *outf = NULL;
949  return ret;
950  }
951 
952  ff_dlog(ctx, "%dx%d rect: (%d;%d) -> (%d,%d) [area:%dx%d]\n",
953  w, h, x, y, x+w, y+h, in->width, in->height);
954 
955  ret = s->set_frame(s, out, in, x, y, w, h);
956  if (ret < 0) {
957  av_frame_free(&out);
958  *outf = NULL;
959  return ret;
960  }
961  memcpy(out->data[1], s->palette, AVPALETTE_SIZE);
962  if (s->calc_mean_err)
963  debug_mean_error(s, in, out, inlink->frame_count_out);
964  *outf = out;
965  return 0;
966 }
967 
968 static int config_output(AVFilterLink *outlink)
969 {
970  int ret;
971  AVFilterContext *ctx = outlink->src;
972  PaletteUseContext *s = ctx->priv;
973 
975  if (ret < 0)
976  return ret;
977  s->fs.opt_repeatlast = 1; // only 1 frame in the palette
978  s->fs.in[1].before = s->fs.in[1].after = EXT_INFINITY;
979  s->fs.on_event = load_apply_palette;
980 
981  outlink->w = ctx->inputs[0]->w;
982  outlink->h = ctx->inputs[0]->h;
983 
984  outlink->time_base = ctx->inputs[0]->time_base;
985  if ((ret = ff_framesync_configure(&s->fs)) < 0)
986  return ret;
987  return 0;
988 }
989 
991 {
992  AVFilterContext *ctx = inlink->dst;
993 
994  if (inlink->w * inlink->h != AVPALETTE_COUNT) {
996  "Palette input must contain exactly %d pixels. "
997  "Specified input has %dx%d=%d pixels\n",
998  AVPALETTE_COUNT, inlink->w, inlink->h,
999  inlink->w * inlink->h);
1000  return AVERROR(EINVAL);
1001  }
1002  return 0;
1003 }
1004 
1005 static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame)
1006 {
1007  int i, x, y;
1008  const uint32_t *p = (const uint32_t *)palette_frame->data[0];
1009  const int p_linesize = palette_frame->linesize[0] >> 2;
1010 
1011  s->transparency_index = -1;
1012 
1013  if (s->new) {
1014  memset(s->palette, 0, sizeof(s->palette));
1015  memset(s->map, 0, sizeof(s->map));
1016  for (i = 0; i < CACHE_SIZE; i++)
1017  av_freep(&s->cache[i].entries);
1018  memset(s->cache, 0, sizeof(s->cache));
1019  }
1020 
1021  i = 0;
1022  for (y = 0; y < palette_frame->height; y++) {
1023  for (x = 0; x < palette_frame->width; x++) {
1024  s->palette[i] = p[x];
1025  if (!s->use_alpha && p[x]>>24 < s->trans_thresh) {
1026  s->transparency_index = i; // we are assuming at most one transparent color in palette
1027  }
1028  i++;
1029  }
1030  p += p_linesize;
1031  }
1032 
1033  load_colormap(s);
1034 
1035  if (!s->new)
1036  s->palette_loaded = 1;
1037 }
1038 
1040 {
1041  AVFilterContext *ctx = fs->parent;
1042  AVFilterLink *inlink = ctx->inputs[0];
1043  PaletteUseContext *s = ctx->priv;
1044  AVFrame *master, *second, *out = NULL;
1045  int ret;
1046 
1047  // writable for error diffusal dithering
1049  if (ret < 0)
1050  return ret;
1051  if (!master || !second) {
1053  return AVERROR_BUG;
1054  }
1055  if (!s->palette_loaded) {
1056  load_palette(s, second);
1057  }
1060  if (ret < 0)
1061  return ret;
1062  return ff_filter_frame(ctx->outputs[0], out);
1063 }
1064 
1065 #define DEFINE_SET_FRAME(color_search, name, value) \
1066 static int set_frame_##name(PaletteUseContext *s, AVFrame *out, AVFrame *in, \
1067  int x_start, int y_start, int w, int h) \
1068 { \
1069  return set_frame(s, out, in, x_start, y_start, w, h, value, color_search); \
1070 }
1071 
1072 #define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro) \
1073  DEFINE_SET_FRAME(color_search_macro, color_search##_##none, DITHERING_NONE) \
1074  DEFINE_SET_FRAME(color_search_macro, color_search##_##bayer, DITHERING_BAYER) \
1075  DEFINE_SET_FRAME(color_search_macro, color_search##_##heckbert, DITHERING_HECKBERT) \
1076  DEFINE_SET_FRAME(color_search_macro, color_search##_##floyd_steinberg, DITHERING_FLOYD_STEINBERG) \
1077  DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2, DITHERING_SIERRA2) \
1078  DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2_4a, DITHERING_SIERRA2_4A) \
1079 
1083 
1084 #define DITHERING_ENTRIES(color_search) { \
1085  set_frame_##color_search##_none, \
1086  set_frame_##color_search##_bayer, \
1087  set_frame_##color_search##_heckbert, \
1088  set_frame_##color_search##_floyd_steinberg, \
1089  set_frame_##color_search##_sierra2, \
1090  set_frame_##color_search##_sierra2_4a, \
1091 }
1092 
1094  DITHERING_ENTRIES(nns_iterative),
1095  DITHERING_ENTRIES(nns_recursive),
1096  DITHERING_ENTRIES(bruteforce),
1097 };
1098 
1099 static int dither_value(int p)
1100 {
1101  const int q = p ^ (p >> 3);
1102  return (p & 4) >> 2 | (q & 4) >> 1 \
1103  | (p & 2) << 1 | (q & 2) << 2 \
1104  | (p & 1) << 4 | (q & 1) << 5;
1105 }
1106 
1108 {
1109  PaletteUseContext *s = ctx->priv;
1110 
1111  s->last_in = av_frame_alloc();
1112  s->last_out = av_frame_alloc();
1113  if (!s->last_in || !s->last_out)
1114  return AVERROR(ENOMEM);
1115 
1116  s->set_frame = set_frame_lut[s->color_search_method][s->dither];
1117 
1118  if (s->dither == DITHERING_BAYER) {
1119  int i;
1120  const int delta = 1 << (5 - s->bayer_scale); // to avoid too much luma
1121 
1122  for (i = 0; i < FF_ARRAY_ELEMS(s->ordered_dither); i++)
1123  s->ordered_dither[i] = (dither_value(i) >> s->bayer_scale) - delta;
1124  }
1125 
1126  return 0;
1127 }
1128 
1130 {
1131  PaletteUseContext *s = ctx->priv;
1132  return ff_framesync_activate(&s->fs);
1133 }
1134 
1136 {
1137  int i;
1138  PaletteUseContext *s = ctx->priv;
1139 
1140  ff_framesync_uninit(&s->fs);
1141  for (i = 0; i < CACHE_SIZE; i++)
1142  av_freep(&s->cache[i].entries);
1143  av_frame_free(&s->last_in);
1144  av_frame_free(&s->last_out);
1145 }
1146 
1147 static const AVFilterPad paletteuse_inputs[] = {
1148  {
1149  .name = "default",
1150  .type = AVMEDIA_TYPE_VIDEO,
1151  },{
1152  .name = "palette",
1153  .type = AVMEDIA_TYPE_VIDEO,
1154  .config_props = config_input_palette,
1155  },
1156 };
1157 
1159  {
1160  .name = "default",
1161  .type = AVMEDIA_TYPE_VIDEO,
1162  .config_props = config_output,
1163  },
1164 };
1165 
1167  .name = "paletteuse",
1168  .description = NULL_IF_CONFIG_SMALL("Use a palette to downsample an input video stream."),
1169  .priv_size = sizeof(PaletteUseContext),
1170  .init = init,
1171  .uninit = uninit,
1172  .activate = activate,
1176  .priv_class = &paletteuse_class,
1177 };
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:990
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:756
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:805
out
FILE * out
Definition: movenc.c:54
color
Definition: vf_paletteuse.c:599
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
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:1107
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:1135
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:537
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:1099
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:926
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:837
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:507
color_rect
Definition: vf_paletteuse.c:604
DEFINE_SET_FRAME_COLOR_SEARCH
#define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro)
Definition: vf_paletteuse.c:1072
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:968
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:1093
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:562
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:1039
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:1166
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:704
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
src
#define src
Definition: vp8dsp.c:255
DITHERING_ENTRIES
#define DITHERING_ENTRIES(color_search)
Definition: vf_paletteuse.c:1084
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:625
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:627
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:508
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:611
activate
static int activate(AVFilterContext *ctx)
Definition: vf_paletteuse.c:1129
src1
#define src1
Definition: h264pred.c:140
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
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:749
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:763
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:609
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:605
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:83
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:601
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
color::value
uint32_t value
Definition: vf_paletteuse.c:600
d
d
Definition: ffmpeg_filter.c:153
paletteuse_outputs
static const AVFilterPad paletteuse_outputs[]
Definition: vf_paletteuse.c:1158
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:606
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:1147
load_palette
static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame)
Definition: vf_paletteuse.c:1005
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