FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 "filters.h"
32 #include "framesync.h"
33 #include "internal.h"
34 
43 };
44 
50 };
51 
52 enum diff_mode {
56 };
57 
58 struct color_node {
61  int split;
63 };
64 
65 #define NBITS 5
66 #define CACHE_SIZE (1<<(3*NBITS))
67 
68 struct cached_color {
69  uint32_t color;
71 };
72 
73 struct cache_node {
76 };
77 
78 struct PaletteUseContext;
79 
81  int x_start, int y_start, int width, int height);
82 
83 typedef struct PaletteUseContext {
84  const AVClass *class;
86  struct cache_node cache[CACHE_SIZE]; /* lookup cache */
87  struct color_node map[AVPALETTE_COUNT]; /* 3D-Tree (KD-Tree with K=3) for reverse colormap */
90  int dither;
91  int new;
94  int ordered_dither[8*8];
95  int diff_mode;
98 
99  /* debug options */
103  uint64_t total_mean_err;
106 
107 #define OFFSET(x) offsetof(PaletteUseContext, x)
108 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
109 static const AVOption paletteuse_options[] = {
110  { "dither", "select dithering mode", OFFSET(dither), AV_OPT_TYPE_INT, {.i64=DITHERING_SIERRA2_4A}, 0, NB_DITHERING-1, FLAGS, "dithering_mode" },
111  { "bayer", "ordered 8x8 bayer dithering (deterministic)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_BAYER}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
112  { "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" },
113  { "floyd_steinberg", "Floyd and Steingberg dithering (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_FLOYD_STEINBERG}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
114  { "sierra2", "Frankie Sierra dithering v2 (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_SIERRA2}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
115  { "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" },
116  { "bayer_scale", "set scale for bayer dithering", OFFSET(bayer_scale), AV_OPT_TYPE_INT, {.i64=2}, 0, 5, FLAGS },
117  { "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" },
118  { "rectangle", "process smallest different rectangle", 0, AV_OPT_TYPE_CONST, {.i64=DIFF_MODE_RECTANGLE}, INT_MIN, INT_MAX, FLAGS, "diff_mode" },
119 
120  /* following are the debug options, not part of the official API */
121  { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
122  { "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" },
123  { "nns_iterative", "iterative search", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_ITERATIVE}, INT_MIN, INT_MAX, FLAGS, "search" },
124  { "nns_recursive", "recursive search", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_RECURSIVE}, INT_MIN, INT_MAX, FLAGS, "search" },
125  { "bruteforce", "brute-force into the palette", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_BRUTEFORCE}, INT_MIN, INT_MAX, FLAGS, "search" },
126  { "mean_err", "compute and print mean error", OFFSET(calc_mean_err), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
127  { "debug_accuracy", "test color search accuracy", OFFSET(debug_accuracy), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
128  { "new", "take new palette for each output frame", OFFSET(new), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
129  { NULL }
130 };
131 
132 AVFILTER_DEFINE_CLASS(paletteuse);
133 
134 static int load_apply_palette(FFFrameSync *fs);
135 
137 {
138  static const enum AVPixelFormat in_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
139  static const enum AVPixelFormat inpal_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
140  static const enum AVPixelFormat out_fmts[] = {AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE};
141  int ret;
143  AVFilterFormats *inpal = ff_make_format_list(inpal_fmts);
145  if (!in || !inpal || !out) {
146  av_freep(&in);
147  av_freep(&inpal);
148  av_freep(&out);
149  return AVERROR(ENOMEM);
150  }
151  if ((ret = ff_formats_ref(in , &ctx->inputs[0]->out_formats)) < 0 ||
152  (ret = ff_formats_ref(inpal, &ctx->inputs[1]->out_formats)) < 0 ||
153  (ret = ff_formats_ref(out , &ctx->outputs[0]->in_formats)) < 0)
154  return ret;
155  return 0;
156 }
157 
158 static av_always_inline int dither_color(uint32_t px, int er, int eg, int eb, int scale, int shift)
159 {
160  return 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)
166 {
167  // XXX: try L*a*b with CIE76 (dL*dL + da*da + db*db)
168  const int dr = c1[0] - c2[0];
169  const int dg = c1[1] - c2[1];
170  const int db = c1[2] - c2[2];
171  return dr*dr + dg*dg + db*db;
172 }
173 
174 static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *rgb)
175 {
176  int i, pal_id = -1, min_dist = INT_MAX;
177 
178  for (i = 0; i < AVPALETTE_COUNT; i++) {
179  const uint32_t c = palette[i];
180 
181  if ((c & 0xff000000) == 0xff000000) { // ignore transparent entry
182  const uint8_t palrgb[] = {
183  palette[i]>>16 & 0xff,
184  palette[i]>> 8 & 0xff,
185  palette[i] & 0xff,
186  };
187  const int d = diff(palrgb, rgb);
188  if (d < min_dist) {
189  pal_id = i;
190  min_dist = d;
191  }
192  }
193  }
194  return pal_id;
195 }
196 
197 /* Recursive form, simpler but a bit slower. Kept for reference. */
199  int node_pos;
200  int dist_sqd;
201 };
202 
203 static void colormap_nearest_node(const struct color_node *map,
204  const int node_pos,
205  const uint8_t *target,
206  struct nearest_color *nearest)
207 {
208  const struct color_node *kd = map + node_pos;
209  const int s = kd->split;
210  int dx, nearer_kd_id, further_kd_id;
211  const uint8_t *current = kd->val;
212  const int current_to_target = diff(target, current);
213 
214  if (current_to_target < nearest->dist_sqd) {
215  nearest->node_pos = node_pos;
216  nearest->dist_sqd = current_to_target;
217  }
218 
219  if (kd->left_id != -1 || kd->right_id != -1) {
220  dx = target[s] - current[s];
221 
222  if (dx <= 0) nearer_kd_id = kd->left_id, further_kd_id = kd->right_id;
223  else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
224 
225  if (nearer_kd_id != -1)
226  colormap_nearest_node(map, nearer_kd_id, target, nearest);
227 
228  if (further_kd_id != -1 && dx*dx < nearest->dist_sqd)
229  colormap_nearest_node(map, further_kd_id, target, nearest);
230  }
231 }
232 
234 {
235  struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1};
236  colormap_nearest_node(node, 0, rgb, &res);
237  return node[res.node_pos].palette_id;
238 }
239 
240 struct stack_node {
241  int color_id;
242  int dx2;
243 };
244 
245 static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target)
246 {
247  int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0;
248  struct stack_node nodes[16];
249  struct stack_node *node = &nodes[0];
250 
251  for (;;) {
252 
253  const struct color_node *kd = &root[cur_color_id];
254  const uint8_t *current = kd->val;
255  const int current_to_target = diff(target, current);
256 
257  /* Compare current color node to the target and update our best node if
258  * it's actually better. */
259  if (current_to_target < best_dist) {
260  best_node_id = cur_color_id;
261  if (!current_to_target)
262  goto end; // exact match, we can return immediately
263  best_dist = current_to_target;
264  }
265 
266  /* Check if it's not a leaf */
267  if (kd->left_id != -1 || kd->right_id != -1) {
268  const int split = kd->split;
269  const int dx = target[split] - current[split];
270  int nearer_kd_id, further_kd_id;
271 
272  /* Define which side is the most interesting. */
273  if (dx <= 0) nearer_kd_id = kd->left_id, further_kd_id = kd->right_id;
274  else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
275 
276  if (nearer_kd_id != -1) {
277  if (further_kd_id != -1) {
278  /* Here, both paths are defined, so we push a state for
279  * when we are going back. */
280  node->color_id = further_kd_id;
281  node->dx2 = dx*dx;
282  pos++;
283  node++;
284  }
285  /* We can now update current color with the most probable path
286  * (no need to create a state since there is nothing to save
287  * anymore). */
288  cur_color_id = nearer_kd_id;
289  continue;
290  } else if (dx*dx < best_dist) {
291  /* The nearest path isn't available, so there is only one path
292  * possible and it's the least probable. We enter it only if the
293  * distance from the current point to the hyper rectangle is
294  * less than our best distance. */
295  cur_color_id = further_kd_id;
296  continue;
297  }
298  }
299 
300  /* Unstack as much as we can, typically as long as the least probable
301  * branch aren't actually probable. */
302  do {
303  if (--pos < 0)
304  goto end;
305  node--;
306  } while (node->dx2 >= best_dist);
307 
308  /* We got a node where the least probable branch might actually contain
309  * a relevant color. */
310  cur_color_id = node->color_id;
311  }
312 
313 end:
314  return root[best_node_id].palette_id;
315 }
316 
317 #define COLORMAP_NEAREST(search, palette, root, target) \
318  search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(root, target) : \
319  search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(root, target) : \
320  colormap_nearest_bruteforce(palette, target)
321 
322 /**
323  * Check if the requested color is in the cache already. If not, find it in the
324  * color tree and cache it.
325  * Note: r, g, and b are the component of c but are passed as well to avoid
326  * recomputing them (they are generally computed by the caller for other uses).
327  */
328 static av_always_inline int color_get(struct cache_node *cache, uint32_t color,
330  const struct color_node *map,
331  const uint32_t *palette,
332  const enum color_search_method search_method)
333 {
334  int i;
335  const uint8_t rgb[] = {r, g, b};
336  const uint8_t rhash = r & ((1<<NBITS)-1);
337  const uint8_t ghash = g & ((1<<NBITS)-1);
338  const uint8_t bhash = b & ((1<<NBITS)-1);
339  const unsigned hash = rhash<<(NBITS*2) | ghash<<NBITS | bhash;
340  struct cache_node *node = &cache[hash];
341  struct cached_color *e;
342 
343  for (i = 0; i < node->nb_entries; i++) {
344  e = &node->entries[i];
345  if (e->color == color)
346  return e->pal_entry;
347  }
348 
349  e = av_dynarray2_add((void**)&node->entries, &node->nb_entries,
350  sizeof(*node->entries), NULL);
351  if (!e)
352  return AVERROR(ENOMEM);
353  e->color = color;
354  e->pal_entry = COLORMAP_NEAREST(search_method, palette, map, rgb);
355  return e->pal_entry;
356 }
357 
359  uint32_t c, const struct color_node *map,
360  const uint32_t *palette,
361  int *er, int *eg, int *eb,
362  const enum color_search_method search_method)
363 {
364  const uint8_t r = c >> 16 & 0xff;
365  const uint8_t g = c >> 8 & 0xff;
366  const uint8_t b = c & 0xff;
367  const int dstx = color_get(cache, c, r, g, b, map, palette, search_method);
368  const uint32_t dstc = palette[dstx];
369  *er = r - (dstc >> 16 & 0xff);
370  *eg = g - (dstc >> 8 & 0xff);
371  *eb = b - (dstc & 0xff);
372  return dstx;
373 }
374 
376  int x_start, int y_start, int w, int h,
377  enum dithering_mode dither,
378  const enum color_search_method search_method)
379 {
380  int x, y;
381  const struct color_node *map = s->map;
382  struct cache_node *cache = s->cache;
383  const uint32_t *palette = s->palette;
384  const int src_linesize = in ->linesize[0] >> 2;
385  const int dst_linesize = out->linesize[0];
386  uint32_t *src = ((uint32_t *)in ->data[0]) + y_start*src_linesize;
387  uint8_t *dst = out->data[0] + y_start*dst_linesize;
388 
389  w += x_start;
390  h += y_start;
391 
392  for (y = y_start; y < h; y++) {
393  for (x = x_start; x < w; x++) {
394  int er, eg, eb;
395 
396  if (dither == DITHERING_BAYER) {
397  const int d = s->ordered_dither[(y & 7)<<3 | (x & 7)];
398  const uint8_t r8 = src[x] >> 16 & 0xff;
399  const uint8_t g8 = src[x] >> 8 & 0xff;
400  const uint8_t b8 = src[x] & 0xff;
401  const uint8_t r = av_clip_uint8(r8 + d);
402  const uint8_t g = av_clip_uint8(g8 + d);
403  const uint8_t b = av_clip_uint8(b8 + d);
404  const uint32_t c = r<<16 | g<<8 | b;
405  const int color = color_get(cache, c, r, g, b, map, palette, search_method);
406 
407  if (color < 0)
408  return color;
409  dst[x] = color;
410 
411  } else if (dither == DITHERING_HECKBERT) {
412  const int right = x < w - 1, down = y < h - 1;
413  const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
414 
415  if (color < 0)
416  return color;
417  dst[x] = color;
418 
419  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 3, 3);
420  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 3, 3);
421  if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 2, 3);
422 
423  } else if (dither == DITHERING_FLOYD_STEINBERG) {
424  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
425  const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
426 
427  if (color < 0)
428  return color;
429  dst[x] = color;
430 
431  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 7, 4);
432  if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 3, 4);
433  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 5, 4);
434  if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 1, 4);
435 
436  } else if (dither == DITHERING_SIERRA2) {
437  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
438  const int right2 = x < w - 2, left2 = x > x_start + 1;
439  const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
440 
441  if (color < 0)
442  return color;
443  dst[x] = color;
444 
445  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 4, 4);
446  if (right2) src[ x + 2] = dither_color(src[ x + 2], er, eg, eb, 3, 4);
447 
448  if (down) {
449  if (left2) src[ src_linesize + x - 2] = dither_color(src[ src_linesize + x - 2], er, eg, eb, 1, 4);
450  if (left) src[ src_linesize + x - 1] = dither_color(src[ src_linesize + x - 1], er, eg, eb, 2, 4);
451  if (1) src[ src_linesize + x ] = dither_color(src[ src_linesize + x ], er, eg, eb, 3, 4);
452  if (right) src[ src_linesize + x + 1] = dither_color(src[ src_linesize + x + 1], er, eg, eb, 2, 4);
453  if (right2) src[ src_linesize + x + 2] = dither_color(src[ src_linesize + x + 2], er, eg, eb, 1, 4);
454  }
455 
456  } else if (dither == DITHERING_SIERRA2_4A) {
457  const int right = x < w - 1, down = y < h - 1, left = x > x_start;
458  const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
459 
460  if (color < 0)
461  return color;
462  dst[x] = color;
463 
464  if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 2, 2);
465  if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 1, 2);
466  if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 1, 2);
467 
468  } else {
469  const uint8_t r = src[x] >> 16 & 0xff;
470  const uint8_t g = src[x] >> 8 & 0xff;
471  const uint8_t b = src[x] & 0xff;
472  const int color = color_get(cache, src[x] & 0xffffff, r, g, b, map, palette, search_method);
473 
474  if (color < 0)
475  return color;
476  dst[x] = color;
477  }
478  }
479  src += src_linesize;
480  dst += dst_linesize;
481  }
482  return 0;
483 }
484 
485 #define INDENT 4
486 static void disp_node(AVBPrint *buf,
487  const struct color_node *map,
488  int parent_id, int node_id,
489  int depth)
490 {
491  const struct color_node *node = &map[node_id];
492  const uint32_t fontcolor = node->val[0] > 0x50 &&
493  node->val[1] > 0x50 &&
494  node->val[2] > 0x50 ? 0 : 0xffffff;
495  av_bprintf(buf, "%*cnode%d ["
496  "label=\"%c%02X%c%02X%c%02X%c\" "
497  "fillcolor=\"#%02x%02x%02x\" "
498  "fontcolor=\"#%06"PRIX32"\"]\n",
499  depth*INDENT, ' ', node->palette_id,
500  "[ "[node->split], node->val[0],
501  "][ "[node->split], node->val[1],
502  " ]["[node->split], node->val[2],
503  " ]"[node->split],
504  node->val[0], node->val[1], node->val[2],
505  fontcolor);
506  if (parent_id != -1)
507  av_bprintf(buf, "%*cnode%d -> node%d\n", depth*INDENT, ' ',
508  map[parent_id].palette_id, node->palette_id);
509  if (node->left_id != -1) disp_node(buf, map, node_id, node->left_id, depth + 1);
510  if (node->right_id != -1) disp_node(buf, map, node_id, node->right_id, depth + 1);
511 }
512 
513 // debug_kdtree=kdtree.dot -> dot -Tpng kdtree.dot > kdtree.png
514 static int disp_tree(const struct color_node *node, const char *fname)
515 {
516  AVBPrint buf;
517  FILE *f = av_fopen_utf8(fname, "w");
518 
519  if (!f) {
520  int ret = AVERROR(errno);
521  av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n",
522  fname, av_err2str(ret));
523  return ret;
524  }
525 
527 
528  av_bprintf(&buf, "digraph {\n");
529  av_bprintf(&buf, " node [style=filled fontsize=10 shape=box]\n");
530  disp_node(&buf, node, -1, 0, 0);
531  av_bprintf(&buf, "}\n");
532 
533  fwrite(buf.str, 1, buf.len, f);
534  fclose(f);
535  av_bprint_finalize(&buf, NULL);
536  return 0;
537 }
538 
539 static int debug_accuracy(const struct color_node *node, const uint32_t *palette,
540  const enum color_search_method search_method)
541 {
542  int r, g, b, ret = 0;
543 
544  for (r = 0; r < 256; r++) {
545  for (g = 0; g < 256; g++) {
546  for (b = 0; b < 256; b++) {
547  const uint8_t rgb[] = {r, g, b};
548  const int r1 = COLORMAP_NEAREST(search_method, palette, node, rgb);
549  const int r2 = colormap_nearest_bruteforce(palette, rgb);
550  if (r1 != r2) {
551  const uint32_t c1 = palette[r1];
552  const uint32_t c2 = palette[r2];
553  const uint8_t palrgb1[] = { c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff };
554  const uint8_t palrgb2[] = { c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff };
555  const int d1 = diff(palrgb1, rgb);
556  const int d2 = diff(palrgb2, rgb);
557  if (d1 != d2) {
559  "/!\\ %02X%02X%02X: %d ! %d (%06"PRIX32" ! %06"PRIX32") / dist: %d ! %d\n",
560  r, g, b, r1, r2, c1 & 0xffffff, c2 & 0xffffff, d1, d2);
561  ret = 1;
562  }
563  }
564  }
565  }
566  }
567  return ret;
568 }
569 
570 struct color {
571  uint32_t value;
573 };
574 
575 struct color_rect {
578 };
579 
580 typedef int (*cmp_func)(const void *, const void *);
581 
582 #define DECLARE_CMP_FUNC(name, pos) \
583 static int cmp_##name(const void *pa, const void *pb) \
584 { \
585  const struct color *a = pa; \
586  const struct color *b = pb; \
587  return (a->value >> (8 * (2 - (pos))) & 0xff) \
588  - (b->value >> (8 * (2 - (pos))) & 0xff); \
589 }
590 
594 
595 static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b};
596 
597 static int get_next_color(const uint8_t *color_used, const uint32_t *palette,
598  int *component, const struct color_rect *box)
599 {
600  int wr, wg, wb;
601  int i, longest = 0;
602  unsigned nb_color = 0;
603  struct color_rect ranges;
604  struct color tmp_pal[256];
605  cmp_func cmpf;
606 
607  ranges.min[0] = ranges.min[1] = ranges.min[2] = 0xff;
608  ranges.max[0] = ranges.max[1] = ranges.max[2] = 0x00;
609 
610  for (i = 0; i < AVPALETTE_COUNT; i++) {
611  const uint32_t c = palette[i];
612  const uint8_t r = c >> 16 & 0xff;
613  const uint8_t g = c >> 8 & 0xff;
614  const uint8_t b = c & 0xff;
615 
616  if (color_used[i] ||
617  r < box->min[0] || g < box->min[1] || b < box->min[2] ||
618  r > box->max[0] || g > box->max[1] || b > box->max[2])
619  continue;
620 
621  if (r < ranges.min[0]) ranges.min[0] = r;
622  if (g < ranges.min[1]) ranges.min[1] = g;
623  if (b < ranges.min[2]) ranges.min[2] = b;
624 
625  if (r > ranges.max[0]) ranges.max[0] = r;
626  if (g > ranges.max[1]) ranges.max[1] = g;
627  if (b > ranges.max[2]) ranges.max[2] = b;
628 
629  tmp_pal[nb_color].value = c;
630  tmp_pal[nb_color].pal_id = i;
631 
632  nb_color++;
633  }
634 
635  if (!nb_color)
636  return -1;
637 
638  /* define longest axis that will be the split component */
639  wr = ranges.max[0] - ranges.min[0];
640  wg = ranges.max[1] - ranges.min[1];
641  wb = ranges.max[2] - ranges.min[2];
642  if (wr >= wg && wr >= wb) longest = 0;
643  if (wg >= wr && wg >= wb) longest = 1;
644  if (wb >= wr && wb >= wg) longest = 2;
645  cmpf = cmp_funcs[longest];
646  *component = longest;
647 
648  /* sort along this axis to get median */
649  AV_QSORT(tmp_pal, nb_color, struct color, cmpf);
650 
651  return tmp_pal[nb_color >> 1].pal_id;
652 }
653 
654 static int colormap_insert(struct color_node *map,
655  uint8_t *color_used,
656  int *nb_used,
657  const uint32_t *palette,
658  const struct color_rect *box)
659 {
660  uint32_t c;
661  int component, cur_id;
662  int node_left_id = -1, node_right_id = -1;
663  struct color_node *node;
664  struct color_rect box1, box2;
665  const int pal_id = get_next_color(color_used, palette, &component, box);
666 
667  if (pal_id < 0)
668  return -1;
669 
670  /* create new node with that color */
671  cur_id = (*nb_used)++;
672  c = palette[pal_id];
673  node = &map[cur_id];
674  node->split = component;
675  node->palette_id = pal_id;
676  node->val[0] = c>>16 & 0xff;
677  node->val[1] = c>> 8 & 0xff;
678  node->val[2] = c & 0xff;
679 
680  color_used[pal_id] = 1;
681 
682  /* get the two boxes this node creates */
683  box1 = box2 = *box;
684  box1.max[component] = node->val[component];
685  box2.min[component] = node->val[component] + 1;
686 
687  node_left_id = colormap_insert(map, color_used, nb_used, palette, &box1);
688 
689  if (box2.min[component] <= box2.max[component])
690  node_right_id = colormap_insert(map, color_used, nb_used, palette, &box2);
691 
692  node->left_id = node_left_id;
693  node->right_id = node_right_id;
694 
695  return cur_id;
696 }
697 
698 static int cmp_pal_entry(const void *a, const void *b)
699 {
700  const int c1 = *(const uint32_t *)a & 0xffffff;
701  const int c2 = *(const uint32_t *)b & 0xffffff;
702  return c1 - c2;
703 }
704 
706 {
707  int i, nb_used = 0;
708  uint8_t color_used[AVPALETTE_COUNT] = {0};
709  uint32_t last_color = 0;
710  struct color_rect box;
711 
712  /* disable transparent colors and dups */
713  qsort(s->palette, AVPALETTE_COUNT, sizeof(*s->palette), cmp_pal_entry);
714  for (i = 0; i < AVPALETTE_COUNT; i++) {
715  const uint32_t c = s->palette[i];
716  if (i != 0 && c == last_color) {
717  color_used[i] = 1;
718  continue;
719  }
720  last_color = c;
721  if ((c & 0xff000000) != 0xff000000) {
722  color_used[i] = 1; // ignore transparent color(s)
723  continue;
724  }
725  }
726 
727  box.min[0] = box.min[1] = box.min[2] = 0x00;
728  box.max[0] = box.max[1] = box.max[2] = 0xff;
729 
730  colormap_insert(s->map, color_used, &nb_used, s->palette, &box);
731 
732  if (s->dot_filename)
733  disp_tree(s->map, s->dot_filename);
734 
735  if (s->debug_accuracy) {
737  av_log(NULL, AV_LOG_INFO, "Accuracy check passed\n");
738  }
739 }
740 
741 static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1,
742  const AVFrame *in2, int frame_count)
743 {
744  int x, y;
745  const uint32_t *palette = s->palette;
746  uint32_t *src1 = (uint32_t *)in1->data[0];
747  uint8_t *src2 = in2->data[0];
748  const int src1_linesize = in1->linesize[0] >> 2;
749  const int src2_linesize = in2->linesize[0];
750  const float div = in1->width * in1->height * 3;
751  unsigned mean_err = 0;
752 
753  for (y = 0; y < in1->height; y++) {
754  for (x = 0; x < in1->width; x++) {
755  const uint32_t c1 = src1[x];
756  const uint32_t c2 = palette[src2[x]];
757  const uint8_t rgb1[] = {c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff};
758  const uint8_t rgb2[] = {c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff};
759  mean_err += diff(rgb1, rgb2);
760  }
761  src1 += src1_linesize;
762  src2 += src2_linesize;
763  }
764 
765  s->total_mean_err += mean_err;
766 
767  av_log(NULL, AV_LOG_INFO, "MEP:%.3f TotalMEP:%.3f\n",
768  mean_err / div, s->total_mean_err / (div * frame_count));
769 }
770 
772  const AVFrame *prv_src, const AVFrame *cur_src,
773  const AVFrame *prv_dst, AVFrame *cur_dst,
774  int *xp, int *yp, int *wp, int *hp)
775 {
776  int x_start = 0, y_start = 0;
777  int width = cur_src->width;
778  int height = cur_src->height;
779 
780  if (prv_src && diff_mode == DIFF_MODE_RECTANGLE) {
781  int y;
782  int x_end = cur_src->width - 1,
783  y_end = cur_src->height - 1;
784  const uint32_t *prv_srcp = (const uint32_t *)prv_src->data[0];
785  const uint32_t *cur_srcp = (const uint32_t *)cur_src->data[0];
786  const uint8_t *prv_dstp = prv_dst->data[0];
787  uint8_t *cur_dstp = cur_dst->data[0];
788 
789  const int prv_src_linesize = prv_src->linesize[0] >> 2;
790  const int cur_src_linesize = cur_src->linesize[0] >> 2;
791  const int prv_dst_linesize = prv_dst->linesize[0];
792  const int cur_dst_linesize = cur_dst->linesize[0];
793 
794  /* skip common lines */
795  while (y_start < y_end && !memcmp(prv_srcp + y_start*prv_src_linesize,
796  cur_srcp + y_start*cur_src_linesize,
797  cur_src->width * 4)) {
798  memcpy(cur_dstp + y_start*cur_dst_linesize,
799  prv_dstp + y_start*prv_dst_linesize,
800  cur_dst->width);
801  y_start++;
802  }
803  while (y_end > y_start && !memcmp(prv_srcp + y_end*prv_src_linesize,
804  cur_srcp + y_end*cur_src_linesize,
805  cur_src->width * 4)) {
806  memcpy(cur_dstp + y_end*cur_dst_linesize,
807  prv_dstp + y_end*prv_dst_linesize,
808  cur_dst->width);
809  y_end--;
810  }
811 
812  height = y_end + 1 - y_start;
813 
814  /* skip common columns */
815  while (x_start < x_end) {
816  int same_column = 1;
817  for (y = y_start; y <= y_end; y++) {
818  if (prv_srcp[y*prv_src_linesize + x_start] != cur_srcp[y*cur_src_linesize + x_start]) {
819  same_column = 0;
820  break;
821  }
822  }
823  if (!same_column)
824  break;
825  x_start++;
826  }
827  while (x_end > x_start) {
828  int same_column = 1;
829  for (y = y_start; y <= y_end; y++) {
830  if (prv_srcp[y*prv_src_linesize + x_end] != cur_srcp[y*cur_src_linesize + x_end]) {
831  same_column = 0;
832  break;
833  }
834  }
835  if (!same_column)
836  break;
837  x_end--;
838  }
839  width = x_end + 1 - x_start;
840 
841  if (x_start) {
842  for (y = y_start; y <= y_end; y++)
843  memcpy(cur_dstp + y*cur_dst_linesize,
844  prv_dstp + y*prv_dst_linesize, x_start);
845  }
846  if (x_end != cur_src->width - 1) {
847  const int copy_len = cur_src->width - 1 - x_end;
848  for (y = y_start; y <= y_end; y++)
849  memcpy(cur_dstp + y*cur_dst_linesize + x_end + 1,
850  prv_dstp + y*prv_dst_linesize + x_end + 1,
851  copy_len);
852  }
853  }
854  *xp = x_start;
855  *yp = y_start;
856  *wp = width;
857  *hp = height;
858 }
859 
861 {
862  int x, y, w, h;
863  AVFilterContext *ctx = inlink->dst;
864  PaletteUseContext *s = ctx->priv;
865  AVFilterLink *outlink = inlink->dst->outputs[0];
866 
867  AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
868  if (!out) {
869  av_frame_free(&in);
870  return NULL;
871  }
872  av_frame_copy_props(out, in);
873 
875  s->last_out, out, &x, &y, &w, &h);
876  av_frame_free(&s->last_in);
877  av_frame_free(&s->last_out);
878  s->last_in = av_frame_clone(in);
879  s->last_out = av_frame_clone(out);
880  if (!s->last_in || !s->last_out ||
882  av_frame_free(&in);
883  av_frame_free(&out);
884  return NULL;
885  }
886 
887  ff_dlog(ctx, "%dx%d rect: (%d;%d) -> (%d,%d) [area:%dx%d]\n",
888  w, h, x, y, x+w, y+h, in->width, in->height);
889 
890  if (s->set_frame(s, out, in, x, y, w, h) < 0) {
891  av_frame_free(&out);
892  return NULL;
893  }
894  memcpy(out->data[1], s->palette, AVPALETTE_SIZE);
895  if (s->calc_mean_err)
896  debug_mean_error(s, in, out, inlink->frame_count_out);
897  av_frame_free(&in);
898  return out;
899 }
900 
901 static int config_output(AVFilterLink *outlink)
902 {
903  int ret;
904  AVFilterContext *ctx = outlink->src;
905  PaletteUseContext *s = ctx->priv;
906 
907  ret = ff_framesync_init_dualinput(&s->fs, ctx);
908  if (ret < 0)
909  return ret;
910  s->fs.opt_repeatlast = 1; // only 1 frame in the palette
911  s->fs.in[1].before = s->fs.in[1].after = EXT_INFINITY;
913 
914  outlink->w = ctx->inputs[0]->w;
915  outlink->h = ctx->inputs[0]->h;
916 
917  outlink->time_base = ctx->inputs[0]->time_base;
918  if ((ret = ff_framesync_configure(&s->fs)) < 0)
919  return ret;
920  return 0;
921 }
922 
924 {
925  AVFilterContext *ctx = inlink->dst;
926 
927  if (inlink->w * inlink->h != AVPALETTE_COUNT) {
928  av_log(ctx, AV_LOG_ERROR,
929  "Palette input must contain exactly %d pixels. "
930  "Specified input has %dx%d=%d pixels\n",
931  AVPALETTE_COUNT, inlink->w, inlink->h,
932  inlink->w * inlink->h);
933  return AVERROR(EINVAL);
934  }
935  return 0;
936 }
937 
938 static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame)
939 {
940  int i, x, y;
941  const uint32_t *p = (const uint32_t *)palette_frame->data[0];
942  const int p_linesize = palette_frame->linesize[0] >> 2;
943 
944  if (s->new) {
945  memset(s->palette, 0, sizeof(s->palette));
946  memset(s->map, 0, sizeof(s->map));
947  for (i = 0; i < CACHE_SIZE; i++)
948  av_freep(&s->cache[i].entries);
949  memset(s->cache, 0, sizeof(s->cache));
950  }
951 
952  i = 0;
953  for (y = 0; y < palette_frame->height; y++) {
954  for (x = 0; x < palette_frame->width; x++)
955  s->palette[i++] = p[x];
956  p += p_linesize;
957  }
958 
959  load_colormap(s);
960 
961  if (!s->new)
962  s->palette_loaded = 1;
963 }
964 
966 {
967  AVFilterContext *ctx = fs->parent;
968  AVFilterLink *inlink = ctx->inputs[0];
969  PaletteUseContext *s = ctx->priv;
970  AVFrame *master, *second, *out;
971  int ret;
972 
973  // writable for error diffusal dithering
974  ret = ff_framesync_dualinput_get_writable(fs, &master, &second);
975  if (ret < 0)
976  return ret;
977  if (!master || !second) {
978  ret = AVERROR_BUG;
979  goto error;
980  }
981  if (!s->palette_loaded) {
982  load_palette(s, second);
983  }
984  out = apply_palette(inlink, master);
985  return ff_filter_frame(ctx->outputs[0], out);
986 
987 error:
988  av_frame_free(&master);
989  av_frame_free(&second);
990  return ret;
991 }
992 
993 #define DEFINE_SET_FRAME(color_search, name, value) \
994 static int set_frame_##name(PaletteUseContext *s, AVFrame *out, AVFrame *in, \
995  int x_start, int y_start, int w, int h) \
996 { \
997  return set_frame(s, out, in, x_start, y_start, w, h, value, color_search); \
998 }
999 
1000 #define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro) \
1001  DEFINE_SET_FRAME(color_search_macro, color_search##_##none, DITHERING_NONE) \
1002  DEFINE_SET_FRAME(color_search_macro, color_search##_##bayer, DITHERING_BAYER) \
1003  DEFINE_SET_FRAME(color_search_macro, color_search##_##heckbert, DITHERING_HECKBERT) \
1004  DEFINE_SET_FRAME(color_search_macro, color_search##_##floyd_steinberg, DITHERING_FLOYD_STEINBERG) \
1005  DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2, DITHERING_SIERRA2) \
1006  DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2_4a, DITHERING_SIERRA2_4A) \
1007 
1011 
1012 #define DITHERING_ENTRIES(color_search) { \
1013  set_frame_##color_search##_none, \
1014  set_frame_##color_search##_bayer, \
1015  set_frame_##color_search##_heckbert, \
1016  set_frame_##color_search##_floyd_steinberg, \
1017  set_frame_##color_search##_sierra2, \
1018  set_frame_##color_search##_sierra2_4a, \
1019 }
1020 
1022  DITHERING_ENTRIES(nns_iterative),
1023  DITHERING_ENTRIES(nns_recursive),
1024  DITHERING_ENTRIES(bruteforce),
1025 };
1026 
1027 static int dither_value(int p)
1028 {
1029  const int q = p ^ (p >> 3);
1030  return (p & 4) >> 2 | (q & 4) >> 1 \
1031  | (p & 2) << 1 | (q & 2) << 2 \
1032  | (p & 1) << 4 | (q & 1) << 5;
1033 }
1034 
1036 {
1037  PaletteUseContext *s = ctx->priv;
1038 
1039  s->set_frame = set_frame_lut[s->color_search_method][s->dither];
1040 
1041  if (s->dither == DITHERING_BAYER) {
1042  int i;
1043  const int delta = 1 << (5 - s->bayer_scale); // to avoid too much luma
1044 
1045  for (i = 0; i < FF_ARRAY_ELEMS(s->ordered_dither); i++)
1046  s->ordered_dither[i] = (dither_value(i) >> s->bayer_scale) - delta;
1047  }
1048 
1049  return 0;
1050 }
1051 
1053 {
1054  PaletteUseContext *s = ctx->priv;
1055  return ff_framesync_activate(&s->fs);
1056 }
1057 
1059 {
1060  int i;
1061  PaletteUseContext *s = ctx->priv;
1062 
1063  ff_framesync_uninit(&s->fs);
1064  for (i = 0; i < CACHE_SIZE; i++)
1065  av_freep(&s->cache[i].entries);
1066  av_frame_free(&s->last_in);
1067  av_frame_free(&s->last_out);
1068 }
1069 
1070 static const AVFilterPad paletteuse_inputs[] = {
1071  {
1072  .name = "default",
1073  .type = AVMEDIA_TYPE_VIDEO,
1074  },{
1075  .name = "palette",
1076  .type = AVMEDIA_TYPE_VIDEO,
1077  .config_props = config_input_palette,
1078  },
1079  { NULL }
1080 };
1081 
1083  {
1084  .name = "default",
1085  .type = AVMEDIA_TYPE_VIDEO,
1086  .config_props = config_output,
1087  },
1088  { NULL }
1089 };
1090 
1092  .name = "paletteuse",
1093  .description = NULL_IF_CONFIG_SMALL("Use a palette to downsample an input video stream."),
1094  .priv_size = sizeof(PaletteUseContext),
1096  .init = init,
1097  .uninit = uninit,
1098  .activate = activate,
1099  .inputs = paletteuse_inputs,
1100  .outputs = paletteuse_outputs,
1101  .priv_class = &paletteuse_class,
1102 };
diff_mode
Definition: vf_paletteuse.c:52
int(* cmp_func)(const void *, const void *)
uint64_t total_mean_err
AVFILTER_DEFINE_CLASS(paletteuse)
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:768
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
static int shift(int a, int b)
Definition: sonic.c:82
static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame)
This structure describes decoded (raw) audio or video data.
Definition: frame.h:201
AVOption.
Definition: opt.h:246
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
color_search_method
Definition: vf_paletteuse.c:45
Main libavfilter public API header.
static AVFrame * apply_palette(AVFilterLink *inlink, AVFrame *in)
const char * g
Definition: vf_curves.c:112
dithering_mode
Definition: vf_paletteuse.c:35
int(* on_event)(struct FFFrameSync *fs)
Callback called when a frame event is ready.
Definition: framesync.h:172
static int query_formats(AVFilterContext *ctx)
FILE * av_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
Definition: file_open.c:154
const char * b
Definition: vf_curves.c:113
static const AVFilterPad paletteuse_outputs[]
static int debug_accuracy(const struct color_node *node, const uint32_t *palette, const enum color_search_method search_method)
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:117
static av_always_inline int dither_color(uint32_t px, int er, int eg, int eb, int scale, int shift)
const char * master
Definition: vf_curves.c:114
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:92
#define src
Definition: vp8dsp.c:254
static av_cold int init(AVFilterContext *ctx)
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
enum FFFrameSyncExtMode before
Extrapolation mode for timestamps before the first frame.
Definition: framesync.h:86
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
const char * name
Pad name.
Definition: internal.h:60
AVFilterContext * parent
Parent filter context.
Definition: framesync.h:152
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
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:80
AVFilter ff_vf_paletteuse
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1151
uint8_t
#define av_cold
Definition: attributes.h:82
float delta
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:73
AVOptions.
uint8_t pal_id
#define INDENT
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:94
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:361
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
uint32_t color
Definition: vf_paletteuse.c:69
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:399
static const cmp_func cmp_funcs[]
static int config_input_palette(AVFilterLink *inlink)
FFFrameSyncIn * in
Pointer to array of inputs.
Definition: framesync.h:203
#define height
FFFrameSync fs
Definition: vf_paletteuse.c:85
static const uint64_t c1
Definition: murmur3.c:49
#define ff_dlog(a,...)
enum FFFrameSyncExtMode after
Extrapolation mode for timestamps after the last frame.
Definition: framesync.h:91
uint32_t palette[AVPALETTE_COUNT]
Definition: vf_paletteuse.c:88
static const AVOption paletteuse_options[]
#define av_log(a,...)
uint8_t val[3]
Definition: vf_paletteuse.c:59
A filter pad used for either input or output.
Definition: internal.h:54
uint8_t hash[HASH_SIZE]
Definition: movenc.c:57
#define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro)
static int disp_tree(const struct color_node *node, const char *fname)
set_frame_func set_frame
Definition: vf_paletteuse.c:92
static int load_apply_palette(FFFrameSync *fs)
int width
Definition: frame.h:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
uint8_t max[3]
#define AV_BPRINT_SIZE_UNLIMITED
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:293
Frame sync structure.
Definition: framesync.h:146
#define AVERROR(e)
Definition: error.h:43
static void colormap_nearest_node(const struct color_node *map, const int node_pos, const uint8_t *target, struct nearest_color *nearest)
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:163
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:179
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
const char * r
Definition: vf_curves.c:111
static const uint8_t dither[8][8]
Definition: vf_fspp.c:57
void * priv
private data for use by the filter
Definition: avfilter.h:353
static const set_frame_func set_frame_lut[NB_COLOR_SEARCHES][NB_DITHERING]
uint16_t width
Definition: gdv.c:47
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition: framesync.c:344
int opt_repeatlast
Definition: framesync.h:205
static int dither_value(int p)
static char * split(char *message, char delim)
Definition: af_channelmap.c:81
static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target)
common internal API header
static void disp_node(AVBPrint *buf, const struct color_node *map, int parent_id, int node_id, int depth)
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:440
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)
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
AVFormatContext * ctx
Definition: movenc.c:48
#define NBITS
Definition: vf_paletteuse.c:65
uint8_t min[3]
static av_always_inline int diff(const uint8_t *c1, const uint8_t *c2)
static const AVFilterPad outputs[]
Definition: af_afftfilt.c:389
static void error(const char *err)
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:492
static int activate(AVFilterContext *ctx)
#define FF_ARRAY_ELEMS(a)
static av_always_inline int get_dst_color_err(struct cache_node *cache, uint32_t c, const struct color_node *map, const uint32_t *palette, int *er, int *eg, int *eb, const enum color_search_method search_method)
static int config_output(AVFilterLink *outlink)
#define src1
Definition: h264pred.c:139
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
static const AVFilterPad inputs[]
Definition: af_afftfilt.c:379
Extend the frame to infinity.
Definition: framesync.h:75
static int cmp_pal_entry(const void *a, const void *b)
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:308
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:232
#define AV_PIX_FMT_RGB32
Definition: pixfmt.h:353
AVFrame * last_out
Definition: vf_paletteuse.c:97
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31))))#defineSET_CONV_FUNC_GROUP(ofmt, ifmt) staticvoidset_generic_function(AudioConvert *ac){}voidff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, intsample_rate, intapply_map){AudioConvert *ac;intin_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) returnNULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt)>2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);returnNULL;}returnac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}elseif(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;elseac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);returnac;}intff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){intuse_generic=1;intlen=in->nb_samples;intp;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%dsamples-audio_convert:%sto%s(dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));returnff_convert_dither(ac-> in
void * buf
Definition: avisynth_c.h:690
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
Describe the class of an AVClass context structure.
Definition: log.h:67
#define DITHERING_ENTRIES(color_search)
Filter definition.
Definition: avfilter.h:144
static int get_next_color(const uint8_t *color_used, const uint32_t *palette, int *component, const struct color_rect *box)
const char * name
Filter name.
Definition: avfilter.h:148
static void load_colormap(PaletteUseContext *s)
static int colormap_insert(struct color_node *map, uint8_t *color_used, int *nb_used, const uint32_t *palette, const struct color_rect *box)
const VDPAUPixFmtMap * map
#define DECLARE_CMP_FUNC(name, pos)
#define OFFSET(x)
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
#define AVPALETTE_COUNT
Definition: pixfmt.h:33
#define COLORMAP_NEAREST(search, palette, root, target)
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
Definition: frame.c:560
#define FLAGS
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:215
int
uint8_t pal_entry
Definition: vf_paletteuse.c:70
struct cache_node cache[CACHE_SIZE]
Definition: vf_paletteuse.c:86
if(ret< 0)
Definition: vf_mcdeint.c:279
static double c[64]
struct cached_color * entries
Definition: vf_paletteuse.c:74
static const uint64_t c2
Definition: murmur3.c:50
static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t *rgb)
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)
static av_cold void uninit(AVFilterContext *ctx)
static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *rgb)
A list of supported formats for one end of a filter link.
Definition: formats.h:64
static av_always_inline int color_get(struct cache_node *cache, uint32_t color, uint8_t r, uint8_t g, uint8_t b, const struct color_node *map, const uint32_t *palette, const enum color_search_method search_method)
Check if the requested color is in the cache already.
An instance of a filter.
Definition: avfilter.h:338
uint8_t palette_id
Definition: vf_paletteuse.c:60
int height
Definition: frame.h:259
FILE * out
Definition: movenc.c:54
#define av_freep(p)
#define av_always_inline
Definition: attributes.h:39
static const AVFilterPad paletteuse_inputs[]
#define CACHE_SIZE
Definition: vf_paletteuse.c:66
internal API functions
struct color_node map[AVPALETTE_COUNT]
Definition: vf_paletteuse.c:87
float min
uint32_t value
AVPixelFormat
Pixel format.
Definition: pixfmt.h:60
#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
for(j=16;j >0;--j)
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:603
int ordered_dither[8 *8]
Definition: vf_paletteuse.c:94
static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1, const AVFrame *in2, int frame_count)