mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
write an ad-hoc EncodeImageInternal variant
Used when we don't code a Huffman Image. -> Simplify the code quite some because we don't have to deal with special cases of histo bits Change-Id: I0c3f46cbf3b501e021c093e07253e7404c01ff4f
This commit is contained in:
parent
eaee9e79f7
commit
3697b5ceb2
@ -40,17 +40,22 @@ static void HistogramClear(VP8LHistogram* const p) {
|
||||
p->bit_cost_ = 0;
|
||||
}
|
||||
|
||||
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
|
||||
VP8LHistogram* const histo) {
|
||||
int i;
|
||||
for (i = 0; i < refs->size; ++i) {
|
||||
VP8LHistogramAddSinglePixOrCopy(histo, &refs->refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void VP8LHistogramCreate(VP8LHistogram* const p,
|
||||
const VP8LBackwardRefs* const refs,
|
||||
int palette_code_bits) {
|
||||
int i;
|
||||
if (palette_code_bits >= 0) {
|
||||
p->palette_code_bits_ = palette_code_bits;
|
||||
}
|
||||
HistogramClear(p);
|
||||
for (i = 0; i < refs->size; ++i) {
|
||||
VP8LHistogramAddSinglePixOrCopy(p, &refs->refs[i]);
|
||||
}
|
||||
VP8LHistogramStoreRefs(refs, p);
|
||||
}
|
||||
|
||||
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) {
|
||||
@ -112,24 +117,24 @@ void VP8LConvertPopulationCountTableToBitEstimates(
|
||||
}
|
||||
}
|
||||
|
||||
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const p,
|
||||
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
|
||||
const PixOrCopy* const v) {
|
||||
if (PixOrCopyIsLiteral(v)) {
|
||||
++p->alpha_[PixOrCopyLiteral(v, 3)];
|
||||
++p->red_[PixOrCopyLiteral(v, 2)];
|
||||
++p->literal_[PixOrCopyLiteral(v, 1)];
|
||||
++p->blue_[PixOrCopyLiteral(v, 0)];
|
||||
++histo->alpha_[PixOrCopyLiteral(v, 3)];
|
||||
++histo->red_[PixOrCopyLiteral(v, 2)];
|
||||
++histo->literal_[PixOrCopyLiteral(v, 1)];
|
||||
++histo->blue_[PixOrCopyLiteral(v, 0)];
|
||||
} else if (PixOrCopyIsCacheIdx(v)) {
|
||||
int literal_ix = 256 + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
|
||||
++p->literal_[literal_ix];
|
||||
++histo->literal_[literal_ix];
|
||||
} else {
|
||||
int code, extra_bits_count, extra_bits_value;
|
||||
PrefixEncode(PixOrCopyLength(v),
|
||||
&code, &extra_bits_count, &extra_bits_value);
|
||||
++p->literal_[256 + code];
|
||||
++histo->literal_[256 + code];
|
||||
PrefixEncode(PixOrCopyDistance(v),
|
||||
&code, &extra_bits_count, &extra_bits_value);
|
||||
++p->distance_[code];
|
||||
++histo->distance_[code];
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,11 +191,11 @@ static double BitsEntropy(const int* const array, int n) {
|
||||
}
|
||||
|
||||
double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
|
||||
double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p)) +
|
||||
BitsEntropy(&p->red_[0], 256) +
|
||||
BitsEntropy(&p->blue_[0], 256) +
|
||||
BitsEntropy(&p->alpha_[0], 256) +
|
||||
BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES);
|
||||
double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p))
|
||||
+ BitsEntropy(&p->red_[0], 256)
|
||||
+ BitsEntropy(&p->blue_[0], 256)
|
||||
+ BitsEntropy(&p->alpha_[0], 256)
|
||||
+ BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES);
|
||||
// Compute the extra bits cost.
|
||||
int i;
|
||||
for (i = 2; i < NUM_LENGTH_CODES - 2; ++i) {
|
||||
@ -259,14 +264,13 @@ static void HistogramBuildImage(int xsize, int histo_bits,
|
||||
VP8LHistogramSet* const image) {
|
||||
int i;
|
||||
int x = 0, y = 0;
|
||||
const int histo_xsize =
|
||||
(histo_bits > 0) ? VP8LSubSampleSize(xsize, histo_bits) : 1;
|
||||
const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
|
||||
VP8LHistogram** const histograms = image->histograms;
|
||||
assert(histo_bits > 0);
|
||||
for (i = 0; i < backward_refs->size; ++i) {
|
||||
const PixOrCopy* const v = &backward_refs->refs[i];
|
||||
const int ix =
|
||||
(histo_bits > 0) ? (y >> histo_bits) * histo_xsize + (x >> histo_bits)
|
||||
: 0;
|
||||
VP8LHistogramAddSinglePixOrCopy(image->histograms[ix], v);
|
||||
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
|
||||
VP8LHistogramAddSinglePixOrCopy(histograms[ix], v);
|
||||
x += PixOrCopyLength(v);
|
||||
while (x >= xsize) {
|
||||
x -= xsize;
|
||||
|
@ -62,11 +62,16 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
|
||||
// Set the palette_code_bits and reset the stats.
|
||||
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
|
||||
|
||||
// Collect all the references into a histogram (without reset)
|
||||
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
|
||||
VP8LHistogram* const histo);
|
||||
|
||||
// Allocate an array of pointer to histograms, allocated and initialized
|
||||
// using 'cache_bits'. Return NULL in case of memory error.
|
||||
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
|
||||
|
||||
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const p,
|
||||
// Accumulate a token 'v' into a histogram.
|
||||
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
|
||||
const PixOrCopy* const v);
|
||||
|
||||
// Estimate how many bits the combined entropy of literals and distance
|
||||
|
@ -33,10 +33,6 @@ extern "C" {
|
||||
#define MIN_HISTO_BITS 2
|
||||
#define MAX_HISTO_BITS 9
|
||||
|
||||
// NO_HISTO_BITS needs to be large enough so that all bits in the image
|
||||
// size are thrown away by shifting.
|
||||
#define NO_HISTO_BITS (VP8L_IMAGE_SIZE_BITS + 1)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Palette
|
||||
|
||||
@ -440,6 +436,54 @@ static void StoreImageToBitMask(
|
||||
}
|
||||
}
|
||||
|
||||
// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
|
||||
static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
|
||||
const uint32_t* const argb,
|
||||
int width, int height, int quality) {
|
||||
int i;
|
||||
int ok = 0;
|
||||
VP8LBackwardRefs refs;
|
||||
HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
|
||||
const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
|
||||
VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0);
|
||||
if (histogram_image == NULL) return 0;
|
||||
|
||||
// Calculate backward references from ARGB image.
|
||||
if (!VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, &refs)) {
|
||||
goto Error;
|
||||
}
|
||||
// Build histogram image and symbols from backward references.
|
||||
VP8LHistogramStoreRefs(&refs, histogram_image->histograms[0]);
|
||||
|
||||
// Create Huffman bit lengths and codes for each histogram image.
|
||||
assert(histogram_image->size == 1);
|
||||
if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// No color cache, no Huffman image.
|
||||
VP8LWriteBits(bw, 1, 0);
|
||||
|
||||
// Store Huffman codes.
|
||||
for (i = 0; i < 5; ++i) {
|
||||
HuffmanTreeCode* const codes = &huffman_codes[i];
|
||||
if (!StoreHuffmanCode(bw, codes)) {
|
||||
goto Error;
|
||||
}
|
||||
ClearHuffmanTreeIfOnlyOneSymbol(codes);
|
||||
}
|
||||
|
||||
// Store actual literals.
|
||||
StoreImageToBitMask(bw, width, 0, &refs, histogram_symbols, huffman_codes);
|
||||
ok = 1;
|
||||
|
||||
Error:
|
||||
free(histogram_image);
|
||||
VP8LClearBackwardRefs(&refs);
|
||||
free(huffman_codes[0].codes);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
const uint32_t* const argb,
|
||||
int width, int height, int quality,
|
||||
@ -449,8 +493,6 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
const int use_2d_locality = 1;
|
||||
const int use_color_cache = (cache_bits > 0);
|
||||
const int histogram_image_xysize =
|
||||
(histogram_bits == NO_HISTO_BITS) ?
|
||||
1 :
|
||||
VP8LSubSampleSize(width, histogram_bits) *
|
||||
VP8LSubSampleSize(height, histogram_bits);
|
||||
VP8LHistogramSet* histogram_image =
|
||||
@ -461,8 +503,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
VP8LBackwardRefs refs;
|
||||
uint16_t* const histogram_symbols =
|
||||
(uint16_t*)malloc(histogram_image_xysize * sizeof(*histogram_symbols));
|
||||
assert((histogram_bits >= 2 && histogram_bits <= 9) ||
|
||||
histogram_bits == NO_HISTO_BITS);
|
||||
assert(histogram_bits >= MIN_HISTO_BITS && histogram_bits <= MAX_HISTO_BITS);
|
||||
if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
|
||||
|
||||
// Calculate backward references from ARGB image.
|
||||
@ -470,14 +511,14 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
use_2d_locality, &refs)) {
|
||||
goto Error;
|
||||
}
|
||||
// Build histogram image & symbols from backward references.
|
||||
// Build histogram image and symbols from backward references.
|
||||
if (!VP8LGetHistoImageSymbols(width, height, &refs,
|
||||
quality, histogram_bits, cache_bits,
|
||||
histogram_image,
|
||||
histogram_symbols)) {
|
||||
goto Error;
|
||||
}
|
||||
// Create Huffman bit lengths & codes for each histogram image.
|
||||
// Create Huffman bit lengths and codes for each histogram image.
|
||||
histogram_image_size = histogram_image->size;
|
||||
bit_array_size = 5 * histogram_image_size;
|
||||
huffman_codes = (HuffmanTreeCode*)calloc(bit_array_size,
|
||||
@ -494,7 +535,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
}
|
||||
|
||||
// Huffman image + meta huffman.
|
||||
if (histogram_bits != NO_HISTO_BITS) {
|
||||
{
|
||||
const int write_histogram_image = (histogram_image_size > 1);
|
||||
VP8LWriteBits(bw, 1, write_histogram_image);
|
||||
if (write_histogram_image) {
|
||||
@ -512,10 +553,10 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
histogram_image_size = max_index;
|
||||
|
||||
VP8LWriteBits(bw, 3, histogram_bits - 2);
|
||||
ok = EncodeImageInternal(bw, histogram_argb,
|
||||
VP8LSubSampleSize(width, histogram_bits),
|
||||
VP8LSubSampleSize(height, histogram_bits),
|
||||
quality, 0, NO_HISTO_BITS);
|
||||
ok = EncodeImageNoHuffman(bw, histogram_argb,
|
||||
VP8LSubSampleSize(width, histogram_bits),
|
||||
VP8LSubSampleSize(height, histogram_bits),
|
||||
quality);
|
||||
free(histogram_argb);
|
||||
if (!ok) goto Error;
|
||||
}
|
||||
@ -607,9 +648,8 @@ static int ApplyPredictFilter(const VP8LEncoder* const enc,
|
||||
VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
|
||||
assert(pred_bits >= 2);
|
||||
VP8LWriteBits(bw, 3, pred_bits - 2);
|
||||
if (!EncodeImageInternal(bw, enc->transform_data_,
|
||||
transform_width, transform_height, quality, 0,
|
||||
NO_HISTO_BITS)) {
|
||||
if (!EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||
transform_width, transform_height, quality)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -629,9 +669,8 @@ static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
|
||||
VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
|
||||
assert(ccolor_transform_bits >= 2);
|
||||
VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
|
||||
if (!EncodeImageInternal(bw, enc->transform_data_,
|
||||
transform_width, transform_height, quality, 0,
|
||||
NO_HISTO_BITS)) {
|
||||
if (!EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||
transform_width, transform_height, quality)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -795,8 +834,7 @@ static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
|
||||
for (i = palette_size - 1; i >= 1; --i) {
|
||||
palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
|
||||
}
|
||||
if (!EncodeImageInternal(bw, palette, palette_size, 1, quality, 0,
|
||||
NO_HISTO_BITS)) {
|
||||
if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) {
|
||||
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||
goto Error;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user