remove a malloc() in case we're using only FILTER_NONE for alpha

+ some revamp and cleanup of the alpha-filter trial loop
+ EncodeAlphaInternal() now just takes a FilterTrial param

Change-Id: Ief84385083b1cba02678bbcd3dbf707245ee962f
This commit is contained in:
Pascal Massimino 2013-06-24 02:03:01 -07:00
parent d1c166ef3f
commit 2c07143b9d

View File

@ -99,13 +99,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. // This function always returns an initialized 'bw' object, even upon error.
static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
int method, int filter, int reduce_levels, int method, int filter, int reduce_levels,
int effort_level, // in [0..6] range int effort_level, // in [0..6] range
uint8_t* const tmp_alpha, uint8_t* const tmp_alpha,
VP8BitWriter* const bw, FilterTrial* result) {
WebPAuxStats* const stats) {
int ok = 0; int ok = 0;
const uint8_t* alpha_src; const uint8_t* alpha_src;
WebPFilterFunc filter_func; WebPFilterFunc filter_func;
@ -126,8 +132,8 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
header = method | (filter << 2); header = method | (filter << 2);
if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
VP8BitWriterInit(bw, expected_size); VP8BitWriterInit(&result->bw, expected_size);
VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN); VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
filter_func = WebPFilters[filter]; filter_func = WebPFilters[filter];
if (filter_func != NULL) { if (filter_func != NULL) {
@ -138,12 +144,14 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
} }
if (method == ALPHA_NO_COMPRESSION) { if (method == ALPHA_NO_COMPRESSION) {
ok = VP8BitWriterAppend(bw, alpha_src, width * height); ok = VP8BitWriterAppend(&result->bw, alpha_src, width * height);
ok = ok && !bw->error_; ok = ok && !result->bw.error_;
} else { } else {
ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats); ok = EncodeLossless(alpha_src, width, height, effort_level,
VP8BitWriterFinish(bw); &result->bw, &result->stats);
VP8BitWriterFinish(&result->bw);
} }
result->score = VP8BitWriterSize(&result->bw);
return ok; return ok;
} }
@ -178,6 +186,9 @@ static int GetNumColors(const uint8_t* data, int width, int height,
return colors; 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. // 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, static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height,
int filter, int effort_level) { int filter, int effort_level) {
@ -195,23 +206,16 @@ static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height,
// 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.
if (try_filter_none || num_colors > kMaxColorsForFilterNone) { if (try_filter_none || num_colors > kMaxColorsForFilterNone) {
bit_map |= 1 << WEBP_FILTER_NONE; bit_map |= FILTER_TRY_NONE;
} }
} else if (filter == WEBP_FILTER_NONE) { } else if (filter == WEBP_FILTER_NONE) {
bit_map = 1 << WEBP_FILTER_NONE; bit_map = FILTER_TRY_NONE;
} else { // WEBP_FILTER_BEST } else { // WEBP_FILTER_BEST -> try all
bit_map = (1 << WEBP_FILTER_LAST) - 1; // try all. bit_map = FILTER_TRY_ALL;
} }
return bit_map; return bit_map;
} }
// Small struct to hold the result of a filter mode compression attempt.
typedef struct {
size_t score;
VP8BitWriter bw;
WebPAuxStats stats;
} FilterTrial;
static void InitFilterTrial(FilterTrial* const score) { static void InitFilterTrial(FilterTrial* const score) {
score->score = (size_t)~0U; score->score = (size_t)~0U;
VP8BitWriterInit(&score->bw, 0); VP8BitWriterInit(&score->bw, 0);
@ -224,48 +228,39 @@ static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
size_t* const output_size, size_t* const output_size,
WebPAuxStats* const stats) { WebPAuxStats* const stats) {
int ok = 1; int ok = 1;
uint8_t* filtered_alpha = NULL; FilterTrial best;
uint32_t try_map = uint32_t try_map =
GetFilterMap(alpha, width, height, filter, effort_level); GetFilterMap(alpha, width, height, filter, effort_level);
// TODO(urvang): In case of no filtering, this malloc is unnecessary. Also,
// the whole loop below should be avoided in that case.
filtered_alpha = (uint8_t*)malloc(data_size);
ok = (filtered_alpha != NULL);
if (ok) {
FilterTrial best;
InitFilterTrial(&best); 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; try_map; ++filter, try_map >>= 1) { for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) {
if (try_map & 1) { if (try_map & 1) {
FilterTrial trial; FilterTrial trial;
ok = EncodeAlphaInternal(alpha, width, height, method, filter, ok = EncodeAlphaInternal(alpha, width, height, method, filter,
reduce_levels, effort_level, filtered_alpha, reduce_levels, effort_level, filtered_alpha,
&trial.bw, stats); &trial);
if (ok) { if (ok && trial.score < best.score) {
trial.score = VP8BitWriterSize(&trial.bw);
if (trial.score < best.score) {
VP8BitWriterWipeOut(&best.bw); VP8BitWriterWipeOut(&best.bw);
best = trial; best = trial;
if (stats != NULL) best.stats = *stats;
} else { } else {
VP8BitWriterWipeOut(&trial.bw); VP8BitWriterWipeOut(&trial.bw);
} }
}
}
free(filtered_alpha);
} else { } else {
VP8BitWriterWipeOut(&trial.bw); ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
VP8BitWriterWipeOut(&best.bw); reduce_levels, effort_level, NULL, &best);
break;
} }
}
}
if (ok) { if (ok) {
if (stats != NULL) *stats = best.stats; if (stats != NULL) *stats = best.stats;
*output_size = VP8BitWriterSize(&best.bw); *output_size = VP8BitWriterSize(&best.bw);
*output = VP8BitWriterBuf(&best.bw); *output = VP8BitWriterBuf(&best.bw);
} } else {
free(filtered_alpha); VP8BitWriterWipeOut(&best.bw);
} }
return ok; return ok;
} }