further simplification for the meta-Huffman coding

* don't transmit the number of Huffman tree group explicitly
* move color-cache information before the meta-Huffman block

* also add a check that color_cache_bits is in [1..11] range, as per spec.

Change-Id: I81d7711068653b509cdbc1151d93e229c4254580
This commit is contained in:
Pascal Massimino 2012-04-25 09:40:41 +00:00 committed by James Zern
parent e491729905
commit 8415ddf3be
2 changed files with 58 additions and 72 deletions

View File

@ -31,6 +31,7 @@ static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
#define NUM_LENGTH_CODES 24 #define NUM_LENGTH_CODES 24
#define NUM_DISTANCE_CODES 40 #define NUM_DISTANCE_CODES 40
#define DEFAULT_CODE_LENGTH 8 #define DEFAULT_CODE_LENGTH 8
#define MAX_CACHE_BITS 11
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Five Huffman codes are used at each meta code: // Five Huffman codes are used at each meta code:
@ -307,10 +308,9 @@ static void DeleteHtreeGroups(HTreeGroup* htree_groups, int num_htree_groups) {
} }
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int* const color_cache_bits_ptr) { int color_cache_bits) {
int ok = 0; int ok = 0;
int i, j; int i, j;
int color_cache_size;
VP8LBitReader* const br = &dec->br_; VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_; VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL; uint32_t* huffman_image = NULL;
@ -318,11 +318,11 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int num_htree_groups = 1; int num_htree_groups = 1;
if (VP8LReadBits(br, 1)) { // use meta Huffman codes if (VP8LReadBits(br, 1)) { // use meta Huffman codes
int meta_codes_nbits;
const int huffman_precision = VP8LReadBits(br, 4); const int huffman_precision = VP8LReadBits(br, 4);
const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision); const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision); const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
const int huffman_pixs = huffman_xsize * huffman_ysize; const int huffman_pixs = huffman_xsize * huffman_ysize;
if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec, if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
&huffman_image)) { &huffman_image)) {
dec->status_ = VP8_STATUS_BITSTREAM_ERROR; dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
@ -331,19 +331,12 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
hdr->huffman_subsample_bits_ = huffman_precision; hdr->huffman_subsample_bits_ = huffman_precision;
for (i = 0; i < huffman_pixs; ++i) { for (i = 0; i < huffman_pixs; ++i) {
// The huffman data is stored in red and green bytes. // The huffman data is stored in red and green bytes.
huffman_image[i] = (huffman_image[i] >> 8) & 0xffff; const int index = (huffman_image[i] >> 8) & 0xffff;
huffman_image[i] = index;
if (index >= num_htree_groups) {
num_htree_groups = index + 1;
}
} }
meta_codes_nbits = VP8LReadBits(br, 4);
num_htree_groups = 2 + VP8LReadBits(br, meta_codes_nbits);
}
if (VP8LReadBits(br, 1)) { // use color cache
*color_cache_bits_ptr = VP8LReadBits(br, 4);
color_cache_size = 1 << *color_cache_bits_ptr;
} else {
*color_cache_bits_ptr = 0;
color_cache_size = 0;
} }
htree_groups = (HTreeGroup*)calloc(num_htree_groups, sizeof(*htree_groups)); htree_groups = (HTreeGroup*)calloc(num_htree_groups, sizeof(*htree_groups));
@ -357,10 +350,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
HuffmanTree* const htrees = htree_groups[i].htrees_; HuffmanTree* const htrees = htree_groups[i].htrees_;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j]; int alphabet_size = kAlphabetSize[j];
if (j == 0) { if (j == 0 && color_cache_bits > 0) {
alphabet_size += color_cache_size; alphabet_size += 1 << color_cache_bits;
} }
ok = ReadHuffmanCode(alphabet_size, dec, &htrees[j]); ok = ReadHuffmanCode(alphabet_size, dec, htrees + j);
ok = ok && !br->error_; ok = ok && !br->error_;
} }
} }
@ -835,29 +828,38 @@ static int DecodeImageStream(int xsize, int ysize,
int ok = 1; int ok = 1;
int transform_xsize = xsize; int transform_xsize = xsize;
int transform_ysize = ysize; int transform_ysize = ysize;
VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_; VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* data = NULL; uint32_t* data = NULL;
const int transform_start_idx = dec->next_transform_;
int color_cache_bits = 0; int color_cache_bits = 0;
VP8LBitReader* const br = &dec->br_; // Read the transforms (may recurse).
int transform_start_idx = dec->next_transform_;
// Step#1: Read the transforms (may recurse).
if (is_level0) { if (is_level0) {
while (ok && VP8LReadBits(br, 1)) { while (ok && VP8LReadBits(br, 1)) {
ok = ReadTransform(&transform_xsize, &transform_ysize, dec); ok = ReadTransform(&transform_xsize, &transform_ysize, dec);
} }
} }
// Step#2: Read the Huffman codes (may recurse). // Color cache
ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize, if (ok && VP8LReadBits(br, 1)) {
&color_cache_bits); color_cache_bits = VP8LReadBits(br, 4);
ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS);
if (!ok) {
dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
goto End;
}
}
// Read the Huffman codes (may recurse).
ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
color_cache_bits);
if (!ok) { if (!ok) {
dec->status_ = VP8_STATUS_BITSTREAM_ERROR; dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
goto End; goto End;
} }
// Finish setting up the color-cache
if (color_cache_bits > 0) { if (color_cache_bits > 0) {
hdr->color_cache_size_ = 1 << color_cache_bits; hdr->color_cache_size_ = 1 << color_cache_bits;
hdr->color_cache_ = (VP8LColorCache*)malloc(sizeof(*hdr->color_cache_)); hdr->color_cache_ = (VP8LColorCache*)malloc(sizeof(*hdr->color_cache_));
@ -868,7 +870,6 @@ static int DecodeImageStream(int xsize, int ysize,
goto End; goto End;
} }
} }
UpdateDecoder(dec, transform_xsize, transform_ysize); UpdateDecoder(dec, transform_xsize, transform_ysize);
if (is_level0) { // level 0 complete if (is_level0) { // level 0 complete
@ -883,11 +884,11 @@ static int DecodeImageStream(int xsize, int ysize,
goto End; goto End;
} }
// Step#3: Use the Huffman trees to decode the LZ77 encoded data. // Use the Huffman trees to decode the LZ77 encoded data.
ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, 0); ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, 0);
ok = ok && !br->error_; ok = ok && !br->error_;
// Step#4: Apply transforms on the decoded data. // Apply transforms on the decoded data.
if (ok) ApplyInverseTransforms(dec, transform_start_idx, data); if (ok) ApplyInverseTransforms(dec, transform_start_idx, data);
End: End:

View File

@ -27,18 +27,12 @@
extern "C" { extern "C" {
#endif #endif
static const uint32_t kImageSizeBits = 14; static const int kImageSizeBits = 14;
static int CompareColors(const void* p1, const void* p2) { static int CompareColors(const void* p1, const void* p2) {
const uint32_t a = *(const uint32_t*)p1; const uint32_t a = *(const uint32_t*)p1;
const uint32_t b = *(const uint32_t*)p2; const uint32_t b = *(const uint32_t*)p2;
if (a < b) { return (a < b) ? -1 : (a > b) ? 1 : 0;
return -1;
}
if (a == b) {
return 0;
}
return 1;
} }
// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE, // If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
@ -511,14 +505,6 @@ static int GetHuffBitLengthsAndCodes(
return 0; return 0;
} }
static void ShiftHistogramImage(uint32_t* image , int image_size) {
int i;
for (i = 0; i < image_size; ++i) {
image[i] <<= 8;
image[i] |= 0xff000000;
}
}
static void ClearHuffmanTreeIfOnlyOneSymbol(const int num_symbols, static void ClearHuffmanTreeIfOnlyOneSymbol(const int num_symbols,
uint8_t* lengths, uint8_t* lengths,
uint16_t* symbols) { uint16_t* symbols) {
@ -758,8 +744,8 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
VP8LSubSampleSize(height, histogram_bits); VP8LSubSampleSize(height, histogram_bits);
VP8LHistogram** histogram_image; VP8LHistogram** histogram_image;
PixOrCopy* backward_refs; PixOrCopy* backward_refs;
uint32_t* histogram_symbols = (uint32_t*) const size_t histo_size = histogram_image_xysize * sizeof(uint32_t);
calloc(histogram_image_xysize, sizeof(*histogram_symbols)); uint32_t* const histogram_symbols = (uint32_t*)calloc(1, histo_size);
if (histogram_symbols == NULL) goto Error; if (histogram_symbols == NULL) goto Error;
@ -790,38 +776,37 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
goto Error; goto Error;
} }
// Huffman image + meta huffman.
write_histogram_image = (histogram_image_size > 1);
VP8LWriteBits(bw, 1, write_histogram_image);
if (write_histogram_image) {
int image_size_bits;
uint32_t* histogram_argb = (uint32_t*)
malloc(histogram_image_xysize * sizeof(*histogram_argb));
if (histogram_argb == NULL) goto Error;
memcpy(histogram_argb, histogram_symbols,
histogram_image_xysize * sizeof(*histogram_argb));
ShiftHistogramImage(histogram_argb, histogram_image_xysize);
VP8LWriteBits(bw, 4, histogram_bits);
if (!EncodeImageInternal(bw, histogram_argb,
VP8LSubSampleSize(width, histogram_bits),
VP8LSubSampleSize(height, histogram_bits),
quality, 0, 0)) {
free(histogram_argb);
goto Error;
}
image_size_bits = VP8LBitsLog2Ceiling(histogram_image_size - 1);
VP8LWriteBits(bw, 4, image_size_bits);
VP8LWriteBits(bw, image_size_bits, histogram_image_size - 2);
free(histogram_argb);
}
// Color Cache parameters. // Color Cache parameters.
VP8LWriteBits(bw, 1, use_color_cache); VP8LWriteBits(bw, 1, use_color_cache);
if (use_color_cache) { if (use_color_cache) {
VP8LWriteBits(bw, 4, cache_bits); VP8LWriteBits(bw, 4, cache_bits);
} }
// Huffman image + meta huffman.
write_histogram_image = (histogram_image_size > 1);
VP8LWriteBits(bw, 1, write_histogram_image);
if (write_histogram_image) {
uint32_t* const histogram_argb = (uint32_t*)malloc(histo_size);
int max_index = 0;
if (histogram_argb == NULL) goto Error;
for (i = 0; i < histogram_image_xysize; ++i) {
const int index = histogram_symbols[i] & 0xffff;
histogram_argb[i] = 0xff000000 | (index << 8);
if (index >= max_index) {
max_index = index + 1;
}
}
histogram_image_size = max_index;
VP8LWriteBits(bw, 4, histogram_bits);
ok = EncodeImageInternal(bw, histogram_argb,
VP8LSubSampleSize(width, histogram_bits),
VP8LSubSampleSize(height, histogram_bits),
quality, 0, 0);
free(histogram_argb);
if (!ok) goto Error;
}
// Store Huffman codes. // Store Huffman codes.
for (i = 0; i < histogram_image_size; ++i) { for (i = 0; i < histogram_image_size; ++i) {
int k; int k;