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;
|
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,
|
void VP8LHistogramCreate(VP8LHistogram* const p,
|
||||||
const VP8LBackwardRefs* const refs,
|
const VP8LBackwardRefs* const refs,
|
||||||
int palette_code_bits) {
|
int palette_code_bits) {
|
||||||
int i;
|
|
||||||
if (palette_code_bits >= 0) {
|
if (palette_code_bits >= 0) {
|
||||||
p->palette_code_bits_ = palette_code_bits;
|
p->palette_code_bits_ = palette_code_bits;
|
||||||
}
|
}
|
||||||
HistogramClear(p);
|
HistogramClear(p);
|
||||||
for (i = 0; i < refs->size; ++i) {
|
VP8LHistogramStoreRefs(refs, p);
|
||||||
VP8LHistogramAddSinglePixOrCopy(p, &refs->refs[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) {
|
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) {
|
const PixOrCopy* const v) {
|
||||||
if (PixOrCopyIsLiteral(v)) {
|
if (PixOrCopyIsLiteral(v)) {
|
||||||
++p->alpha_[PixOrCopyLiteral(v, 3)];
|
++histo->alpha_[PixOrCopyLiteral(v, 3)];
|
||||||
++p->red_[PixOrCopyLiteral(v, 2)];
|
++histo->red_[PixOrCopyLiteral(v, 2)];
|
||||||
++p->literal_[PixOrCopyLiteral(v, 1)];
|
++histo->literal_[PixOrCopyLiteral(v, 1)];
|
||||||
++p->blue_[PixOrCopyLiteral(v, 0)];
|
++histo->blue_[PixOrCopyLiteral(v, 0)];
|
||||||
} else if (PixOrCopyIsCacheIdx(v)) {
|
} else if (PixOrCopyIsCacheIdx(v)) {
|
||||||
int literal_ix = 256 + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
|
int literal_ix = 256 + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
|
||||||
++p->literal_[literal_ix];
|
++histo->literal_[literal_ix];
|
||||||
} else {
|
} else {
|
||||||
int code, extra_bits_count, extra_bits_value;
|
int code, extra_bits_count, extra_bits_value;
|
||||||
PrefixEncode(PixOrCopyLength(v),
|
PrefixEncode(PixOrCopyLength(v),
|
||||||
&code, &extra_bits_count, &extra_bits_value);
|
&code, &extra_bits_count, &extra_bits_value);
|
||||||
++p->literal_[256 + code];
|
++histo->literal_[256 + code];
|
||||||
PrefixEncode(PixOrCopyDistance(v),
|
PrefixEncode(PixOrCopyDistance(v),
|
||||||
&code, &extra_bits_count, &extra_bits_value);
|
&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 VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
|
||||||
double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p)) +
|
double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p))
|
||||||
BitsEntropy(&p->red_[0], 256) +
|
+ BitsEntropy(&p->red_[0], 256)
|
||||||
BitsEntropy(&p->blue_[0], 256) +
|
+ BitsEntropy(&p->blue_[0], 256)
|
||||||
BitsEntropy(&p->alpha_[0], 256) +
|
+ BitsEntropy(&p->alpha_[0], 256)
|
||||||
BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES);
|
+ BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES);
|
||||||
// Compute the extra bits cost.
|
// Compute the extra bits cost.
|
||||||
int i;
|
int i;
|
||||||
for (i = 2; i < NUM_LENGTH_CODES - 2; ++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) {
|
VP8LHistogramSet* const image) {
|
||||||
int i;
|
int i;
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
const int histo_xsize =
|
const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
|
||||||
(histo_bits > 0) ? VP8LSubSampleSize(xsize, histo_bits) : 1;
|
VP8LHistogram** const histograms = image->histograms;
|
||||||
|
assert(histo_bits > 0);
|
||||||
for (i = 0; i < backward_refs->size; ++i) {
|
for (i = 0; i < backward_refs->size; ++i) {
|
||||||
const PixOrCopy* const v = &backward_refs->refs[i];
|
const PixOrCopy* const v = &backward_refs->refs[i];
|
||||||
const int ix =
|
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
|
||||||
(histo_bits > 0) ? (y >> histo_bits) * histo_xsize + (x >> histo_bits)
|
VP8LHistogramAddSinglePixOrCopy(histograms[ix], v);
|
||||||
: 0;
|
|
||||||
VP8LHistogramAddSinglePixOrCopy(image->histograms[ix], v);
|
|
||||||
x += PixOrCopyLength(v);
|
x += PixOrCopyLength(v);
|
||||||
while (x >= xsize) {
|
while (x >= xsize) {
|
||||||
x -= xsize;
|
x -= xsize;
|
||||||
|
@ -62,11 +62,16 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
|
|||||||
// Set the palette_code_bits and reset the stats.
|
// Set the palette_code_bits and reset the stats.
|
||||||
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
|
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
|
// Allocate an array of pointer to histograms, allocated and initialized
|
||||||
// using 'cache_bits'. Return NULL in case of memory error.
|
// using 'cache_bits'. Return NULL in case of memory error.
|
||||||
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
|
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);
|
const PixOrCopy* const v);
|
||||||
|
|
||||||
// Estimate how many bits the combined entropy of literals and distance
|
// Estimate how many bits the combined entropy of literals and distance
|
||||||
|
@ -33,10 +33,6 @@ extern "C" {
|
|||||||
#define MIN_HISTO_BITS 2
|
#define MIN_HISTO_BITS 2
|
||||||
#define MAX_HISTO_BITS 9
|
#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
|
// 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,
|
static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||||
const uint32_t* const argb,
|
const uint32_t* const argb,
|
||||||
int width, int height, int quality,
|
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_2d_locality = 1;
|
||||||
const int use_color_cache = (cache_bits > 0);
|
const int use_color_cache = (cache_bits > 0);
|
||||||
const int histogram_image_xysize =
|
const int histogram_image_xysize =
|
||||||
(histogram_bits == NO_HISTO_BITS) ?
|
|
||||||
1 :
|
|
||||||
VP8LSubSampleSize(width, histogram_bits) *
|
VP8LSubSampleSize(width, histogram_bits) *
|
||||||
VP8LSubSampleSize(height, histogram_bits);
|
VP8LSubSampleSize(height, histogram_bits);
|
||||||
VP8LHistogramSet* histogram_image =
|
VP8LHistogramSet* histogram_image =
|
||||||
@ -461,8 +503,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
|||||||
VP8LBackwardRefs refs;
|
VP8LBackwardRefs refs;
|
||||||
uint16_t* const histogram_symbols =
|
uint16_t* const histogram_symbols =
|
||||||
(uint16_t*)malloc(histogram_image_xysize * sizeof(*histogram_symbols));
|
(uint16_t*)malloc(histogram_image_xysize * sizeof(*histogram_symbols));
|
||||||
assert((histogram_bits >= 2 && histogram_bits <= 9) ||
|
assert(histogram_bits >= MIN_HISTO_BITS && histogram_bits <= MAX_HISTO_BITS);
|
||||||
histogram_bits == NO_HISTO_BITS);
|
|
||||||
if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
|
if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
|
||||||
|
|
||||||
// Calculate backward references from ARGB image.
|
// Calculate backward references from ARGB image.
|
||||||
@ -470,14 +511,14 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
|||||||
use_2d_locality, &refs)) {
|
use_2d_locality, &refs)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
// Build histogram image & symbols from backward references.
|
// Build histogram image and symbols from backward references.
|
||||||
if (!VP8LGetHistoImageSymbols(width, height, &refs,
|
if (!VP8LGetHistoImageSymbols(width, height, &refs,
|
||||||
quality, histogram_bits, cache_bits,
|
quality, histogram_bits, cache_bits,
|
||||||
histogram_image,
|
histogram_image,
|
||||||
histogram_symbols)) {
|
histogram_symbols)) {
|
||||||
goto Error;
|
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;
|
histogram_image_size = histogram_image->size;
|
||||||
bit_array_size = 5 * histogram_image_size;
|
bit_array_size = 5 * histogram_image_size;
|
||||||
huffman_codes = (HuffmanTreeCode*)calloc(bit_array_size,
|
huffman_codes = (HuffmanTreeCode*)calloc(bit_array_size,
|
||||||
@ -494,7 +535,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Huffman image + meta huffman.
|
// Huffman image + meta huffman.
|
||||||
if (histogram_bits != NO_HISTO_BITS) {
|
{
|
||||||
const int write_histogram_image = (histogram_image_size > 1);
|
const int write_histogram_image = (histogram_image_size > 1);
|
||||||
VP8LWriteBits(bw, 1, write_histogram_image);
|
VP8LWriteBits(bw, 1, write_histogram_image);
|
||||||
if (write_histogram_image) {
|
if (write_histogram_image) {
|
||||||
@ -512,10 +553,10 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
|||||||
histogram_image_size = max_index;
|
histogram_image_size = max_index;
|
||||||
|
|
||||||
VP8LWriteBits(bw, 3, histogram_bits - 2);
|
VP8LWriteBits(bw, 3, histogram_bits - 2);
|
||||||
ok = EncodeImageInternal(bw, histogram_argb,
|
ok = EncodeImageNoHuffman(bw, histogram_argb,
|
||||||
VP8LSubSampleSize(width, histogram_bits),
|
VP8LSubSampleSize(width, histogram_bits),
|
||||||
VP8LSubSampleSize(height, histogram_bits),
|
VP8LSubSampleSize(height, histogram_bits),
|
||||||
quality, 0, NO_HISTO_BITS);
|
quality);
|
||||||
free(histogram_argb);
|
free(histogram_argb);
|
||||||
if (!ok) goto Error;
|
if (!ok) goto Error;
|
||||||
}
|
}
|
||||||
@ -607,9 +648,8 @@ static int ApplyPredictFilter(const VP8LEncoder* const enc,
|
|||||||
VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
|
VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
|
||||||
assert(pred_bits >= 2);
|
assert(pred_bits >= 2);
|
||||||
VP8LWriteBits(bw, 3, pred_bits - 2);
|
VP8LWriteBits(bw, 3, pred_bits - 2);
|
||||||
if (!EncodeImageInternal(bw, enc->transform_data_,
|
if (!EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||||
transform_width, transform_height, quality, 0,
|
transform_width, transform_height, quality)) {
|
||||||
NO_HISTO_BITS)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -629,9 +669,8 @@ static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
|
|||||||
VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
|
VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
|
||||||
assert(ccolor_transform_bits >= 2);
|
assert(ccolor_transform_bits >= 2);
|
||||||
VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
|
VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
|
||||||
if (!EncodeImageInternal(bw, enc->transform_data_,
|
if (!EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||||
transform_width, transform_height, quality, 0,
|
transform_width, transform_height, quality)) {
|
||||||
NO_HISTO_BITS)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -795,8 +834,7 @@ static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
|
|||||||
for (i = palette_size - 1; i >= 1; --i) {
|
for (i = palette_size - 1; i >= 1; --i) {
|
||||||
palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
|
palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
|
||||||
}
|
}
|
||||||
if (!EncodeImageInternal(bw, palette, palette_size, 1, quality, 0,
|
if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) {
|
||||||
NO_HISTO_BITS)) {
|
|
||||||
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user