Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(454)

Unified Diff: third_party/libwebp/enc/alpha.c

Issue 116213006: Update libwebp to 0.4.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: After Blink Roll Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/libwebp/dsp/yuv.c ('k') | third_party/libwebp/enc/analysis.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/libwebp/enc/alpha.c
diff --git a/third_party/libwebp/enc/alpha.c b/third_party/libwebp/enc/alpha.c
index e636c967237da33af76d9044f1d3255c39397e76..21d4b5cbde387b4f19151ff084960958d3869426 100644
--- a/third_party/libwebp/enc/alpha.c
+++ b/third_party/libwebp/enc/alpha.c
@@ -19,10 +19,6 @@
#include "../utils/quant_levels.h"
#include "../webp/format_constants.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
// -----------------------------------------------------------------------------
// Encodes the given alpha data via specified compression method 'method'.
// The pre-processing (quantization) is performed if 'quality' is less than 100.
@@ -71,7 +67,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
const uint8_t* src = data;
for (j = 0; j < picture.height; ++j) {
for (i = 0; i < picture.width; ++i) {
- dst[i] = (src[i] << 8) | 0xff000000u;
+ dst[i] = src[i] << 8; // we leave A/R/B channels zero'd.
}
src += width;
dst += picture.argb_stride;
@@ -81,8 +77,10 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
WebPConfigInit(&config);
config.lossless = 1;
config.method = effort_level; // impact is very small
- // Set a moderate default quality setting for alpha.
- config.quality = 10.f * effort_level;
+ // Set a low default quality for encoding alpha. Ensure that Alpha quality at
+ // lower methods (3 and below) is less than the threshold for triggering
+ // costly 'BackwardReferencesTraceBackwards'.
+ config.quality = 8.f * effort_level;
assert(config.quality >= 0 && config.quality <= 100.f);
ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3);
@@ -99,12 +97,19 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
// -----------------------------------------------------------------------------
+// Small struct to hold the result of a filter mode compression attempt.
+typedef struct {
+ size_t score;
+ VP8BitWriter bw;
+ WebPAuxStats stats;
+} FilterTrial;
+
+// This function always returns an initialized 'bw' object, even upon error.
static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
int method, int filter, int reduce_levels,
int effort_level, // in [0..6] range
uint8_t* const tmp_alpha,
- VP8BitWriter* const bw,
- WebPAuxStats* const stats) {
+ FilterTrial* result) {
int ok = 0;
const uint8_t* alpha_src;
WebPFilterFunc filter_func;
@@ -125,8 +130,8 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
header = method | (filter << 2);
if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
- VP8BitWriterInit(bw, expected_size);
- VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN);
+ VP8BitWriterInit(&result->bw, expected_size);
+ VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
filter_func = WebPFilters[filter];
if (filter_func != NULL) {
@@ -137,12 +142,14 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
}
if (method == ALPHA_NO_COMPRESSION) {
- ok = VP8BitWriterAppend(bw, alpha_src, width * height);
- ok = ok && !bw->error_;
+ ok = VP8BitWriterAppend(&result->bw, alpha_src, width * height);
+ ok = ok && !result->bw.error_;
} else {
- ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats);
- VP8BitWriterFinish(bw);
+ ok = EncodeLossless(alpha_src, width, height, effort_level,
+ &result->bw, &result->stats);
+ VP8BitWriterFinish(&result->bw);
}
+ result->score = VP8BitWriterSize(&result->bw);
return ok;
}
@@ -177,6 +184,85 @@ static int GetNumColors(const uint8_t* data, int width, int height,
return colors;
}
+#define FILTER_TRY_NONE (1 << WEBP_FILTER_NONE)
+#define FILTER_TRY_ALL ((1 << WEBP_FILTER_LAST) - 1)
+
+// Given the input 'filter' option, return an OR'd bit-set of filters to try.
+static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height,
+ int filter, int effort_level) {
+ uint32_t bit_map = 0U;
+ if (filter == WEBP_FILTER_FAST) {
+ // Quick estimate of the best candidate.
+ int try_filter_none = (effort_level > 3);
+ const int kMinColorsForFilterNone = 16;
+ const int kMaxColorsForFilterNone = 192;
+ const int num_colors = GetNumColors(alpha, width, height, width);
+ // For low number of colors, NONE yields better compression.
+ filter = (num_colors <= kMinColorsForFilterNone) ? WEBP_FILTER_NONE :
+ EstimateBestFilter(alpha, width, height, width);
+ bit_map |= 1 << filter;
+ // For large number of colors, try FILTER_NONE in addition to the best
+ // filter as well.
+ if (try_filter_none || num_colors > kMaxColorsForFilterNone) {
+ bit_map |= FILTER_TRY_NONE;
+ }
+ } else if (filter == WEBP_FILTER_NONE) {
+ bit_map = FILTER_TRY_NONE;
+ } else { // WEBP_FILTER_BEST -> try all
+ bit_map = FILTER_TRY_ALL;
+ }
+ return bit_map;
+}
+
+static void InitFilterTrial(FilterTrial* const score) {
+ score->score = (size_t)~0U;
+ VP8BitWriterInit(&score->bw, 0);
+}
+
+static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
+ size_t data_size, int method, int filter,
+ int reduce_levels, int effort_level,
+ uint8_t** const output,
+ size_t* const output_size,
+ WebPAuxStats* const stats) {
+ int ok = 1;
+ FilterTrial best;
+ uint32_t try_map =
+ GetFilterMap(alpha, width, height, filter, effort_level);
+ InitFilterTrial(&best);
+ if (try_map != FILTER_TRY_NONE) {
+ uint8_t* filtered_alpha = (uint8_t*)malloc(data_size);
+ if (filtered_alpha == NULL) return 0;
+
+ for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) {
+ if (try_map & 1) {
+ FilterTrial trial;
+ ok = EncodeAlphaInternal(alpha, width, height, method, filter,
+ reduce_levels, effort_level, filtered_alpha,
+ &trial);
+ if (ok && trial.score < best.score) {
+ VP8BitWriterWipeOut(&best.bw);
+ best = trial;
+ } else {
+ VP8BitWriterWipeOut(&trial.bw);
+ }
+ }
+ }
+ free(filtered_alpha);
+ } else {
+ ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
+ reduce_levels, effort_level, NULL, &best);
+ }
+ if (ok) {
+ if (stats != NULL) *stats = best.stats;
+ *output_size = VP8BitWriterSize(&best.bw);
+ *output = VP8BitWriterBuf(&best.bw);
+ } else {
+ VP8BitWriterWipeOut(&best.bw);
+ }
+ return ok;
+}
+
static int EncodeAlpha(VP8Encoder* const enc,
int quality, int method, int filter,
int effort_level,
@@ -207,6 +293,11 @@ static int EncodeAlpha(VP8Encoder* const enc,
return 0;
}
+ if (method == ALPHA_NO_COMPRESSION) {
+ // Don't filter, as filtering will make no impact on compressed size.
+ filter = WEBP_FILTER_NONE;
+ }
+
quant_alpha = (uint8_t*)malloc(data_size);
if (quant_alpha == NULL) {
return 0;
@@ -225,105 +316,19 @@ static int EncodeAlpha(VP8Encoder* const enc,
}
if (ok) {
- VP8BitWriter bw;
- int test_filter;
- uint8_t* filtered_alpha = NULL;
- int try_filter_none = (effort_level > 3);
-
- if (filter == WEBP_FILTER_FAST) { // Quick estimate of the best candidate.
- const int kMinColorsForFilterNone = 16;
- const int kMaxColorsForFilterNone = 192;
- const int num_colors = GetNumColors(quant_alpha, width, height, width);
- // For low number of colors, NONE yeilds better compression.
- filter = (num_colors <= kMinColorsForFilterNone) ? WEBP_FILTER_NONE :
- EstimateBestFilter(quant_alpha, width, height, width);
- // For large number of colors, try FILTER_NONE in addition to the best
- // filter as well.
- if (num_colors > kMaxColorsForFilterNone) {
- try_filter_none = 1;
- }
- }
-
- // Test for WEBP_FILTER_NONE for higher effort levels.
- if (try_filter_none || filter == WEBP_FILTER_NONE) {
- ok = EncodeAlphaInternal(quant_alpha, width, height,
- method, WEBP_FILTER_NONE, reduce_levels,
- effort_level, NULL, &bw, pic->stats);
-
- if (!ok) {
- VP8BitWriterWipeOut(&bw);
- goto End;
- }
- }
- // Stop?
- if (filter == WEBP_FILTER_NONE) {
- goto Ok;
- }
-
- filtered_alpha = (uint8_t*)malloc(data_size);
- ok = (filtered_alpha != NULL);
- if (!ok) {
- goto End;
+ ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method,
+ filter, reduce_levels, effort_level, output,
+ output_size, pic->stats);
+ if (pic->stats != NULL) { // need stats?
+ pic->stats->coded_size += (int)(*output_size);
+ enc->sse_[3] = sse;
}
-
- // Try the other mode(s).
- {
- WebPAuxStats best_stats;
- size_t best_score = try_filter_none ?
- VP8BitWriterSize(&bw) : (size_t)~0U;
- int wipe_tmp_bw = try_filter_none;
-
- memset(&best_stats, 0, sizeof(best_stats)); // prevent spurious warning
- if (pic->stats != NULL) best_stats = *pic->stats;
- for (test_filter =
- try_filter_none ? WEBP_FILTER_HORIZONTAL : WEBP_FILTER_NONE;
- ok && (test_filter <= WEBP_FILTER_GRADIENT);
- ++test_filter) {
- VP8BitWriter tmp_bw;
- if (filter != WEBP_FILTER_BEST && test_filter != filter) {
- continue;
- }
- ok = EncodeAlphaInternal(quant_alpha, width, height,
- method, test_filter, reduce_levels,
- effort_level, filtered_alpha, &tmp_bw,
- pic->stats);
- if (ok) {
- const size_t score = VP8BitWriterSize(&tmp_bw);
- if (score < best_score) {
- // swap bitwriter objects.
- VP8BitWriter tmp = tmp_bw;
- tmp_bw = bw;
- bw = tmp;
- best_score = score;
- if (pic->stats != NULL) best_stats = *pic->stats;
- }
- } else {
- VP8BitWriterWipeOut(&bw);
- }
- if (wipe_tmp_bw) {
- VP8BitWriterWipeOut(&tmp_bw);
- }
- wipe_tmp_bw = 1; // For next filter trial for WEBP_FILTER_BEST.
- }
- if (pic->stats != NULL) *pic->stats = best_stats;
- }
- Ok:
- if (ok) {
- *output_size = VP8BitWriterSize(&bw);
- *output = VP8BitWriterBuf(&bw);
- if (pic->stats != NULL) { // need stats?
- pic->stats->coded_size += (int)(*output_size);
- enc->sse_[3] = sse;
- }
- }
- free(filtered_alpha);
}
- End:
+
free(quant_alpha);
return ok;
}
-
//------------------------------------------------------------------------------
// Main calls
@@ -403,6 +408,3 @@ int VP8EncDeleteAlpha(VP8Encoder* const enc) {
return ok;
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
« no previous file with comments | « third_party/libwebp/dsp/yuv.c ('k') | third_party/libwebp/enc/analysis.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698