mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 02:15:42 +01:00 
			
		
		
		
	Alpha coding: reorganize the filter/unfiltering code
Move the filtering code to their own dsp/ spot New function: VP8FiltersInit() Change-Id: I0b2041eab42346c59b972f2575b05509e6a8f7b1
This commit is contained in:
		| @@ -51,6 +51,7 @@ LOCAL_SRC_FILES := \ | |||||||
|     src/dsp/enc_mips_dsp_r2.c \ |     src/dsp/enc_mips_dsp_r2.c \ | ||||||
|     src/dsp/enc_neon.$(NEON) \ |     src/dsp/enc_neon.$(NEON) \ | ||||||
|     src/dsp/enc_sse2.c \ |     src/dsp/enc_sse2.c \ | ||||||
|  |     src/dsp/filters.c \ | ||||||
|     src/dsp/filters_mips_dsp_r2.c \ |     src/dsp/filters_mips_dsp_r2.c \ | ||||||
|     src/dsp/lossless.c \ |     src/dsp/lossless.c \ | ||||||
|     src/dsp/lossless_mips32.c \ |     src/dsp/lossless_mips32.c \ | ||||||
|   | |||||||
| @@ -195,6 +195,7 @@ DSP_DEC_OBJS = \ | |||||||
|     $(DIROBJ)\dsp\dec_mips_dsp_r2.obj \ |     $(DIROBJ)\dsp\dec_mips_dsp_r2.obj \ | ||||||
|     $(DIROBJ)\dsp\dec_neon.obj \ |     $(DIROBJ)\dsp\dec_neon.obj \ | ||||||
|     $(DIROBJ)\dsp\dec_sse2.obj \ |     $(DIROBJ)\dsp\dec_sse2.obj \ | ||||||
|  |     $(DIROBJ)\dsp\filters.obj \ | ||||||
|     $(DIROBJ)\dsp\filters_mips_dsp_r2.obj \ |     $(DIROBJ)\dsp\filters_mips_dsp_r2.obj \ | ||||||
|     $(DIROBJ)\dsp\lossless.obj \ |     $(DIROBJ)\dsp\lossless.obj \ | ||||||
|     $(DIROBJ)\dsp\lossless_mips32.obj \ |     $(DIROBJ)\dsp\lossless_mips32.obj \ | ||||||
|   | |||||||
| @@ -119,6 +119,7 @@ DSP_DEC_OBJS = \ | |||||||
|     src/dsp/dec_mips_dsp_r2.o \ |     src/dsp/dec_mips_dsp_r2.o \ | ||||||
|     src/dsp/dec_neon.o \ |     src/dsp/dec_neon.o \ | ||||||
|     src/dsp/dec_sse2.o \ |     src/dsp/dec_sse2.o \ | ||||||
|  |     src/dsp/filters.o \ | ||||||
|     src/dsp/filters_mips_dsp_r2.o \ |     src/dsp/filters_mips_dsp_r2.o \ | ||||||
|     src/dsp/lossless.o \ |     src/dsp/lossless.o \ | ||||||
|     src/dsp/lossless_mips32.o \ |     src/dsp/lossless_mips32.o \ | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
| #include "./alphai.h" | #include "./alphai.h" | ||||||
| #include "./vp8i.h" | #include "./vp8i.h" | ||||||
| #include "./vp8li.h" | #include "./vp8li.h" | ||||||
|  | #include "../dsp/dsp.h" | ||||||
| #include "../utils/quant_levels_dec.h" | #include "../utils/quant_levels_dec.h" | ||||||
| #include "../utils/utils.h" | #include "../utils/utils.h" | ||||||
| #include "../webp/format_constants.h" | #include "../webp/format_constants.h" | ||||||
| @@ -78,6 +79,7 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, | |||||||
|     assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION); |     assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION); | ||||||
|     ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size, output); |     ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size, output); | ||||||
|   } |   } | ||||||
|  |   VP8FiltersInit(); | ||||||
|   return ok; |   return ok; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ COMMON_SOURCES += dec_mips32.c | |||||||
| COMMON_SOURCES += dec_mips_dsp_r2.c | COMMON_SOURCES += dec_mips_dsp_r2.c | ||||||
| COMMON_SOURCES += dec_neon.c | COMMON_SOURCES += dec_neon.c | ||||||
| COMMON_SOURCES += dsp.h | COMMON_SOURCES += dsp.h | ||||||
|  | COMMON_SOURCES += filters.c | ||||||
| COMMON_SOURCES += filters_mips_dsp_r2.c | COMMON_SOURCES += filters_mips_dsp_r2.c | ||||||
| COMMON_SOURCES += lossless.c | COMMON_SOURCES += lossless.c | ||||||
| COMMON_SOURCES += lossless.h | COMMON_SOURCES += lossless.h | ||||||
|   | |||||||
| @@ -343,7 +343,6 @@ int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int); | |||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| // Init function | // Init function | ||||||
|  |  | ||||||
| extern void VP8FiltersInitMIPSdspR2(void); |  | ||||||
| extern void WebPInitAlphaProcessingMIPSdspR2(void); | extern void WebPInitAlphaProcessingMIPSdspR2(void); | ||||||
| extern void WebPInitAlphaProcessingSSE2(void); | extern void WebPInitAlphaProcessingSSE2(void); | ||||||
|  |  | ||||||
| @@ -370,7 +369,6 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) { | |||||||
| #endif | #endif | ||||||
| #if defined(WEBP_USE_MIPS_DSP_R2) | #if defined(WEBP_USE_MIPS_DSP_R2) | ||||||
|     if (VP8GetCPUInfo(kMIPSdspR2)) { |     if (VP8GetCPUInfo(kMIPSdspR2)) { | ||||||
|       VP8FiltersInitMIPSdspR2(); |  | ||||||
|       WebPInitAlphaProcessingMIPSdspR2(); |       WebPInitAlphaProcessingMIPSdspR2(); | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -373,6 +373,39 @@ extern void (*VP8PackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b, | |||||||
| // To be called first before using the above. | // To be called first before using the above. | ||||||
| WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspARGBInit(void); | WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspARGBInit(void); | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | // Filter functions | ||||||
|  |  | ||||||
|  | typedef enum {     // Filter types. | ||||||
|  |   WEBP_FILTER_NONE = 0, | ||||||
|  |   WEBP_FILTER_HORIZONTAL, | ||||||
|  |   WEBP_FILTER_VERTICAL, | ||||||
|  |   WEBP_FILTER_GRADIENT, | ||||||
|  |   WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1,  // end marker | ||||||
|  |   WEBP_FILTER_BEST,    // meta-types | ||||||
|  |   WEBP_FILTER_FAST | ||||||
|  | } WEBP_FILTER_TYPE; | ||||||
|  |  | ||||||
|  | typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, | ||||||
|  |                                int stride, uint8_t* out); | ||||||
|  | typedef void (*WebPUnfilterFunc)(int width, int height, int stride, | ||||||
|  |                                  int row, int num_rows, uint8_t* data); | ||||||
|  |  | ||||||
|  | // Filter the given data using the given predictor. | ||||||
|  | // 'in' corresponds to a 2-dimensional pixel array of size (stride * height) | ||||||
|  | // in raster order. | ||||||
|  | // 'stride' is number of bytes per scan line (with possible padding). | ||||||
|  | // 'out' should be pre-allocated. | ||||||
|  | extern WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; | ||||||
|  |  | ||||||
|  | // In-place reconstruct the original data from the given filtered data. | ||||||
|  | // The reconstruction will be done for 'num_rows' rows starting from 'row' | ||||||
|  | // (assuming rows upto 'row - 1' are already reconstructed). | ||||||
|  | extern WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST]; | ||||||
|  |  | ||||||
|  | // To be called first before using the above. | ||||||
|  | WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void); | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| }    // extern "C" | }    // extern "C" | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										234
									
								
								src/dsp/filters.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								src/dsp/filters.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,234 @@ | |||||||
|  | // Copyright 2011 Google Inc. All Rights Reserved. | ||||||
|  | // | ||||||
|  | // Use of this source code is governed by a BSD-style license | ||||||
|  | // that can be found in the COPYING file in the root of the source | ||||||
|  | // tree. An additional intellectual property rights grant can be found | ||||||
|  | // in the file PATENTS. All contributing project authors may | ||||||
|  | // be found in the AUTHORS file in the root of the source tree. | ||||||
|  | // ----------------------------------------------------------------------------- | ||||||
|  | // | ||||||
|  | // Spatial prediction using various filters | ||||||
|  | // | ||||||
|  | // Author: Urvang (urvang@google.com) | ||||||
|  |  | ||||||
|  | #include "./dsp.h" | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | // Helpful macro. | ||||||
|  |  | ||||||
|  | # define SANITY_CHECK(in, out)                                                 \ | ||||||
|  |   assert(in != NULL);                                                          \ | ||||||
|  |   assert(out != NULL);                                                         \ | ||||||
|  |   assert(width > 0);                                                           \ | ||||||
|  |   assert(height > 0);                                                          \ | ||||||
|  |   assert(stride >= width);                                                     \ | ||||||
|  |   assert(row >= 0 && num_rows > 0 && row + num_rows <= height);                \ | ||||||
|  |   (void)height;  // Silence unused warning. | ||||||
|  |  | ||||||
|  | static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, | ||||||
|  |                                     uint8_t* dst, int length, int inverse) { | ||||||
|  |   int i; | ||||||
|  |   if (inverse) { | ||||||
|  |     for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i]; | ||||||
|  |   } else { | ||||||
|  |     for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | // Horizontal filter. | ||||||
|  |  | ||||||
|  | static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, | ||||||
|  |                                            int width, int height, int stride, | ||||||
|  |                                            int row, int num_rows, | ||||||
|  |                                            int inverse, uint8_t* out) { | ||||||
|  |   const uint8_t* preds; | ||||||
|  |   const size_t start_offset = row * stride; | ||||||
|  |   const int last_row = row + num_rows; | ||||||
|  |   SANITY_CHECK(in, out); | ||||||
|  |   in += start_offset; | ||||||
|  |   out += start_offset; | ||||||
|  |   preds = inverse ? out : in; | ||||||
|  |  | ||||||
|  |   if (row == 0) { | ||||||
|  |     // Leftmost pixel is the same as input for topmost scanline. | ||||||
|  |     out[0] = in[0]; | ||||||
|  |     PredictLine(in + 1, preds, out + 1, width - 1, inverse); | ||||||
|  |     row = 1; | ||||||
|  |     preds += stride; | ||||||
|  |     in += stride; | ||||||
|  |     out += stride; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Filter line-by-line. | ||||||
|  |   while (row < last_row) { | ||||||
|  |     // Leftmost pixel is predicted from above. | ||||||
|  |     PredictLine(in, preds - stride, out, 1, inverse); | ||||||
|  |     PredictLine(in + 1, preds, out + 1, width - 1, inverse); | ||||||
|  |     ++row; | ||||||
|  |     preds += stride; | ||||||
|  |     in += stride; | ||||||
|  |     out += stride; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | // Vertical filter. | ||||||
|  |  | ||||||
|  | static WEBP_INLINE void DoVerticalFilter(const uint8_t* in, | ||||||
|  |                                          int width, int height, int stride, | ||||||
|  |                                          int row, int num_rows, | ||||||
|  |                                          int inverse, uint8_t* out) { | ||||||
|  |   const uint8_t* preds; | ||||||
|  |   const size_t start_offset = row * stride; | ||||||
|  |   const int last_row = row + num_rows; | ||||||
|  |   SANITY_CHECK(in, out); | ||||||
|  |   in += start_offset; | ||||||
|  |   out += start_offset; | ||||||
|  |   preds = inverse ? out : in; | ||||||
|  |  | ||||||
|  |   if (row == 0) { | ||||||
|  |     // Very first top-left pixel is copied. | ||||||
|  |     out[0] = in[0]; | ||||||
|  |     // Rest of top scan-line is left-predicted. | ||||||
|  |     PredictLine(in + 1, preds, out + 1, width - 1, inverse); | ||||||
|  |     row = 1; | ||||||
|  |     in += stride; | ||||||
|  |     out += stride; | ||||||
|  |   } else { | ||||||
|  |     // We are starting from in-between. Make sure 'preds' points to prev row. | ||||||
|  |     preds -= stride; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Filter line-by-line. | ||||||
|  |   while (row < last_row) { | ||||||
|  |     PredictLine(in, preds, out, width, inverse); | ||||||
|  |     ++row; | ||||||
|  |     preds += stride; | ||||||
|  |     in += stride; | ||||||
|  |     out += stride; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | // Gradient filter. | ||||||
|  |  | ||||||
|  | static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { | ||||||
|  |   const int g = a + b - c; | ||||||
|  |   return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255;  // clip to 8bit | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static WEBP_INLINE void DoGradientFilter(const uint8_t* in, | ||||||
|  |                                          int width, int height, int stride, | ||||||
|  |                                          int row, int num_rows, | ||||||
|  |                                          int inverse, uint8_t* out) { | ||||||
|  |   const uint8_t* preds; | ||||||
|  |   const size_t start_offset = row * stride; | ||||||
|  |   const int last_row = row + num_rows; | ||||||
|  |   SANITY_CHECK(in, out); | ||||||
|  |   in += start_offset; | ||||||
|  |   out += start_offset; | ||||||
|  |   preds = inverse ? out : in; | ||||||
|  |  | ||||||
|  |   // left prediction for top scan-line | ||||||
|  |   if (row == 0) { | ||||||
|  |     out[0] = in[0]; | ||||||
|  |     PredictLine(in + 1, preds, out + 1, width - 1, inverse); | ||||||
|  |     row = 1; | ||||||
|  |     preds += stride; | ||||||
|  |     in += stride; | ||||||
|  |     out += stride; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Filter line-by-line. | ||||||
|  |   while (row < last_row) { | ||||||
|  |     int w; | ||||||
|  |     // leftmost pixel: predict from above. | ||||||
|  |     PredictLine(in, preds - stride, out, 1, inverse); | ||||||
|  |     for (w = 1; w < width; ++w) { | ||||||
|  |       const int pred = GradientPredictor(preds[w - 1], | ||||||
|  |                                          preds[w - stride], | ||||||
|  |                                          preds[w - stride - 1]); | ||||||
|  |       out[w] = in[w] + (inverse ? pred : -pred); | ||||||
|  |     } | ||||||
|  |     ++row; | ||||||
|  |     preds += stride; | ||||||
|  |     in += stride; | ||||||
|  |     out += stride; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #undef SANITY_CHECK | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | static void HorizontalFilter(const uint8_t* data, int width, int height, | ||||||
|  |                              int stride, uint8_t* filtered_data) { | ||||||
|  |   DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void VerticalFilter(const uint8_t* data, int width, int height, | ||||||
|  |                            int stride, uint8_t* filtered_data) { | ||||||
|  |   DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void GradientFilter(const uint8_t* data, int width, int height, | ||||||
|  |                            int stride, uint8_t* filtered_data) { | ||||||
|  |   DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | static void VerticalUnfilter(int width, int height, int stride, int row, | ||||||
|  |                              int num_rows, uint8_t* data) { | ||||||
|  |   DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void HorizontalUnfilter(int width, int height, int stride, int row, | ||||||
|  |                                int num_rows, uint8_t* data) { | ||||||
|  |   DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void GradientUnfilter(int width, int height, int stride, int row, | ||||||
|  |                              int num_rows, uint8_t* data) { | ||||||
|  |   DoGradientFilter(data, width, height, stride, row, num_rows, 1, data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | // Init function | ||||||
|  |  | ||||||
|  | WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; | ||||||
|  | WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST]; | ||||||
|  |  | ||||||
|  | extern void VP8FiltersInitMIPSdspR2(void); | ||||||
|  |  | ||||||
|  | static volatile VP8CPUInfo filters_last_cpuinfo_used = | ||||||
|  |     (VP8CPUInfo)&filters_last_cpuinfo_used; | ||||||
|  |  | ||||||
|  | WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) { | ||||||
|  |   if (filters_last_cpuinfo_used == VP8GetCPUInfo) return; | ||||||
|  |  | ||||||
|  |   WebPUnfilters[WEBP_FILTER_NONE] = NULL; | ||||||
|  |   WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter; | ||||||
|  |   WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter; | ||||||
|  |   WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter; | ||||||
|  |  | ||||||
|  |   WebPFilters[WEBP_FILTER_NONE] = NULL; | ||||||
|  |   WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter; | ||||||
|  |   WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter; | ||||||
|  |   WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter; | ||||||
|  |  | ||||||
|  |   if (VP8GetCPUInfo != NULL) { | ||||||
|  | #if defined(WEBP_USE_MIPS_DSP_R2) | ||||||
|  |     if (VP8GetCPUInfo(kMIPSdspR2)) { | ||||||
|  |       VP8FiltersInitMIPSdspR2(); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |   } | ||||||
|  |   filters_last_cpuinfo_used = VP8GetCPUInfo; | ||||||
|  | } | ||||||
| @@ -16,7 +16,7 @@ | |||||||
|  |  | ||||||
| #if defined(WEBP_USE_MIPS_DSP_R2) | #if defined(WEBP_USE_MIPS_DSP_R2) | ||||||
|  |  | ||||||
| #include "../utils/filters.h" | #include "../dsp/dsp.h" | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  |  | ||||||
| #include "./vp8enci.h" | #include "./vp8enci.h" | ||||||
|  | #include "../dsp/dsp.h" | ||||||
| #include "../utils/filters.h" | #include "../utils/filters.h" | ||||||
| #include "../utils/quant_levels.h" | #include "../utils/quant_levels.h" | ||||||
| #include "../utils/utils.h" | #include "../utils/utils.h" | ||||||
| @@ -208,8 +209,9 @@ static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height, | |||||||
|     const int kMaxColorsForFilterNone = 192; |     const int kMaxColorsForFilterNone = 192; | ||||||
|     const int num_colors = GetNumColors(alpha, width, height, width); |     const int num_colors = GetNumColors(alpha, width, height, width); | ||||||
|     // For low number of colors, NONE yields better compression. |     // For low number of colors, NONE yields better compression. | ||||||
|     filter = (num_colors <= kMinColorsForFilterNone) ? WEBP_FILTER_NONE : |     filter = (num_colors <= kMinColorsForFilterNone) | ||||||
|              EstimateBestFilter(alpha, width, height, width); |         ? WEBP_FILTER_NONE | ||||||
|  |         : WebPEstimateBestFilter(alpha, width, height, width); | ||||||
|     bit_map |= 1 << filter; |     bit_map |= 1 << filter; | ||||||
|     // For large number of colors, try FILTER_NONE in addition to the best |     // For large number of colors, try FILTER_NONE in addition to the best | ||||||
|     // filter as well. |     // filter as well. | ||||||
| @@ -240,6 +242,7 @@ static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height, | |||||||
|   uint32_t try_map = |   uint32_t try_map = | ||||||
|       GetFilterMap(alpha, width, height, filter, effort_level); |       GetFilterMap(alpha, width, height, filter, effort_level); | ||||||
|   InitFilterTrial(&best); |   InitFilterTrial(&best); | ||||||
|  |  | ||||||
|   if (try_map != FILTER_TRY_NONE) { |   if (try_map != FILTER_TRY_NONE) { | ||||||
|     uint8_t* filtered_alpha =  (uint8_t*)WebPSafeMalloc(1ULL, data_size); |     uint8_t* filtered_alpha =  (uint8_t*)WebPSafeMalloc(1ULL, data_size); | ||||||
|     if (filtered_alpha == NULL) return 0; |     if (filtered_alpha == NULL) return 0; | ||||||
| @@ -326,6 +329,7 @@ static int EncodeAlpha(VP8Encoder* const enc, | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (ok) { |   if (ok) { | ||||||
|  |     VP8FiltersInit(); | ||||||
|     ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method, |     ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method, | ||||||
|                                filter, reduce_levels, effort_level, output, |                                filter, reduce_levels, effort_level, output, | ||||||
|                                output_size, pic->stats); |                                output_size, pic->stats); | ||||||
|   | |||||||
| @@ -7,199 +7,26 @@ | |||||||
| // be found in the AUTHORS file in the root of the source tree. | // be found in the AUTHORS file in the root of the source tree. | ||||||
| // ----------------------------------------------------------------------------- | // ----------------------------------------------------------------------------- | ||||||
| // | // | ||||||
| // Spatial prediction using various filters | // filter estimation | ||||||
| // | // | ||||||
| // Author: Urvang (urvang@google.com) | // Author: Urvang (urvang@google.com) | ||||||
|  |  | ||||||
| #include "./filters.h" | #include "./filters.h" | ||||||
| #include <assert.h> |  | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| // Helpful macro. |  | ||||||
|  |  | ||||||
| # define SANITY_CHECK(in, out)                                                 \ |  | ||||||
|   assert(in != NULL);                                                          \ |  | ||||||
|   assert(out != NULL);                                                         \ |  | ||||||
|   assert(width > 0);                                                           \ |  | ||||||
|   assert(height > 0);                                                          \ |  | ||||||
|   assert(stride >= width);                                                     \ |  | ||||||
|   assert(row >= 0 && num_rows > 0 && row + num_rows <= height);                \ |  | ||||||
|   (void)height;  // Silence unused warning. |  | ||||||
|  |  | ||||||
| static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, |  | ||||||
|                                     uint8_t* dst, int length, int inverse) { |  | ||||||
|   int i; |  | ||||||
|   if (inverse) { |  | ||||||
|     for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i]; |  | ||||||
|   } else { |  | ||||||
|     for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i]; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| // Horizontal filter. |  | ||||||
|  |  | ||||||
| static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, |  | ||||||
|                                            int width, int height, int stride, |  | ||||||
|                                            int row, int num_rows, |  | ||||||
|                                            int inverse, uint8_t* out) { |  | ||||||
|   const uint8_t* preds; |  | ||||||
|   const size_t start_offset = row * stride; |  | ||||||
|   const int last_row = row + num_rows; |  | ||||||
|   SANITY_CHECK(in, out); |  | ||||||
|   in += start_offset; |  | ||||||
|   out += start_offset; |  | ||||||
|   preds = inverse ? out : in; |  | ||||||
|  |  | ||||||
|   if (row == 0) { |  | ||||||
|     // Leftmost pixel is the same as input for topmost scanline. |  | ||||||
|     out[0] = in[0]; |  | ||||||
|     PredictLine(in + 1, preds, out + 1, width - 1, inverse); |  | ||||||
|     row = 1; |  | ||||||
|     preds += stride; |  | ||||||
|     in += stride; |  | ||||||
|     out += stride; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Filter line-by-line. |  | ||||||
|   while (row < last_row) { |  | ||||||
|     // Leftmost pixel is predicted from above. |  | ||||||
|     PredictLine(in, preds - stride, out, 1, inverse); |  | ||||||
|     PredictLine(in + 1, preds, out + 1, width - 1, inverse); |  | ||||||
|     ++row; |  | ||||||
|     preds += stride; |  | ||||||
|     in += stride; |  | ||||||
|     out += stride; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void HorizontalFilter(const uint8_t* data, int width, int height, |  | ||||||
|                              int stride, uint8_t* filtered_data) { |  | ||||||
|   DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void HorizontalUnfilter(int width, int height, int stride, int row, |  | ||||||
|                                int num_rows, uint8_t* data) { |  | ||||||
|   DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| // Vertical filter. |  | ||||||
|  |  | ||||||
| static WEBP_INLINE void DoVerticalFilter(const uint8_t* in, |  | ||||||
|                                          int width, int height, int stride, |  | ||||||
|                                          int row, int num_rows, |  | ||||||
|                                          int inverse, uint8_t* out) { |  | ||||||
|   const uint8_t* preds; |  | ||||||
|   const size_t start_offset = row * stride; |  | ||||||
|   const int last_row = row + num_rows; |  | ||||||
|   SANITY_CHECK(in, out); |  | ||||||
|   in += start_offset; |  | ||||||
|   out += start_offset; |  | ||||||
|   preds = inverse ? out : in; |  | ||||||
|  |  | ||||||
|   if (row == 0) { |  | ||||||
|     // Very first top-left pixel is copied. |  | ||||||
|     out[0] = in[0]; |  | ||||||
|     // Rest of top scan-line is left-predicted. |  | ||||||
|     PredictLine(in + 1, preds, out + 1, width - 1, inverse); |  | ||||||
|     row = 1; |  | ||||||
|     in += stride; |  | ||||||
|     out += stride; |  | ||||||
|   } else { |  | ||||||
|     // We are starting from in-between. Make sure 'preds' points to prev row. |  | ||||||
|     preds -= stride; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Filter line-by-line. |  | ||||||
|   while (row < last_row) { |  | ||||||
|     PredictLine(in, preds, out, width, inverse); |  | ||||||
|     ++row; |  | ||||||
|     preds += stride; |  | ||||||
|     in += stride; |  | ||||||
|     out += stride; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void VerticalFilter(const uint8_t* data, int width, int height, |  | ||||||
|                            int stride, uint8_t* filtered_data) { |  | ||||||
|   DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void VerticalUnfilter(int width, int height, int stride, int row, |  | ||||||
|                              int num_rows, uint8_t* data) { |  | ||||||
|   DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| // Gradient filter. |  | ||||||
|  |  | ||||||
| static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { |  | ||||||
|   const int g = a + b - c; |  | ||||||
|   return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255;  // clip to 8bit |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static WEBP_INLINE void DoGradientFilter(const uint8_t* in, |  | ||||||
|                                          int width, int height, int stride, |  | ||||||
|                                          int row, int num_rows, |  | ||||||
|                                          int inverse, uint8_t* out) { |  | ||||||
|   const uint8_t* preds; |  | ||||||
|   const size_t start_offset = row * stride; |  | ||||||
|   const int last_row = row + num_rows; |  | ||||||
|   SANITY_CHECK(in, out); |  | ||||||
|   in += start_offset; |  | ||||||
|   out += start_offset; |  | ||||||
|   preds = inverse ? out : in; |  | ||||||
|  |  | ||||||
|   // left prediction for top scan-line |  | ||||||
|   if (row == 0) { |  | ||||||
|     out[0] = in[0]; |  | ||||||
|     PredictLine(in + 1, preds, out + 1, width - 1, inverse); |  | ||||||
|     row = 1; |  | ||||||
|     preds += stride; |  | ||||||
|     in += stride; |  | ||||||
|     out += stride; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Filter line-by-line. |  | ||||||
|   while (row < last_row) { |  | ||||||
|     int w; |  | ||||||
|     // leftmost pixel: predict from above. |  | ||||||
|     PredictLine(in, preds - stride, out, 1, inverse); |  | ||||||
|     for (w = 1; w < width; ++w) { |  | ||||||
|       const int pred = GradientPredictor(preds[w - 1], |  | ||||||
|                                          preds[w - stride], |  | ||||||
|                                          preds[w - stride - 1]); |  | ||||||
|       out[w] = in[w] + (inverse ? pred : -pred); |  | ||||||
|     } |  | ||||||
|     ++row; |  | ||||||
|     preds += stride; |  | ||||||
|     in += stride; |  | ||||||
|     out += stride; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void GradientFilter(const uint8_t* data, int width, int height, |  | ||||||
|                            int stride, uint8_t* filtered_data) { |  | ||||||
|   DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void GradientUnfilter(int width, int height, int stride, int row, |  | ||||||
|                              int num_rows, uint8_t* data) { |  | ||||||
|   DoGradientFilter(data, width, height, stride, row, num_rows, 1, data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #undef SANITY_CHECK |  | ||||||
|  |  | ||||||
| // ----------------------------------------------------------------------------- | // ----------------------------------------------------------------------------- | ||||||
| // Quick estimate of a potentially interesting filter mode to try. | // Quick estimate of a potentially interesting filter mode to try. | ||||||
|  |  | ||||||
| #define SMAX 16 | #define SMAX 16 | ||||||
| #define SDIFF(a, b) (abs((a) - (b)) >> 4)   // Scoring diff, in [0..SMAX) | #define SDIFF(a, b) (abs((a) - (b)) >> 4)   // Scoring diff, in [0..SMAX) | ||||||
|  |  | ||||||
| WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data, | static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { | ||||||
|  |   const int g = a + b - c; | ||||||
|  |   return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255;  // clip to 8bit | ||||||
|  | } | ||||||
|  |  | ||||||
|  | WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data, | ||||||
|                                         int width, int height, int stride) { |                                         int width, int height, int stride) { | ||||||
|   int i, j; |   int i, j; | ||||||
|   int bins[WEBP_FILTER_LAST][SMAX]; |   int bins[WEBP_FILTER_LAST][SMAX]; | ||||||
| @@ -247,20 +74,3 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data, | |||||||
| #undef SDIFF | #undef SDIFF | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
| WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = { |  | ||||||
|   NULL,              // WEBP_FILTER_NONE |  | ||||||
|   HorizontalFilter,  // WEBP_FILTER_HORIZONTAL |  | ||||||
|   VerticalFilter,    // WEBP_FILTER_VERTICAL |  | ||||||
|   GradientFilter     // WEBP_FILTER_GRADIENT |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST] = { |  | ||||||
|   NULL,                // WEBP_FILTER_NONE |  | ||||||
|   HorizontalUnfilter,  // WEBP_FILTER_HORIZONTAL |  | ||||||
|   VerticalUnfilter,    // WEBP_FILTER_VERTICAL |  | ||||||
|   GradientUnfilter     // WEBP_FILTER_GRADIENT |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,41 +15,14 @@ | |||||||
| #define WEBP_UTILS_FILTERS_H_ | #define WEBP_UTILS_FILTERS_H_ | ||||||
|  |  | ||||||
| #include "../webp/types.h" | #include "../webp/types.h" | ||||||
|  | #include "../dsp/dsp.h" | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // Filters. |  | ||||||
| typedef enum { |  | ||||||
|   WEBP_FILTER_NONE = 0, |  | ||||||
|   WEBP_FILTER_HORIZONTAL, |  | ||||||
|   WEBP_FILTER_VERTICAL, |  | ||||||
|   WEBP_FILTER_GRADIENT, |  | ||||||
|   WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1,  // end marker |  | ||||||
|   WEBP_FILTER_BEST, |  | ||||||
|   WEBP_FILTER_FAST |  | ||||||
| } WEBP_FILTER_TYPE; |  | ||||||
|  |  | ||||||
| typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, |  | ||||||
|                                int stride, uint8_t* out); |  | ||||||
| typedef void (*WebPUnfilterFunc)(int width, int height, int stride, |  | ||||||
|                                  int row, int num_rows, uint8_t* data); |  | ||||||
|  |  | ||||||
| // Filter the given data using the given predictor. |  | ||||||
| // 'in' corresponds to a 2-dimensional pixel array of size (stride * height) |  | ||||||
| // in raster order. |  | ||||||
| // 'stride' is number of bytes per scan line (with possible padding). |  | ||||||
| // 'out' should be pre-allocated. |  | ||||||
| extern WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; |  | ||||||
|  |  | ||||||
| // In-place reconstruct the original data from the given filtered data. |  | ||||||
| // The reconstruction will be done for 'num_rows' rows starting from 'row' |  | ||||||
| // (assuming rows upto 'row - 1' are already reconstructed). |  | ||||||
| extern WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST]; |  | ||||||
|  |  | ||||||
| // Fast estimate of a potentially good filter. | // Fast estimate of a potentially good filter. | ||||||
| WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data, | WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data, | ||||||
|                                         int width, int height, int stride); |                                         int width, int height, int stride); | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user