45#define MAX_DENSITY 255
46#define MAX_DENSITY_ALPHA 64
66#define VC_SIZE (1 << VC_SHIFT)
67#define VC_AREA (VC_SIZE * VC_SIZE)
68#define VC_MASK (VC_SIZE - 1)
71#define VC_KSIZE (2 * VC_RADIUS + 1)
116#define OFFSET(x) offsetof(LatticePalContext, x)
117#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
120 {
"max_colors",
"set the maximum number of palette entries to use",
OFFSET(max_colors),
AV_OPT_TYPE_INT, {.i64=256}, 2, 256,
FLAGS },
161 { 0, 55, 14, 68, 3, 58, 17, 72, },
162 { 37, 18, 50, 32, 40, 22, 54, 35, },
163 { 9, 64, 5, 59, 13, 67, 8, 63, },
164 { 46, 27, 41, 23, 49, 31, 44, 26, },
165 { 2, 57, 16, 71, 1, 56, 15, 70, },
166 { 39, 21, 52, 34, 38, 19, 51, 33, },
167 { 11, 66, 7, 62, 10, 65, 6, 60, },
168 { 48, 30, 43, 25, 47, 29, 42, 24, },
175static void vc_splat(
float *energy,
const float *kern,
int pos,
float sign)
180 const int y = (py + dy) &
VC_MASK;
182 float *erow = &energy[y <<
VC_SHIFT];
185 erow[(px + dx) &
VC_MASK] += sign * krow[dx];
194static int vc_extreme(
const float *energy,
const uint8_t *
bits,
int want_set,
int find_max)
200 if (
bits[
i] != want_set)
202 if (best < 0 || (find_max ? energy[
i] > beste : energy[
i] < beste)) {
220 float *e1,
const float *kern,
AVLFG *lfg)
227 memset(energy, 0,
VC_AREA *
sizeof(*energy));
230 for (placed = 0; placed < n1;) {
253 memcpy(e1, energy,
VC_AREA *
sizeof(*e1));
254 for (
int r = n1 - 1;
r >= 0;
r--) {
283 const int N =
s->density;
284 const int nc =
s->nc;
288 for (
int i = 0;
i < nc;
i++) {
297 for (
int i = 1;
i < nc;
i++)
300 dir = d[k] >= 0.f ? 1 : -1;
301 if (
f[k] + dir < 0 ||
f[k] + dir >
N)
318 for (
int i = 1;
i <
s->nc;
i++)
325 if (
s->nb_used ==
s->nb_alloc) {
326 const int na =
FFMAX(
s->nb_alloc * 2, 512);
333 e = &
s->list[
s->nb_used];
338 e->
ci[3] =
s->nc == 4 ?
f[3] : 0;
341 s->cell[
pos] = idx = ++
s->nb_used;
343 s->list[idx - 1].count++;
363 const uint8_t *
val =
s->idx2val;
364 const int dim =
s->dim;
365 const int i0 = ci[0], i1 = ci[1], i2 = ci[2], i3 = ci[3];
366 const int v0 =
val[i0], v1 =
val[i1], v2 =
val[i2], v3 =
val[i3];
367 int best = -1, bestd = INT_MAX;
369 if (
s->nb_alive > 0 &&
s->nb_alive <= 1024) {
370 for (
int k = 0; k <
s->nb_alive; k++) {
371 const int j =
s->alive_arr[k];
377 dv =
val[o->
ci[0]] - v0; d2 = dv * dv;
378 dv =
val[o->
ci[1]] - v1; d2 += dv * dv;
379 dv =
val[o->
ci[2]] - v2; d2 += dv * dv;
380 dv =
val[o->
ci[3]] - v3; d2 += dv * dv;
386 *out_d2 = best >= 0 ? bestd : 0;
390#define CHECK_CELL3(a, b, c) do { \
391 const int e = s->cell[((a) * dim + (b)) * dim + (c)]; \
392 if (e > 0 && e - 1 != self && list[e - 1].alive) { \
393 const int dr = val[a] - v0; \
394 const int dg = val[b] - v1; \
395 const int db = val[c] - v2; \
396 const int d2 = dr * dr + dg * dg + db * db; \
404#define CHECK_CELL4(a, b, c, l) do { \
405 const int e = s->cell[(((a) * dim + (b)) * dim + (c)) * dim + (l)]; \
406 if (e > 0 && e - 1 != self && list[e - 1].alive) { \
407 const int dr = val[a] - v0; \
408 const int dg = val[b] - v1; \
409 const int db = val[c] - v2; \
410 const int da_ = val[l] - v3; \
411 const int d2 = dr * dr + dg * dg + db * db + da_ * da_; \
419 for (
int r = 1;
r <
dim;
r++) {
420 if (best >= 0 && (
int64_t)
r *
s->min_gap *
r *
s->min_gap > bestd)
423 const int da =
FFABS(
a - i0);
430 if (!((
a +
b +
c) & 1))
433 if (i2 -
r >= 0 && !((
a +
b + i2 -
r) & 1))
435 if (i2 +
r <
dim && !((
a +
b + i2 +
r) & 1))
442 if (!((
a +
b +
c + l) & 1))
445 if (i3 -
r >= 0 && !((
a +
b +
c + i3 -
r) & 1))
447 if (i3 +
r <
dim && !((
a +
b +
c + i3 +
r) & 1))
458 *out_d2 = best >= 0 ? bestd : 0;
467 s->list[self].d2 = d2;
479 while (
i > 0 && heap[(
i - 1) / 2].imp > imp) {
480 heap[
i] = heap[(
i - 1) / 2];
490 const HeapEnt last = heap[--*nb];
493 while ((
c = 2 *
i + 1) < *nb) {
494 if (
c + 1 < *nb && heap[
c + 1].imp < heap[
c].imp)
496 if (heap[
c].imp >= last.
imp)
520 int nb_heap = 0, cap =
s->nb_used + 64;
526 if (
s->alive_alloc <
s->nb_used) {
531 if (!
s->alive_arr || !
s->alive_pos) {
535 s->alive_alloc =
s->nb_used;
538 for (
int i = 0;
i <
s->nb_used;
i++) {
541 s->alive_pos[
i] =
s->nb_alive;
542 s->alive_arr[
s->nb_alive++] =
i;
546 for (
int k = 0; k <
s->nb_alive; k++) {
547 const int i =
s->alive_arr[k];
550 heap_push(heap, &nb_heap, list[
i].count * list[
i].d2,
i);
553 while (alive > target) {
555 const int i = top.
idx;
560 if (!list[list[
i].nn].alive)
563 if (imp != top.
imp) {
565 if (nb_heap == cap) {
581 s->alive_arr[
s->alive_pos[
i]] =
s->alive_arr[--
s->nb_alive];
582 s->alive_pos[
s->alive_arr[
s->nb_alive]] =
s->alive_pos[
i];
592 return (
s->nc == 4 ? (uint32_t)
s->idx2val[e->
ci[3]] << 24 : 0xFF000000) |
593 s->idx2val[e->
ci[0]] << 16 |
594 s->idx2val[e->
ci[1]] << 8 |
595 s->idx2val[e->
ci[2]];
617 const int ro =
s->ro, go =
s->go, bo =
s->bo, ao =
s->ao, pixstep =
s->pixstep;
618 const int nc =
s->nc;
619 const uint32_t *pal = (
const uint32_t *)
out->data[1];
621 memset(
s->err[0], 0, (
w + 2) * nc *
sizeof(*
s->err[0]));
622 memset(
s->err[1], 0, (
w + 2) * nc *
sizeof(*
s->err[1]));
624 for (
int y = 0; y <
h; y++) {
626 uint8_t *
dst =
out->data[0] + y *
out->linesize[0];
627 const int dir = (y & 1) ? -1 : 1;
628 const int x0 = dir > 0 ? 0 :
w - 1;
629 int32_t *err_cur =
s->err[ y & 1] + nc;
630 int32_t *err_next =
s->err[(y + 1) & 1] + nc;
634 memset(err_next - nc, 0, (
w + 2) * nc *
sizeof(*err_next));
636 for (
int k = 0; k <
w; k++) {
637 const int x = x0 + k * dir;
638 const int32_t *e = &err_cur[x * nc];
646 px[3] =
av_clip_uint8((ao >= 0 ?
src[x * pixstep + ao] : 255) + ((e[3] + 8) >> 4));
650 for (
int i = 1;
i < nc;
i++)
653 slot1 =
s->cell[
pos];
655 const uint8_t *
val =
s->idx2val;
658 for (
int k = 0; k <
s->nb_alive; k++) {
659 const PalEntry *o = &
s->list[
s->alive_arr[k]];
662 dv =
val[o->
ci[0]] -
val[
f[0]]; d2 = dv * dv;
663 dv =
val[o->
ci[1]] -
val[
f[1]]; d2 += dv * dv;
664 dv =
val[o->
ci[2]] -
val[
f[2]]; d2 += dv * dv;
666 dv =
val[o->
ci[3]] -
val[
f[3]]; d2 += dv * dv;
673 if (
s->nb_touched ==
s->touched_alloc) {
674 const int na =
FFMAX(
s->touched_alloc * 2, 1024);
679 s->touched_alloc = na;
681 s->touched[
s->nb_touched++] =
pos;
682 s->cell[
pos] = slot1;
687 for (
int i = 0;
i < nc;
i++) {
688 static const int sh[4] = { 16, 8, 0, 24 };
689 const int qerr = px[
i] - (int)(
c >> sh[
i] & 0xff);
691 err_cur [(x + dir) * nc +
i] += qerr * 7;
692 err_next[(x - dir) * nc +
i] += qerr * 3;
693 err_next[ x * nc +
i] += qerr * 5;
694 err_next[(x + dir) * nc +
i] += qerr;
715 const int nc =
s->nc;
716 const uint32_t *pal = (
const uint32_t *)
out->data[1];
717 const uint8_t *
val =
s->idx2val;
720 memset(
s->err[0], 0, (
w + 2) * nc *
sizeof(*
s->err[0]));
721 memset(
s->err[1], 0, (
w + 2) * nc *
sizeof(*
s->err[1]));
723 for (
int y = 0; y <
h; y++) {
724 const uint32_t *ppos =
s->pixpos + (size_t)y *
w;
725 uint8_t *
dst =
out->data[0] + y *
out->linesize[0];
726 const int dir = (y & 1) ? -1 : 1;
727 const int x0 = dir > 0 ? 0 :
w - 1;
728 int32_t *err_cur =
s->err[ y & 1] + nc;
729 int32_t *err_next =
s->err[(y + 1) & 1] + nc;
733 memset(err_next - nc, 0, (
w + 2) * nc *
sizeof(*err_next));
735 for (
int k = 0; k <
w; k++) {
736 const int x = x0 + k * dir;
737 const PalEntry *e1 = &list[
s->cell[ppos[x]] - 1];
738 const int32_t *e = &err_cur[x * nc];
742 if (e1->
alive && !(e[0] | e[1] | e[2] | (nc == 4 ? e[3] : 0))) {
749 for (
int i = 0;
i < nc;
i++)
754 for (
int i = 1;
i < nc;
i++)
759 slot = list[v - 1].
nn;
766 for (
int j = 0; j <
s->nb_alive; j++) {
767 const PalEntry *o = &list[
s->alive_arr[j]];
770 dv =
val[o->
ci[0]] -
val[
f[0]]; d2 = dv * dv;
771 dv =
val[o->
ci[1]] -
val[
f[1]]; d2 += dv * dv;
772 dv =
val[o->
ci[2]] -
val[
f[2]]; d2 += dv * dv;
774 dv =
val[o->
ci[3]] -
val[
f[3]]; d2 += dv * dv;
781 if (
s->nb_touched ==
s->touched_alloc) {
782 const int na =
FFMAX(
s->touched_alloc * 2, 1024);
787 s->touched_alloc = na;
789 s->touched[
s->nb_touched++] =
pos;
790 s->cell[
pos] = -(slot + 1);
795 for (
int i = 0;
i < nc;
i++) {
796 static const int sh[4] = { 16, 8, 0, 24 };
797 const int qerr = px[
i] - (int)(
c >> sh[
i] & 0xff);
799 err_cur [(x + dir) * nc +
i] += qerr * 7;
800 err_next[(x - dir) * nc +
i] += qerr * 3;
801 err_next[ x * nc +
i] += qerr * 5;
802 err_next[(x + dir) * nc +
i] += qerr;
819 const int ro =
s->ro, go =
s->go, bo =
s->bo, ao =
s->ao, pixstep =
s->pixstep;
820 const int nc =
s->nc;
821 const uint8_t *
val =
s->idx2val;
824 for (
int k = 0; k <
s->nb_alive; k++)
825 list[
s->alive_arr[k]].
count = 0;
827 memset(
s->err[0], 0, (
w + 2) * nc *
sizeof(*
s->err[0]));
828 memset(
s->err[1], 0, (
w + 2) * nc *
sizeof(*
s->err[1]));
830 for (
int y = 0; y <
h; y++) {
832 uint32_t *ppos =
s->pixpos + (size_t)y *
w;
833 const int dir = (y & 1) ? -1 : 1;
834 const int x0 = dir > 0 ? 0 :
w - 1;
835 int32_t *err_cur =
s->err[ y & 1] + nc;
836 int32_t *err_next =
s->err[(y + 1) & 1] + nc;
840 memset(err_next - nc, 0, (
w + 2) * nc *
sizeof(*err_next));
842 for (
int k = 0; k <
w; k++) {
843 const int x = x0 + k * dir;
844 const int32_t *e = &err_cur[x * nc];
852 px[3] =
av_clip_uint8((ao >= 0 ?
src[x * pixstep + ao] : 255) + ((e[3] + 8) >> 4));
856 for (
int i = 1;
i < nc;
i++)
860 if (v > 0 && list[v - 1].alive) {
862 }
else if (v < 0 && list[-v - 1].alive) {
865 const uint8_t fci[4] = {
f[0],
f[1],
f[2], nc == 4 ?
f[3] : 0 };
870 if (
s->nb_touched ==
s->touched_alloc) {
871 const int na =
FFMAX(
s->touched_alloc * 2, 1024);
876 s->touched_alloc = na;
878 s->touched[
s->nb_touched++] =
pos;
880 s->cell[
pos] = -(j + 1);
886 for (
int i = 0;
i < nc;
i++) {
887 const int qerr = px[
i] -
val[o->
ci[
i]];
889 err_cur [(x + dir) * nc +
i] += qerr * 7;
890 err_next[(x - dir) * nc +
i] += qerr * 3;
891 err_next[ x * nc +
i] += qerr * 5;
892 err_next[(x + dir) * nc +
i] += qerr;
910 int alive =
s->nb_used;
912 while (alive >
s->max_colors) {
913 const int excess = alive -
s->max_colors;
914 const int target =
s->max_colors + excess / 2;
926 for (
int k = 0; k <
s->nb_alive;) {
927 const int i =
s->alive_arr[k];
929 if (!
s->list[
i].count) {
930 s->list[
i].alive = 0;
931 s->alive_arr[k] =
s->alive_arr[--
s->nb_alive];
932 s->alive_pos[
s->alive_arr[k]] = k;
947 const int ro =
s->ro, go =
s->go, bo =
s->bo, ao =
s->ao, pixstep =
s->pixstep;
948 const int nc =
s->nc;
951 int ret, reduced = 0;
965 memset(
s->err[0], 0, (
w + 2) * nc *
sizeof(*
s->err[0]));
966 memset(
s->err[1], 0, (
w + 2) * nc *
sizeof(*
s->err[1]));
970 for (
int y = 0; y <
h; y++) {
972 uint32_t *ppos =
s->pixpos + (size_t)y *
w;
973 int f[4], px[4],
pos;
980 const int dir = (y & 1) ? -1 : 1;
981 const int x0 = dir > 0 ? 0 :
w - 1;
982 int32_t *err_cur =
s->err[ y & 1] + nc;
983 int32_t *err_next =
s->err[(y + 1) & 1] + nc;
985 memset(err_next - nc, 0, (
w + 2) * nc *
sizeof(*err_next));
987 for (
int k = 0; k <
w; k++) {
988 const int x = x0 + k * dir;
989 const int32_t *e = &err_cur[x * nc];
995 px[3] =
av_clip_uint8((ao >= 0 ?
src[x * pixstep + ao] : 255) + ((e[3] + 8) >> 4));
1005 for (
int i = 0;
i < nc;
i++) {
1006 const int qerr = px[
i] -
s->idx2val[
f[
i]];
1008 err_cur [(x + dir) * nc +
i] += qerr * 7;
1009 err_next[(x - dir) * nc +
i] += qerr * 3;
1010 err_next[ x * nc +
i] += qerr * 5;
1011 err_next[(x + dir) * nc +
i] += qerr;
1020 for (
int i = 0;
i < nc;
i++)
1021 dt[
i] = (blue ?
s->blue_dither[
i] :
s->ordered_dither[
i]) + rowoff;
1023 for (
int x = 0; x <
w; x++) {
1024 px[0] =
src[x * pixstep + ro] + dt[0][x &
mask];
1025 px[1] =
src[x * pixstep + go] + dt[1][x &
mask];
1026 px[2] =
src[x * pixstep + bo] + dt[2][x &
mask];
1028 px[3] = (ao >= 0 ?
src[x * pixstep + ao] : 255) + dt[3][x &
mask];
1039 for (
int x = 0; x <
w; x++) {
1040 px[0] =
src[x * pixstep + ro];
1041 px[1] =
src[x * pixstep + go];
1042 px[2] =
src[x * pixstep + bo];
1044 px[3] = ao >= 0 ?
src[x * pixstep + ao] : 255;
1057 reduced =
s->nb_used >
s->max_colors;
1066 "pts %"PRId64
": %d lattice colors used, %d dropped\n",
1067 in->
pts,
s->nb_used,
s->nb_used -
s->nb_alive);
1079 for (
int i = 0;
i <
s->nb_used;
i++) {
1088 if (!claimed[slot] &&
s->prev_pal[slot] ==
c) {
1095 for (
int i = 0;
i <
s->nb_used;
i++) {
1105 const uint32_t p =
s->prev_pal[slot];
1106 const int da = (int)(p >> 24 ) - (int)(
c >> 24 );
1107 const int dr = (int)(p >> 16 & 0xff) - (int)(
c >> 16 & 0xff);
1108 const int dg = (int)(p >> 8 & 0xff) - (int)(
c >> 8 & 0xff);
1109 const int db = (int)(p & 0xff) - (int)(
c & 0xff);
1110 const int64_t d2 = (
int64_t)da * da + dr * dr + dg * dg + db * db;
1112 if (!claimed[slot] && d2 < bd) {
1121 pal = (uint32_t *)
out->data[1];
1123 for (
int i = 0;
i <
s->nb_used;
i++) {
1132 for (
int i = 0;
i <
s->nb_used;
i++) {
1137 e->
nn =
s->list[e->
nn].nn;
1144 for (
int y = 0; y <
h; y++) {
1145 const uint32_t *ppos =
s->pixpos + (size_t)y *
w;
1146 uint8_t *
dst =
out->data[0] + y *
out->linesize[0];
1148 for (
int x = 0; x <
w; x++)
1149 dst[x] =
s->list[ppos[x]].nn;
1158 for (
int i = 0;
i <
s->nb_used;
i++)
1159 s->cell[
s->list[
i].pos] =
s->list[
i].nn + 1;
1165 for (
int i = 0;
i <
s->nb_used;
i++)
1166 s->cell[
s->list[
i].pos] =
s->list[
i].nn;
1167 for (
int y = 0; y <
h; y++) {
1168 const uint32_t *ppos =
s->pixpos + (size_t)y *
w;
1169 uint8_t *
dst =
out->data[0] + y *
out->linesize[0];
1171 for (
int x = 0; x <
w; x++)
1172 dst[x] =
s->cell[ppos[x]];
1177 for (
int i = 0;
i <
s->nb_used;
i++)
1178 s->cell[
s->list[
i].pos] = 0;
1179 for (
int i = 0;
i <
s->nb_touched;
i++)
1180 s->cell[
s->touched[
i]] = 0;
1187 for (
int i = 0;
i <
s->nb_used;
i++)
1188 s->cell[
s->list[
i].pos] = 0;
1189 for (
int i = 0;
i <
s->nb_touched;
i++)
1190 s->cell[
s->touched[
i]] = 0;
1202 const int N =
s->density;
1204 s->pixstep =
desc->comp[0].step;
1205 s->ro =
desc->comp[0].offset;
1206 s->go =
desc->comp[1].offset;
1207 s->bo =
desc->comp[2].offset;
1209 ?
desc->comp[3].offset : -1;
1210 s->nc =
s->alpha ? 4 : 3;
1214 "density is limited to %d when the alpha channel is quantized\n",
1219 s->scale =
N / 255.f;
1220 for (
int i = 0;
i <=
N;
i++)
1224 s->prev_pal[
i] = 0xFF000000;
1228 for (
int i = 1;
i <=
N;
i++)
1229 s->min_gap =
FFMIN(
s->min_gap,
s->idx2val[
i] -
s->idx2val[
i - 1]);
1232 s->cell =
av_calloc(
s->nc == 4 ? (
size_t)
s->dim *
s->dim *
s->dim *
s->dim
1233 : (
size_t)
s->dim *
s->dim *
s->dim,
1237 if (!
s->cell || !
s->pixpos)
1257 const float amp = 2.f * 255.f /
N;
1258 for (
int y = 0; y < 8; y++) {
1259 for (
int x = 0; x < 8; x++) {
1260 const int i = y << 3 | x;
1287 const float step = 255.f /
N;
1289 uint16_t *ranks[4] = {
NULL };
1302 ret = !
bits || !energy || !e1 ?
AVERROR(ENOMEM) : 0;
1304 for (
int p = 0; p <
s->nc && ret >= 0; p++) {
1308 if (!
s->blue_dither[p])
1310 if (!ranks[p] || !
s->blue_dither[p]) {
1320 const float a = (ranks[0][
i] + 0.5f) /
VC_AREA;
1321 const float b = (ranks[1][
i] + 0.5f) /
VC_AREA;
1322 const float c = (ranks[2][
i] + 0.5f) /
VC_AREA;
1324 s->blue_dither[0][
i] =
lrintf(step * (
a +
b - 1.f));
1325 s->blue_dither[1][
i] =
lrintf(step * (
a -
b));
1327 const float dd = (ranks[3][
i] + 0.5f) /
VC_AREA;
1329 s->blue_dither[2][
i] =
lrintf(step * (
c + dd - 1.f));
1330 s->blue_dither[3][
i] =
lrintf(step * (
c - dd));
1332 s->blue_dither[2][
i] =
lrintf(step * (2.f *
c - 1.f));
1348 for (
int i = 0;
i < 2;
i++) {
1365 for (
int i = 0;
i < 4;
i++)
1385 .p.name =
"latticepal",
1386 .p.description =
NULL_IF_CONFIG_SMALL(
"Convert RGB to PAL8 using a per-frame FCC lattice palette."),
1387 .p.priv_class = &latticepal_class,
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
static double val(void *priv, double ch)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static int config_input(AVFilterLink *inlink)
const FFFilter ff_vf_latticepal
static AVFormatContext * ctx
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
static __device__ float fabsf(float a)
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
static const uint8_t bits[8]
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
static const int16_t alpha[]
static av_cold void uninit(AVBitStreamFilterContext *ctx)
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
#define u(width, name, range_min, range_max)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
#define AVFILTER_DEFINE_CLASS(fname)
#define FILTER_QUERY_FUNC2(func)
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
static const uint16_t mask[17]
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
AVPixelFormat
Pixel format.
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Describe the class of an AVClass context structure.
A link between two filters.
int w
agreed upon image width
int h
agreed upon image height
AVFilterContext * dst
dest filter
int format
agreed upon media format
A filter pad used for either input or output.
This structure describes decoded (raw) audio or video data.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Context structure for the Lagged Fibonacci PRNG.
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
int64_t imp
impact of the removal when the entry was pushed
int idx
used color list index
int * alive_pos
position of each live color in alive_arr
int density
lattice steps per color axis
int32_t * err[2]
Floyd-Steinberg error rows, nc ints per pixel.
int ao
byte offsets of R, G, B, A in an input pixel, ao < 0: opaque
int * blue_dither[4]
per-channel blue noise offsets spanning one lattice period
int * touched
cells filled on demand by the refinement pass
uint8_t idx2val[MAX_DENSITY+1]
lattice index -> 8-bit component value
int nb_alive
entries in alive_arr, 0 outside reduction/remap
int alpha
quantize the alpha channel too (D4 lattice)
int nc
quantized components, 3 or 4
int ordered_dither[4][8 *8]
per-channel bayer offsets spanning one lattice period
int pixstep
bytes per input pixel
int refine
rediffuse the error of dropped colors
int max_colors
palette entries to use at most
int min_gap
smallest idx2val increment
uint32_t prev_pal[AVPALETTE_COUNT]
previous frame's palette, for stable slot assignment
int * alive_arr
compact list of live color indices while reducing
int32_t * cell
dim^nc table: lattice cell -> list index + 1, 0 if unused
uint32_t * pixpos
per-pixel cell position of the quantized color
PalEntry * list
colors used by the current frame
int dim
density + 1, lattice cells per axis
int nn
nearest live color while reducing, then palette slot
int pos
lattice cell position, ((i * dim + j) * dim + k) [* dim + l]
int d2
squared RGB(A) distance to nn
int64_t count
pixels quantizing to this color, incl. absorbed ones
uint8_t ci[4]
lattice indices of the color
uint8_t alive
still part of the palette while reducing
#define av_malloc_array(a, b)
static const uint16_t dither[8][8]
static void heap_push(HeapEnt *heap, int *nb, int64_t imp, int idx)
static const AVFilterPad latticepal_inputs[]
static int nearest_alive(LatticePalContext *s, const uint8_t ci[4], int self, int *out_d2)
Find the nearest live color of the used color list, excluding self (pass -1 to match any live color).
static void vc_generate(uint16_t *rank, uint8_t *bits, float *energy, float *e1, const float *kern, AVLFG *lfg)
Generate a void-and-cluster blue noise rank matrix (Ulichney 1993): every cell gets a unique rank in ...
#define CHECK_CELL3(a, b, c)
static int batch_assign(LatticePalContext *s, const AVFrame *in)
Rediffuse the whole frame against the current live colors and reassign every pixel,...
@ DITHERING_FLOYD_STEINBERG
static int refine_residual(LatticePalContext *s, AVFrame *out, const AVFrame *in)
Residual refinement pass: rediffuse only the error of the dropped colors, using the first pass quanti...
static void vc_splat(float *energy, const float *kern, int pos, float sign)
Add (sign > 0) or remove (sign < 0) the Gaussian energy contribution of a minority pixel at position ...
static int config_input(AVFilterLink *inlink)
static const AVOption latticepal_options[]
static const uint8_t dither_8x8_73[8][8]
static int refine_full(LatticePalContext *s, AVFrame *out, const AVFrame *in)
Full refinement pass: rediffuse the whole frame against the final palette.
static av_always_inline uint32_t entry_color(const LatticePalContext *s, const PalEntry *e)
Palette color (AARRGGBB) of a used color list entry.
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static void nn_search(LatticePalContext *s, int self)
static int vc_extreme(const float *energy, const uint8_t *bits, int want_set, int find_max)
Position of the extreme energy value among the cells whose bit equals want_set: the tightest cluster ...
static av_always_inline int color_inc(LatticePalContext *s, const int f[4])
Account one pixel using the lattice color with indices f, registering the color in the cell table and...
#define CHECK_CELL4(a, b, c, l)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static av_cold void uninit(AVFilterContext *ctx)
#define MAX_DENSITY_ALPHA
static int reduce_colors(LatticePalContext *s, int target)
Reduce the live colors down to target by repeatedly dropping the color whose removal has the least im...
static int reduce_batched(LatticePalContext *s, const AVFrame *in)
Batched reduction: instead of dropping all excess colors against the first pass statistics,...
static HeapEnt heap_pop(HeapEnt *heap, int *nb)
static av_always_inline void quant_dn(const LatticePalContext *s, const int *in, int f[4])
Quantize a color to the nearest point of the scaled D3 (FCC) or D4 lattice.
static double b1(void *priv, double x, double y)
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.