From 3697b5ceb2ac6009480807a4edac245559aa1a6c Mon Sep 17 00:00:00 2001 From: Pascal Massimino Date: Fri, 8 Jun 2012 11:52:31 -0700 Subject: [PATCH] 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 --- src/enc/histogram.c | 50 ++++++++++++++------------- src/enc/histogram.h | 7 +++- src/enc/vp8l.c | 84 ++++++++++++++++++++++++++++++++------------- 3 files changed, 94 insertions(+), 47 deletions(-) diff --git a/src/enc/histogram.c b/src/enc/histogram.c index 6bb92e01..50bffa23 100644 --- a/src/enc/histogram.c +++ b/src/enc/histogram.c @@ -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; diff --git a/src/enc/histogram.h b/src/enc/histogram.h index 1cb2f767..912bbb18 100644 --- a/src/enc/histogram.h +++ b/src/enc/histogram.h @@ -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 diff --git a/src/enc/vp8l.c b/src/enc/vp8l.c index d380b363..f24e7c49 100644 --- a/src/enc/vp8l.c +++ b/src/enc/vp8l.c @@ -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; }