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
31
40 };
41
47 };
48
53 };
54
60 };
61
63 #define CACHE_SIZE (1<<(3*NBITS))
64
68 };
69
73 };
74
76
79
94
95 /* debug options */
102
103 #define OFFSET(x) offsetof(PaletteUseContext, x)
104 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
115
116 /* following are the debug options, not part of the official API */
125 };
126
128
130 {
137 if (!in || !inpal || !out) {
142 }
146 return 0;
147 }
148
150 {
151 return av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<<shift))) << 16
152 | av_clip_uint8((px >> 8 & 0xff) + ((eg * scale) / (1<<shift))) << 8
153 | av_clip_uint8((px & 0xff) + ((eb * scale) / (1<<shift)));
154 }
155
157 {
158 // XXX: try L*a*b with CIE76 (dL*dL + da*da + db*db)
159 const int dr = c1[0] - c2[0];
160 const int dg = c1[1] - c2[1];
161 const int db = c1[2] - c2[2];
162 return dr*dr + dg*dg + db*db;
163 }
164
166 {
167 int i, pal_id = -1, min_dist = INT_MAX;
168
170 const uint32_t
c = palette[i];
171
172 if ((c & 0xff000000) == 0xff000000) { // ignore transparent entry
174 palette[i]>>16 & 0xff,
175 palette[i]>> 8 & 0xff,
176 palette[i] & 0xff,
177 };
178 const int d =
diff(palrgb, rgb);
179 if (d < min_dist) {
180 pal_id = i;
181 min_dist = d;
182 }
183 }
184 }
185 return pal_id;
186 }
187
188 /* Recursive form, simpler but a bit slower. Kept for reference. */
192 };
193
195 const int node_pos,
198 {
200 const int s = kd->
split;
201 int dx, nearer_kd_id, further_kd_id;
203 const int current_to_target =
diff(target, current);
204
205 if (current_to_target < nearest->dist_sqd) {
207 nearest->
dist_sqd = current_to_target;
208 }
209
211 dx = target[
s] - current[
s];
212
215
216 if (nearer_kd_id != -1)
218
219 if (further_kd_id != -1 && dx*dx < nearest->dist_sqd)
221 }
222 }
223
225 {
229 }
230
234 };
235
237 {
238 int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0;
241
242 for (;;) {
243
244 const struct color_node *kd = &root[cur_color_id];
246 const int current_to_target =
diff(target, current);
247
248 /* Compare current color node to the target and update our best node if
249 * it's actually better. */
250 if (current_to_target < best_dist) {
251 best_node_id = cur_color_id;
252 if (!current_to_target)
253 goto end;
// exact match, we can return immediately
254 best_dist = current_to_target;
255 }
256
257 /* Check if it's not a leaf */
260 const int dx = target[
split] - current[
split];
261 int nearer_kd_id, further_kd_id;
262
263 /* Define which side is the most interesting. */
266
267 if (nearer_kd_id != -1) {
268 if (further_kd_id != -1) {
269 /* Here, both paths are defined, so we push a state for
270 * when we are going back. */
273 pos++;
274 node++;
275 }
276 /* We can now update current color with the most probable path
277 * (no need to create a state since there is nothing to save
278 * anymore). */
279 cur_color_id = nearer_kd_id;
280 continue;
281 } else if (dx*dx < best_dist) {
282 /* The nearest path isn't available, so there is only one path
283 * possible and it's the least probable. We enter it only if the
284 * distance from the current point to the hyper rectangle is
285 * less than our best distance. */
286 cur_color_id = further_kd_id;
287 continue;
288 }
289 }
290
291 /* Unstack as much as we can, typically as long as the least probable
292 * branch aren't actually probable. */
293 do {
294 if (--pos < 0)
296 node--;
297 }
while (node->
dx2 >= best_dist);
298
299 /* We got a node where the least probable branch might actually contain
300 * a relevant color. */
302 }
303
306 }
307
308 #define COLORMAP_NEAREST(search, palette, root, target) \
309 search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(root, target) : \
310 search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(root, target) : \
311 colormap_nearest_bruteforce(palette, target)
312
313 /**
314 * Check if the requested color is in the cache already. If not, find it in the
315 * color tree and cache it.
316 * Note: r, g, and b are the component of c but are passed as well to avoid
317 * recomputing them (they are generally computed by the caller for other uses).
318 */
324 {
325 int i;
333
336 if (e->
color == color)
338 }
339
342 if (!e)
347 }
348
352 int *er, int *eg, int *eb,
354 {
358 const int dstx =
color_get(cache, c, r, g, b, map, palette, search_method);
359 const uint32_t dstc = palette[dstx];
360 *er = r - (dstc >> 16 & 0xff);
361 *eg = g - (dstc >> 8 & 0xff);
362 *eb = b - (dstc & 0xff);
363 return dstx;
364 }
365
367 int x_start, int y_start, int w, int h,
370 {
375 const int src_linesize = in ->
linesize[0] >> 2;
376 const int dst_linesize = out->
linesize[0];
377 uint32_t *
src = ((uint32_t *)in ->
data[0]) + y_start*src_linesize;
378 uint8_t *dst = out->
data[0] + y_start*dst_linesize;
379
380 w += x_start;
381 h += y_start;
382
383 for (y = y_start; y < h; y++) {
384 for (x = x_start; x < w; x++) {
385 int er, eg, eb;
386
389 const uint8_t r8 = src[x] >> 16 & 0xff;
390 const uint8_t g8 = src[x] >> 8 & 0xff;
391 const uint8_t b8 = src[x] & 0xff;
392 const uint8_t r = av_clip_uint8(r8 + d);
393 const uint8_t g = av_clip_uint8(g8 + d);
394 const uint8_t b = av_clip_uint8(b8 + d);
395 const uint32_t
c = r<<16 | g<<8 |
b;
396 const int color =
color_get(cache, c, r, g, b, map, palette, search_method);
397
398 if (color < 0)
401
403 const int right = x < w - 1, down = y < h - 1;
405
406 if (color < 0)
409
410 if (right) src[ x + 1] =
dither_color(src[ x + 1], er, eg, eb, 3, 3);
411 if ( down) src[src_linesize + x ] =
dither_color(src[src_linesize + x ], er, eg, eb, 3, 3);
412 if (right && down) src[src_linesize + x + 1] =
dither_color(src[src_linesize + x + 1], er, eg, eb, 2, 3);
413
415 const int right = x < w - 1, down = y < h - 1, left = x > x_start;
417
418 if (color < 0)
421
422 if (right) src[ x + 1] =
dither_color(src[ x + 1], er, eg, eb, 7, 4);
423 if (left && down) src[src_linesize + x - 1] =
dither_color(src[src_linesize + x - 1], er, eg, eb, 3, 4);
424 if ( down) src[src_linesize + x ] =
dither_color(src[src_linesize + x ], er, eg, eb, 5, 4);
425 if (right && down) src[src_linesize + x + 1] =
dither_color(src[src_linesize + x + 1], er, eg, eb, 1, 4);
426
428 const int right = x < w - 1, down = y < h - 1, left = x > x_start;
429 const int right2 = x < w - 2, left2 = x > x_start + 1;
431
432 if (color < 0)
435
436 if (right) src[ x + 1] =
dither_color(src[ x + 1], er, eg, eb, 4, 4);
437 if (right2) src[ x + 2] =
dither_color(src[ x + 2], er, eg, eb, 3, 4);
438
439 if (down) {
440 if (left2) src[ src_linesize + x - 2] =
dither_color(src[ src_linesize + x - 2], er, eg, eb, 1, 4);
441 if (left) src[ src_linesize + x - 1] =
dither_color(src[ src_linesize + x - 1], er, eg, eb, 2, 4);
442 src[ src_linesize + x ] =
dither_color(src[ src_linesize + x ], er, eg, eb, 3, 4);
443 if (right) src[ src_linesize + x + 1] =
dither_color(src[ src_linesize + x + 1], er, eg, eb, 2, 4);
444 if (right2) src[ src_linesize + x + 2] =
dither_color(src[ src_linesize + x + 2], er, eg, eb, 1, 4);
445 }
446
448 const int right = x < w - 1, down = y < h - 1, left = x > x_start;
450
451 if (color < 0)
454
455 if (right) src[ x + 1] =
dither_color(src[ x + 1], er, eg, eb, 2, 2);
456 if (left && down) src[src_linesize + x - 1] =
dither_color(src[src_linesize + x - 1], er, eg, eb, 1, 2);
457 if ( down) src[src_linesize + x ] =
dither_color(src[src_linesize + x ], er, eg, eb, 1, 2);
458
459 } else {
460 const uint8_t r = src[x] >> 16 & 0xff;
461 const uint8_t g = src[x] >> 8 & 0xff;
463 const int color =
color_get(cache, src[x] & 0xffffff, r, g, b, map, palette, search_method);
464
465 if (color < 0)
468 }
469 }
470 src += src_linesize;
471 dst += dst_linesize;
472 }
473 return 0;
474 }
475
479 int parent_id, int node_id,
481 {
482 const struct color_node *node = &map[node_id];
483 const uint32_t fontcolor = node->
val[0] > 0x50 &&
484 node->
val[1] > 0x50 &&
485 node->
val[2] > 0x50 ? 0 : 0xffffff;
487 "label=\"%c%02X%c%02X%c%02X%c\" "
488 "fillcolor=\"#%02x%02x%02x\" "
489 "fontcolor=\"#%06X\"]\n",
495 node->
val[0], node->
val[1], node->
val[2],
496 fontcolor);
497 if (parent_id != -1)
498 av_bprintf(buf,
"%*cnode%d -> node%d\n", depth*INDENT,
' ',
502 }
503
504 // debug_kdtree=kdtree.dot -> dot -Tpng kdtree.dot > kdtree.png
506 {
509
510 if (!f) {
515 }
516
518
520 av_bprintf(&buf,
" node [style=filled fontsize=10 shape=box]\n");
523
524 fwrite(buf.str, 1, buf.len, f);
525 fclose(f);
527 return 0;
528 }
529
532 {
534
535 for (r = 0; r < 256; r++) {
536 for (g = 0; g < 256; g++) {
537 for (b = 0; b < 256; b++) {
541 if (r1 != r2) {
542 const uint32_t
c1 = palette[r1];
543 const uint32_t
c2 = palette[r2];
544 const uint8_t palrgb1[] = { c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff };
545 const uint8_t palrgb2[] = { c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff };
546 const int d1 =
diff(palrgb1, rgb);
547 const int d2 =
diff(palrgb2, rgb);
548 if (d1 != d2) {
550 "/!\\ %02X%02X%02X: %d ! %d (%06X ! %06X) / dist: %d ! %d\n",
551 r, g, b, r1, r2, c1 & 0xffffff, c2 & 0xffffff, d1, d2);
552 ret = 1;
553 }
554 }
555 }
556 }
557 }
559 }
560
564 };
565
569 };
570
571 typedef int (*
cmp_func)(
const void *,
const void *);
572
573 #define DECLARE_CMP_FUNC(name, pos) \
574 static int cmp_##name(const void *pa, const void *pb) \
575 { \
576 const struct color *a = pa; \
577 const struct color *b = pb; \
578 return (a->value >> (8 * (2 - (pos))) & 0xff) \
579 - (b->value >> (8 * (2 - (pos))) & 0xff); \
580 }
581
585
587
590 {
591 int wr, wg, wb;
592 int i, longest = 0;
593 unsigned nb_color = 0;
595 struct color tmp_pal[256];
597
598 ranges.
min[0] = ranges.
min[1] = ranges.
min[2] = 0xff;
599 ranges.
max[0] = ranges.
max[1] = ranges.
max[2] = 0x00;
600
602 const uint32_t
c = palette[i];
606
607 if (color_used[i] ||
608 r < box->
min[0] || g < box->
min[1] || b < box->
min[2] ||
609 r > box->
max[0] || g > box->
max[1] || b > box->
max[2])
610 continue;
611
612 if (r < ranges.
min[0]) ranges.
min[0] =
r;
613 if (g < ranges.
min[1]) ranges.
min[1] =
g;
614 if (b < ranges.
min[2]) ranges.
min[2] =
b;
615
616 if (r > ranges.
max[0]) ranges.
max[0] =
r;
617 if (g > ranges.
max[1]) ranges.
max[1] =
g;
618 if (b > ranges.
max[2]) ranges.
max[2] =
b;
619
620 tmp_pal[nb_color].
value =
c;
621 tmp_pal[nb_color].
pal_id = i;
622
623 nb_color++;
624 }
625
626 if (!nb_color)
627 return -1;
628
629 /* define longest axis that will be the split component */
630 wr = ranges.
max[0] - ranges.
min[0];
631 wg = ranges.
max[1] - ranges.
min[1];
632 wb = ranges.
max[2] - ranges.
min[2];
633 if (wr >= wg && wr >= wb) longest = 0;
634 if (wg >= wr && wg >= wb) longest = 1;
635 if (wb >= wr && wb >= wg) longest = 2;
637 *component = longest;
638
639 /* sort along this axis to get median */
641
642 return tmp_pal[nb_color >> 1].
pal_id;
643 }
644
647 int *nb_used,
650 {
652 int component, cur_id;
653 int node_left_id = -1, node_right_id = -1;
656 const int pal_id =
get_next_color(color_used, palette, &component, box);
657
658 if (pal_id < 0)
659 return -1;
660
661 /* create new node with that color */
662 cur_id = (*nb_used)++;
663 c = palette[pal_id];
664 node = &map[cur_id];
665 node->
split = component;
667 node->
val[0] = c>>16 & 0xff;
668 node->
val[1] = c>> 8 & 0xff;
669 node->
val[2] = c & 0xff;
670
671 color_used[pal_id] = 1;
672
673 /* get the two boxes this node creates */
674 box1 = box2 = *box;
675 box1.
max[component] = node->
val[component];
676 box2.
min[component] = node->
val[component] + 1;
677
678 node_left_id =
colormap_insert(map, color_used, nb_used, palette, &box1);
679
680 if (box2.
min[component] <= box2.
max[component])
681 node_right_id =
colormap_insert(map, color_used, nb_used, palette, &box2);
682
685
686 return cur_id;
687 }
688
690 {
691 const int c1 = *(
const uint32_t *)a & 0xffffff;
692 const int c2 = *(
const uint32_t *)b & 0xffffff;
694 }
695
697 {
698 int i, nb_used = 0;
700 uint32_t last_color = 0;
702
703 /* disable transparent colors and dups */
707 if (i != 0 && c == last_color) {
708 color_used[i] = 1;
709 continue;
710 }
712 if ((c & 0xff000000) != 0xff000000) {
713 color_used[i] = 1; // ignore transparent color(s)
714 continue;
715 }
716 }
717
718 box.
min[0] = box.
min[1] = box.
min[2] = 0x00;
719 box.
max[0] = box.
max[1] = box.
max[2] = 0xff;
720
722
725
729 }
730 }
731
733 const AVFrame *in2,
int frame_count)
734 {
737 uint32_t *src1 = (uint32_t *)in1->
data[0];
739 const int src1_linesize = in1->
linesize[0] >> 2;
740 const int src2_linesize = in2->
linesize[0];
742 unsigned mean_err = 0;
743
745 for (x = 0; x < in1->
width; x++) {
746 const uint32_t
c1 = src1[x];
747 const uint32_t
c2 = palette[src2[x]];
748 const uint8_t rgb1[] = {c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff};
749 const uint8_t rgb2[] = {c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff};
750 mean_err +=
diff(rgb1, rgb2);
751 }
752 src1 += src1_linesize;
753 src2 += src2_linesize;
754 }
755
757
760 }
761
765 int *xp, int *yp, int *wp, int *hp)
766 {
767 int x_start = 0, y_start = 0;
770
773 int x_end = cur_src->
width - 1,
774 y_end = cur_src->
height - 1;
775 const uint32_t *prv_srcp = (
const uint32_t *)prv_src->
data[0];
776 const uint32_t *cur_srcp = (
const uint32_t *)cur_src->
data[0];
779
780 const int prv_src_linesize = prv_src->
linesize[0] >> 2;
781 const int cur_src_linesize = cur_src->
linesize[0] >> 2;
782 const int prv_dst_linesize = prv_dst->
linesize[0];
783 const int cur_dst_linesize = cur_dst->
linesize[0];
784
785 /* skip common lines */
786 while (y_start < y_end && !memcmp(prv_srcp + y_start*prv_src_linesize,
787 cur_srcp + y_start*cur_src_linesize,
788 cur_src->
width * 4)) {
789 memcpy(cur_dstp + y_start*cur_dst_linesize,
790 prv_dstp + y_start*prv_dst_linesize,
792 y_start++;
793 }
794 while (y_end > y_start && !memcmp(prv_srcp + y_end*prv_src_linesize,
795 cur_srcp + y_end*cur_src_linesize,
796 cur_src->
width * 4)) {
797 memcpy(cur_dstp + y_end*cur_dst_linesize,
798 prv_dstp + y_end*prv_dst_linesize,
800 y_end--;
801 }
802
803 height = y_end + 1 - y_start;
804
805 /* skip common columns */
806 while (x_start < x_end) {
807 int same_column = 1;
808 for (y = y_start; y <= y_end; y++) {
809 if (prv_srcp[y*prv_src_linesize + x_start] != cur_srcp[y*cur_src_linesize + x_start]) {
810 same_column = 0;
811 break;
812 }
813 }
814 if (!same_column)
815 break;
816 x_start++;
817 }
818 while (x_end > x_start) {
819 int same_column = 1;
820 for (y = y_start; y <= y_end; y++) {
821 if (prv_srcp[y*prv_src_linesize + x_end] != cur_srcp[y*cur_src_linesize + x_end]) {
822 same_column = 0;
823 break;
824 }
825 }
826 if (!same_column)
827 break;
828 x_end--;
829 }
830 width = x_end + 1 - x_start;
831
832 if (x_start) {
833 for (y = y_start; y <= y_end; y++)
834 memcpy(cur_dstp + y*cur_dst_linesize,
835 prv_dstp + y*prv_dst_linesize, x_start);
836 }
837 if (x_end != cur_src->
width - 1) {
838 const int copy_len = cur_src->
width - 1 - x_end;
839 for (y = y_start; y <= y_end; y++)
840 memcpy(cur_dstp + y*cur_dst_linesize + x_end + 1,
841 prv_dstp + y*prv_dst_linesize + x_end + 1,
842 copy_len);
843 }
844 }
845 *xp = x_start;
846 *yp = y_start;
849 }
850
852 {
857
859 if (!out) {
862 }
864
876 }
877
878 av_dlog(ctx,
"%dx%d rect: (%d;%d) -> (%d,%d) [area:%dx%d]\n",
880
881 if (s->
set_frame(s, out, in, x, y, w, h) < 0) {
884 }
890 }
891
893 {
897
900
904 return 0;
905 }
906
908 {
910
913 "Palette input must contain exactly %d pixels. "
914 "Specified input has %dx%d=%d pixels\n",
916 inlink->
w * inlink->
h);
918 }
919 return 0;
920 }
921
923 {
925 const uint32_t *p = (
const uint32_t *)palette_frame->
data[0];
926 const int p_linesize = palette_frame->
linesize[0] >> 2;
927
928 i = 0;
929 for (y = 0; y < palette_frame->
height; y++) {
930 for (x = 0; x < palette_frame->
width; x++)
932 p += p_linesize;
933 }
934
936
938 }
939
942 {
947 }
949 }
950
952 {
955 }
956
957 #define DEFINE_SET_FRAME(color_search, name, value) \
958 static int set_frame_##name(PaletteUseContext *s, AVFrame *out, AVFrame *in, \
959 int x_start, int y_start, int w, int h) \
960 { \
961 return set_frame(s, out, in, x_start, y_start, w, h, value, color_search); \
962 }
963
964 #define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro) \
965 DEFINE_SET_FRAME(color_search_macro, color_search##_##none, DITHERING_NONE) \
966 DEFINE_SET_FRAME(color_search_macro, color_search##_##bayer, DITHERING_BAYER) \
967 DEFINE_SET_FRAME(color_search_macro, color_search##_##heckbert, DITHERING_HECKBERT) \
968 DEFINE_SET_FRAME(color_search_macro, color_search##_##floyd_steinberg, DITHERING_FLOYD_STEINBERG) \
969 DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2, DITHERING_SIERRA2) \
970 DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2_4a, DITHERING_SIERRA2_4A) \
971
975
976 #define DITHERING_ENTRIES(color_search) { \
977 set_frame_##color_search##_none, \
978 set_frame_##color_search##_bayer, \
979 set_frame_##color_search##_heckbert, \
980 set_frame_##color_search##_floyd_steinberg, \
981 set_frame_##color_search##_sierra2, \
982 set_frame_##color_search##_sierra2_4a, \
983 }
984
989 };
990
992 {
993 const int q = p ^ (p >> 3);
994 return (p & 4) >> 2 | (q & 4) >> 1 \
995 | (p & 2) << 1 | (q & 2) << 2 \
996 | (p & 1) << 4 | (q & 1) << 5;
997 }
998
1000 {
1004
1006
1008 int i;
1010
1013 }
1014
1015 return 0;
1016 }
1017
1019 {
1022 }
1023
1025 {
1026 int i;
1028
1034 }
1035
1037 {
1041 .needs_writable = 1, // for error diffusal dithering
1042 },{
1043 .name = "palette",
1047 },
1049 };
1050
1052 {
1057 },
1059 };
1060
1062 .
name =
"paletteuse",
1068 .
inputs = paletteuse_inputs,
1069 .
outputs = paletteuse_outputs,
1070 .priv_class = &paletteuse_class,
1071 };