add a fallback to ALPHA_NO_COMPRESSION

if ALPHA_LOSSLESS_COMPRESSION produces a too big file (very rare!),
we fall-back to no-compression automatically.

Change-Id: I5f3f509c635ce43a5e7c23f5d0f0c8329a5f24b7
This commit is contained in:
skal 2014-09-02 21:55:13 +02:00
parent a6140194ff
commit 187d379db6

View File

@ -47,12 +47,11 @@
static int EncodeLossless(const uint8_t* const data, int width, int height, static int EncodeLossless(const uint8_t* const data, int width, int height,
int effort_level, // in [0..6] range int effort_level, // in [0..6] range
VP8BitWriter* const bw, VP8LBitWriter* const bw,
WebPAuxStats* const stats) { WebPAuxStats* const stats) {
int ok = 0; int ok = 0;
WebPConfig config; WebPConfig config;
WebPPicture picture; WebPPicture picture;
VP8LBitWriter tmp_bw;
WebPPictureInit(&picture); WebPPictureInit(&picture);
picture.width = width; picture.width = width;
@ -84,16 +83,15 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
config.quality = 8.f * effort_level; config.quality = 8.f * effort_level;
assert(config.quality >= 0 && config.quality <= 100.f); assert(config.quality >= 0 && config.quality <= 100.f);
ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3); ok = (VP8LEncodeStream(&config, &picture, bw) == VP8_ENC_OK);
ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK);
WebPPictureFree(&picture); WebPPictureFree(&picture);
if (ok) { ok = ok && !bw->error_;
const uint8_t* const buffer = VP8LBitWriterFinish(&tmp_bw); if (!ok) {
const size_t buffer_size = VP8LBitWriterNumBytes(&tmp_bw); VP8LBitWriterDestroy(bw);
VP8BitWriterAppend(bw, buffer, buffer_size); return 0;
} }
VP8LBitWriterDestroy(&tmp_bw); return 1;
return ok && !bw->error_;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -115,8 +113,10 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
const uint8_t* alpha_src; const uint8_t* alpha_src;
WebPFilterFunc filter_func; WebPFilterFunc filter_func;
uint8_t header; uint8_t header;
size_t expected_size;
const size_t data_size = width * height; const size_t data_size = width * height;
const uint8_t* output = NULL;
size_t output_size = 0;
VP8LBitWriter tmp_bw;
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
assert(filter >= 0 && filter < WEBP_FILTER_LAST); assert(filter >= 0 && filter < WEBP_FILTER_LAST);
@ -125,15 +125,6 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
assert(sizeof(header) == ALPHA_HEADER_LEN); assert(sizeof(header) == ALPHA_HEADER_LEN);
// TODO(skal): have a common function and #define's to validate alpha params. // TODO(skal): have a common function and #define's to validate alpha params.
expected_size =
(method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size)
: (data_size >> 5);
header = method | (filter << 2);
if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
VP8BitWriterInit(&result->bw, expected_size);
VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
filter_func = WebPFilters[filter]; filter_func = WebPFilters[filter];
if (filter_func != NULL) { if (filter_func != NULL) {
filter_func(data, width, height, width, tmp_alpha); filter_func(data, width, height, width, tmp_alpha);
@ -142,14 +133,42 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
alpha_src = data; alpha_src = data;
} }
if (method == ALPHA_NO_COMPRESSION) { if (method != ALPHA_NO_COMPRESSION) {
ok = VP8BitWriterAppend(&result->bw, alpha_src, width * height); ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3);
ok = ok && !result->bw.error_; ok = ok && EncodeLossless(alpha_src, width, height, effort_level,
} else { &tmp_bw, &result->stats);
ok = EncodeLossless(alpha_src, width, height, effort_level, if (ok) {
&result->bw, &result->stats); output = VP8LBitWriterFinish(&tmp_bw);
VP8BitWriterFinish(&result->bw); output_size = VP8LBitWriterNumBytes(&tmp_bw);
if (output_size > data_size) {
// compressed size is larger than source! Revert to uncompressed mode.
method = ALPHA_NO_COMPRESSION;
VP8LBitWriterDestroy(&tmp_bw);
}
} else {
VP8LBitWriterDestroy(&tmp_bw);
return 0;
}
} }
if (method == ALPHA_NO_COMPRESSION) {
output = alpha_src;
output_size = data_size;
ok = 1;
}
// Emit final result.
header = method | (filter << 2);
if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size);
ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
ok = ok && VP8BitWriterAppend(&result->bw, output, output_size);
if (method != ALPHA_NO_COMPRESSION) {
VP8LBitWriterDestroy(&tmp_bw);
}
ok = ok && !result->bw.error_;
result->score = VP8BitWriterSize(&result->bw); result->score = VP8BitWriterSize(&result->bw);
return ok; return ok;
} }