mirror of
https://github.com/webmproject/libwebp.git
synced 2025-04-11 11:26:47 +02:00
modulate alpha-compression effort according to config.method
we vary linearly lossless-method between 0 and 6, and lossless-quality between 50 and 100, so that encoding speed can go from 'quite fast' to 'rather slow'. Impact on size is moderate, but visible. Change-Id: I0b7917e7170eb50258afb1a4e248028cd9e9207d
This commit is contained in:
parent
f5f2fff657
commit
18da1f53fc
@ -28,7 +28,7 @@ extern "C" {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// int EncodeAlpha(const uint8_t* data, int width, int height, int stride,
|
// int EncodeAlpha(const uint8_t* data, int width, int height, int stride,
|
||||||
// int quality, int method, int filter,
|
// int quality, int method, int filter, int effort_level,
|
||||||
// uint8_t** output, size_t* output_size)
|
// uint8_t** output, size_t* output_size)
|
||||||
//
|
//
|
||||||
// Encodes the given alpha data 'data' of size 'stride'x'height' via specified
|
// Encodes the given alpha data 'data' of size 'stride'x'height' via specified
|
||||||
@ -40,7 +40,9 @@ extern "C" {
|
|||||||
// 'filter' values [0, 4] correspond to prediction modes none, horizontal,
|
// 'filter' values [0, 4] correspond to prediction modes none, horizontal,
|
||||||
// vertical & gradient filters. The prediction mode 4 will try all the
|
// vertical & gradient filters. The prediction mode 4 will try all the
|
||||||
// prediction modes (0 to 3) and pick the best prediction mode.
|
// prediction modes (0 to 3) and pick the best prediction mode.
|
||||||
|
// 'effort_level': specifies how much effort must be spent to try and reduce
|
||||||
|
// the compressed output size. In range 0 (quick) to 6 (slow).
|
||||||
|
//
|
||||||
// 'output' corresponds to the buffer containing compressed alpha data.
|
// 'output' corresponds to the buffer containing compressed alpha data.
|
||||||
// This buffer is allocated by this method and caller should call
|
// This buffer is allocated by this method and caller should call
|
||||||
// free(*output) when done.
|
// free(*output) when done.
|
||||||
@ -56,6 +58,7 @@ extern "C" {
|
|||||||
#include "../enc/vp8li.h"
|
#include "../enc/vp8li.h"
|
||||||
|
|
||||||
static int EncodeLossless(const uint8_t* data, int width, int height,
|
static int EncodeLossless(const uint8_t* data, int width, int height,
|
||||||
|
int effort_level, // in [0..6] range
|
||||||
VP8BitWriter* const bw) {
|
VP8BitWriter* const bw) {
|
||||||
|
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
@ -85,8 +88,10 @@ static int EncodeLossless(const uint8_t* data, int width, int height,
|
|||||||
|
|
||||||
WebPConfigInit(&config);
|
WebPConfigInit(&config);
|
||||||
config.lossless = 1;
|
config.lossless = 1;
|
||||||
config.method = 2;
|
config.method = effort_level; // impact is very small
|
||||||
config.quality = 100; // TODO(skal): make it adjustable.
|
// quality below 50 doesn't change things much (in speed and size).
|
||||||
|
// quality above 80 can be very very slow.
|
||||||
|
config.quality = 40 + 10 * effort_level;
|
||||||
|
|
||||||
VP8LBitWriterInit(&tmp_bw, (width * height) >> 3);
|
VP8LBitWriterInit(&tmp_bw, (width * height) >> 3);
|
||||||
ok = (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK);
|
ok = (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK);
|
||||||
@ -106,6 +111,7 @@ static int EncodeLossless(const uint8_t* data, int width, int height,
|
|||||||
|
|
||||||
static int EncodeAlphaInternal(const uint8_t* data, int width, int height,
|
static int EncodeAlphaInternal(const uint8_t* 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
|
||||||
uint8_t* tmp_alpha, VP8BitWriter* const bw) {
|
uint8_t* tmp_alpha, VP8BitWriter* const bw) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
const uint8_t* alpha_src;
|
const uint8_t* alpha_src;
|
||||||
@ -145,9 +151,10 @@ static int EncodeAlphaInternal(const uint8_t* data, int width, int height,
|
|||||||
ok = ok && !bw->error_;
|
ok = ok && !bw->error_;
|
||||||
} else {
|
} else {
|
||||||
#ifdef USE_LOSSLESS_ENCODER
|
#ifdef USE_LOSSLESS_ENCODER
|
||||||
ok = EncodeLossless(alpha_src, width, height, bw);
|
ok = EncodeLossless(alpha_src, width, height, effort_level, bw);
|
||||||
VP8BitWriterFinish(bw);
|
VP8BitWriterFinish(bw);
|
||||||
#else
|
#else
|
||||||
|
(void)effort_level;
|
||||||
assert(0); // not reached.
|
assert(0); // not reached.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -168,6 +175,7 @@ static void CopyPlane(const uint8_t* src, int src_stride,
|
|||||||
|
|
||||||
static int EncodeAlpha(const uint8_t* data, int width, int height, int stride,
|
static int EncodeAlpha(const uint8_t* data, int width, int height, int stride,
|
||||||
int quality, int method, int filter,
|
int quality, int method, int filter,
|
||||||
|
int effort_level,
|
||||||
uint8_t** output, size_t* output_size) {
|
uint8_t** output, size_t* output_size) {
|
||||||
uint8_t* quant_alpha = NULL;
|
uint8_t* quant_alpha = NULL;
|
||||||
const size_t data_size = width * height;
|
const size_t data_size = width * height;
|
||||||
@ -214,7 +222,7 @@ static int EncodeAlpha(const uint8_t* data, int width, int height, int stride,
|
|||||||
// We always test WEBP_FILTER_NONE first.
|
// We always test WEBP_FILTER_NONE first.
|
||||||
ok = EncodeAlphaInternal(quant_alpha, width, height,
|
ok = EncodeAlphaInternal(quant_alpha, width, height,
|
||||||
method, WEBP_FILTER_NONE, reduce_levels,
|
method, WEBP_FILTER_NONE, reduce_levels,
|
||||||
NULL, &bw);
|
effort_level, NULL, &bw);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
VP8BitWriterWipeOut(&bw);
|
VP8BitWriterWipeOut(&bw);
|
||||||
goto End;
|
goto End;
|
||||||
@ -246,7 +254,7 @@ static int EncodeAlpha(const uint8_t* data, int width, int height, int stride,
|
|||||||
|
|
||||||
ok = EncodeAlphaInternal(quant_alpha, width, height,
|
ok = EncodeAlphaInternal(quant_alpha, width, height,
|
||||||
method, test_filter, reduce_levels,
|
method, test_filter, reduce_levels,
|
||||||
filtered_alpha, &tmp_bw);
|
effort_level, filtered_alpha, &tmp_bw);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
const size_t score = VP8BitWriterSize(&tmp_bw);
|
const size_t score = VP8BitWriterSize(&tmp_bw);
|
||||||
if (score < best_score) {
|
if (score < best_score) {
|
||||||
@ -289,6 +297,7 @@ int VP8EncFinishAlpha(VP8Encoder* enc) {
|
|||||||
const WebPPicture* pic = enc->pic_;
|
const WebPPicture* pic = enc->pic_;
|
||||||
uint8_t* tmp_data = NULL;
|
uint8_t* tmp_data = NULL;
|
||||||
size_t tmp_size = 0;
|
size_t tmp_size = 0;
|
||||||
|
const int effort_level = config->method; // maps to [0..6]
|
||||||
const WEBP_FILTER_TYPE filter =
|
const WEBP_FILTER_TYPE filter =
|
||||||
(config->alpha_filtering == 0) ? WEBP_FILTER_NONE :
|
(config->alpha_filtering == 0) ? WEBP_FILTER_NONE :
|
||||||
(config->alpha_filtering == 1) ? WEBP_FILTER_FAST :
|
(config->alpha_filtering == 1) ? WEBP_FILTER_FAST :
|
||||||
@ -297,7 +306,7 @@ int VP8EncFinishAlpha(VP8Encoder* enc) {
|
|||||||
assert(pic->a);
|
assert(pic->a);
|
||||||
if (!EncodeAlpha(pic->a, pic->width, pic->height, pic->a_stride,
|
if (!EncodeAlpha(pic->a, pic->width, pic->height, pic->a_stride,
|
||||||
config->alpha_quality, config->alpha_compression,
|
config->alpha_quality, config->alpha_compression,
|
||||||
filter, &tmp_data, &tmp_size)) {
|
filter, effort_level, &tmp_data, &tmp_size)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (tmp_size != (uint32_t)tmp_size) { // Sanity check.
|
if (tmp_size != (uint32_t)tmp_size) { // Sanity check.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user