On Sun, Sep 26, 2021 at 12:43:37AM +0000, Soft Works wrote: > Usage example: > > ffmpeg -y -loglevel verbose -i "..\fate-suite\apng\o_sample.png" > -filter_complex > "split[split1][split2];[split1]palettegen=max_colors=254:use_alpha=1[pal1];[split2][pal1]paletteuse=use_alpha=1" > -frames:v 1 out.png > > Signed-off-by: softworkz <[email protected]> > --- > doc/filters.texi | 8 ++ > libavfilter/vf_palettegen.c | 140 ++++++++++++++-------- > libavfilter/vf_paletteuse.c | 225 +++++++++++++++++++++--------------- > 3 files changed, 233 insertions(+), 140 deletions(-) > > diff --git a/doc/filters.texi b/doc/filters.texi > index 36113e5c4b..7e4806235c 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -16454,6 +16454,9 @@ Compute new histogram for each frame. > @end table > > Default value is @var{full}. > +@item use_alpha > +Create a palette of colors with alpha components. > +Setting this, will automatically disable 'reserve_transparent'. > @end table > > The filter also exports the frame metadata @code{lavfi.color_quant_ratio} > @@ -16532,6 +16535,11 @@ will be treated as completely opaque, and values > below this threshold will be > treated as completely transparent. > > The option must be an integer value in the range [0,255]. Default is > @var{128}. > + > +@item use_alpha > +Apply the palette by taking alpha values into account. Only useful with > +palettes that are containing multiple colors with alpha components. > +Setting this will automatically disable 'alpha_treshold'. > @end table > > @subsection Examples > diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c > index 4c2fbd36d7..7a74a3752f 100644 > --- a/libavfilter/vf_palettegen.c > +++ b/libavfilter/vf_palettegen.c > @@ -59,7 +59,7 @@ enum { > }; > > #define NBITS 5 > -#define HIST_SIZE (1<<(3*NBITS)) > +#define HIST_SIZE (1<<(4*NBITS)) > > typedef struct PaletteGenContext { > const AVClass *class; > @@ -67,6 +67,7 @@ typedef struct PaletteGenContext { > int max_colors; > int reserve_transparent; > int stats_mode; > + int use_alpha; > > AVFrame *prev_frame; // previous frame used for the > diff stats_mode > struct hist_node histogram[HIST_SIZE]; // histogram/hashtable of the > colors > @@ -88,6 +89,7 @@ static const AVOption palettegen_options[] = { > { "full", "compute full frame histograms", 0, AV_OPT_TYPE_CONST, > {.i64=STATS_MODE_ALL_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" }, > { "diff", "compute histograms only for the part that differs from > previous frame", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_DIFF_FRAMES}, > INT_MIN, INT_MAX, FLAGS, "mode" }, > { "single", "compute new histogram for each frame", 0, > AV_OPT_TYPE_CONST, {.i64=STATS_MODE_SINGLE_FRAMES}, INT_MIN, INT_MAX, FLAGS, > "mode" }, > + { "use_alpha", "create a palette including alpha values", > OFFSET(use_alpha), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, > { NULL } > }; > > @@ -113,15 +115,16 @@ static int cmp_##name(const void *pa, const void *pb) > \ > { \ > const struct color_ref * const *a = pa; \ > const struct color_ref * const *b = pb; \ > - return (int)((*a)->color >> (8 * (2 - (pos))) & 0xff) \ > - - (int)((*b)->color >> (8 * (2 - (pos))) & 0xff); \ > + return (int)((*a)->color >> (8 * (3 - (pos))) & 0xff) \ > + - (int)((*b)->color >> (8 * (3 - (pos))) & 0xff); \ > } > > -DECLARE_CMP_FUNC(r, 0) > -DECLARE_CMP_FUNC(g, 1) > -DECLARE_CMP_FUNC(b, 2) > +DECLARE_CMP_FUNC(a, 0) > +DECLARE_CMP_FUNC(r, 1) > +DECLARE_CMP_FUNC(g, 2) > +DECLARE_CMP_FUNC(b, 3) > > -static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b}; > +static const cmp_func cmp_funcs[] = {cmp_a, cmp_r, cmp_g, cmp_b}; > > /** > * Simple color comparison for sorting the final palette > @@ -143,6 +146,17 @@ static av_always_inline int diff(const uint32_t a, const > uint32_t b) > return dr*dr + dg*dg + db*db; > } > > +static av_always_inline int diff_alpha(const uint32_t a, const uint32_t b) > +{ > + const uint8_t c1[] = {a >> 24 & 0xff, a >> 16 & 0xff, a >> 8 & 0xff, a & > 0xff}; > + const uint8_t c2[] = {b >> 24 & 0xff, b >> 16 & 0xff, b >> 8 & 0xff, b & > 0xff}; > + const int da = c1[0] - c2[0]; > + const int dr = c1[1] - c2[1]; > + const int dg = c1[2] - c2[2]; > + const int db = c1[3] - c2[3]; > + return da*da + dr*dr + dg*dg + db*db; > +} > + > /** > * Find the next box to split: pick the one with the highest variance > */ > @@ -164,7 +178,10 @@ static int get_next_box_id_to_split(PaletteGenContext *s) > > for (i = 0; i < box->len; i++) { > const struct color_ref *ref = s->refs[box->start + i]; > - variance += diff(ref->color, box->color) * ref->count; > + if (s->use_alpha) > + variance += (int64_t)diff_alpha(ref->color, > box->color) * ref->count; > + else > + variance += (int64_t)diff(ref->color, box->color) * > ref->count; > } > box->variance = variance; > } > @@ -184,24 +201,31 @@ static int get_next_box_id_to_split(PaletteGenContext > *s) > * specified box. Takes into account the weight of each color. > */ > static uint32_t get_avg_color(struct color_ref * const *refs, > - const struct range_box *box) > + const struct range_box *box, int use_alpha) > { > int i; > const int n = box->len; > - uint64_t r = 0, g = 0, b = 0, div = 0; > + uint64_t a = 0, r = 0, g = 0, b = 0, div = 0; > > for (i = 0; i < n; i++) { > const struct color_ref *ref = refs[box->start + i]; > - r += (ref->color >> 16 & 0xff) * ref->count; > - g += (ref->color >> 8 & 0xff) * ref->count; > - b += (ref->color & 0xff) * ref->count; > + if (use_alpha) > + a += (ref->color >> 24 & 0xff) * ref->count; > + r += (ref->color >> 16 & 0xff) * ref->count; > + g += (ref->color >> 8 & 0xff) * ref->count; > + b += (ref->color & 0xff) * ref->count; > div += ref->count; > } > > + if (use_alpha) > + a = a / div; > r = r / div; > g = g / div; > b = b / div; > > + if (use_alpha) > + return a<<24 | r<<16 | g<<8 | b; > + > return 0xffU<<24 | r<<16 | g<<8 | b; > } > > @@ -220,8 +244,8 @@ static void split_box(PaletteGenContext *s, struct > range_box *box, int n) > av_assert0(box->len >= 1); > av_assert0(new_box->len >= 1); > > - box->color = get_avg_color(s->refs, box); > - new_box->color = get_avg_color(s->refs, new_box); > + box->color = get_avg_color(s->refs, box, s->use_alpha); > + new_box->color = get_avg_color(s->refs, new_box, s->use_alpha); > box->variance = -1; > new_box->variance = -1; > }
> @@ -242,7 +266,7 @@ static void write_palette(AVFilterContext *ctx, AVFrame
> *out)
> if (box_id < s->nb_boxes) {
> pal[x] = s->boxes[box_id++].color;
> if ((x || y) && pal[x] == last_color)
> - av_log(ctx, AV_LOG_WARNING, "Dupped color:
> %08"PRIX32"\n", pal[x]);
> + av_log(ctx, AV_LOG_WARNING, "Duped color:
> %08"PRIX32"\n", pal[x]);
> last_color = pal[x];
> } else {
> pal[x] = last_color; // pad with last color
should be in a seperate patch, this is not related to alpha
[...]
> - return r<<(NBITS*2) | g<<NBITS | b;
> + return r << (NBITS * 2) | g << NBITS | b;
[...]
> - const int s = kd->split;
> + const int split = kd->split;
also unrelated to the alpha change
all these changes are ok but please do them in a seperate patch, that makes the
commits
easier to read in the future
thx
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Complexity theory is the science of finding the exact solution to an
approximation. Benchmarking OTOH is finding an approximation of the exact
signature.asc
Description: PGP signature
_______________________________________________ ffmpeg-devel mailing list [email protected] https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email [email protected] with subject "unsubscribe".
