diff options
Diffstat (limited to 'gst/dvbsubenc/libimagequant/viter.c')
-rw-r--r-- | gst/dvbsubenc/libimagequant/viter.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/gst/dvbsubenc/libimagequant/viter.c b/gst/dvbsubenc/libimagequant/viter.c new file mode 100644 index 000000000..489f3657c --- /dev/null +++ b/gst/dvbsubenc/libimagequant/viter.c @@ -0,0 +1,111 @@ + +#include "libimagequant.h" +#include "pam.h" +#include "viter.h" +#include "nearest.h" +#include <stdlib.h> +#include <string.h> + +#ifdef _OPENMP +#include <omp.h> +#else +#define omp_get_max_threads() 1 +#define omp_get_thread_num() 0 +#endif + +/* + * Voronoi iteration: new palette color is computed from weighted average of colors that map to that palette entry. + */ +LIQ_PRIVATE void +viter_init (const colormap * map, const unsigned int max_threads, + viter_state average_color[]) +{ + memset (average_color, 0, + sizeof (average_color[0]) * (VITER_CACHE_LINE_GAP + + map->colors) * max_threads); +} + +LIQ_PRIVATE void +viter_update_color (const f_pixel acolor, const float value, + const colormap * map, unsigned int match, const unsigned int thread, + viter_state average_color[]) +{ + match += thread * (VITER_CACHE_LINE_GAP + map->colors); + average_color[match].a += acolor.a * value; + average_color[match].r += acolor.r * value; + average_color[match].g += acolor.g * value; + average_color[match].b += acolor.b * value; + average_color[match].total += value; +} + +LIQ_PRIVATE void +viter_finalize (colormap * map, const unsigned int max_threads, + const viter_state average_color[]) +{ + for (unsigned int i = 0; i < map->colors; i++) { + double a = 0, r = 0, g = 0, b = 0, total = 0; + + // Aggregate results from all threads + for (unsigned int t = 0; t < max_threads; t++) { + const unsigned int offset = (VITER_CACHE_LINE_GAP + map->colors) * t + i; + + a += average_color[offset].a; + r += average_color[offset].r; + g += average_color[offset].g; + b += average_color[offset].b; + total += average_color[offset].total; + } + + if (total && !map->palette[i].fixed) { + map->palette[i].acolor = (f_pixel) { + .a = a / total,.r = r / total,.g = g / total,.b = b / total,}; + } else { + total = i / 1024.0; + } + map->palette[i].popularity = total; + } +} + +LIQ_PRIVATE double +viter_do_iteration (histogram * hist, colormap * const map, + const float min_opaque_val, viter_callback callback, + const bool fast_palette) +{ + viter_state *average_color; + const unsigned int max_threads = omp_get_max_threads (); + double total_diff = 0; + + average_color = + g_alloca (sizeof (viter_state) * (VITER_CACHE_LINE_GAP + + map->colors) * max_threads); + + viter_init (map, max_threads, average_color); + { + struct nearest_map *const n = nearest_init (map, fast_palette); + hist_item *const achv = hist->achv; + const int hist_size = hist->size; + int j; + +#pragma omp parallel for if (hist_size > 3000) \ + schedule(static) default(none) shared(average_color,callback) reduction(+:total_diff) + for (j = 0; j < hist_size; j++) { + float diff; + unsigned int match = + nearest_search (n, achv[j].acolor, achv[j].tmp.likely_colormap_index, + min_opaque_val, &diff); + achv[j].tmp.likely_colormap_index = match; + total_diff += diff * achv[j].perceptual_weight; + + viter_update_color (achv[j].acolor, achv[j].perceptual_weight, map, match, + omp_get_thread_num (), average_color); + + if (callback) + callback (&achv[j], diff); + } + + nearest_free (n); + } + viter_finalize (map, max_threads, average_color); + + return total_diff / hist->total_perceptual_weight; +} |