diff --git a/src/dec/vp8l.c b/src/dec/vp8l.c index 35720d71..d7f21ca0 100644 --- a/src/dec/vp8l.c +++ b/src/dec/vp8l.c @@ -31,6 +31,7 @@ static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 }; #define NUM_LENGTH_CODES 24 #define NUM_DISTANCE_CODES 40 #define DEFAULT_CODE_LENGTH 8 +#define MAX_CACHE_BITS 11 // ----------------------------------------------------------------------------- // 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, - int* const color_cache_bits_ptr) { + int color_cache_bits) { int ok = 0; int i, j; - int color_cache_size; VP8LBitReader* const br = &dec->br_; VP8LMetadata* const hdr = &dec->hdr_; uint32_t* huffman_image = NULL; @@ -318,11 +318,11 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, int num_htree_groups = 1; if (VP8LReadBits(br, 1)) { // use meta Huffman codes - int meta_codes_nbits; const int huffman_precision = VP8LReadBits(br, 4); const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision); const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision); const int huffman_pixs = huffman_xsize * huffman_ysize; + if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec, &huffman_image)) { 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; for (i = 0; i < huffman_pixs; ++i) { // 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)); @@ -357,10 +350,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, HuffmanTree* const htrees = htree_groups[i].htrees_; for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { int alphabet_size = kAlphabetSize[j]; - if (j == 0) { - alphabet_size += color_cache_size; + if (j == 0 && color_cache_bits > 0) { + alphabet_size += 1 << color_cache_bits; } - ok = ReadHuffmanCode(alphabet_size, dec, &htrees[j]); + ok = ReadHuffmanCode(alphabet_size, dec, htrees + j); ok = ok && !br->error_; } } @@ -835,29 +828,38 @@ static int DecodeImageStream(int xsize, int ysize, int ok = 1; int transform_xsize = xsize; int transform_ysize = ysize; + VP8LBitReader* const br = &dec->br_; VP8LMetadata* const hdr = &dec->hdr_; uint32_t* data = NULL; + const int transform_start_idx = dec->next_transform_; int color_cache_bits = 0; - VP8LBitReader* const br = &dec->br_; - int transform_start_idx = dec->next_transform_; - - // Step#1: Read the transforms (may recurse). + // Read the transforms (may recurse). if (is_level0) { while (ok && VP8LReadBits(br, 1)) { ok = ReadTransform(&transform_xsize, &transform_ysize, dec); } } - // Step#2: Read the Huffman codes (may recurse). - ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize, - &color_cache_bits); + // Color cache + if (ok && VP8LReadBits(br, 1)) { + 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) { dec->status_ = VP8_STATUS_BITSTREAM_ERROR; goto End; } + // Finish setting up the color-cache if (color_cache_bits > 0) { hdr->color_cache_size_ = 1 << color_cache_bits; hdr->color_cache_ = (VP8LColorCache*)malloc(sizeof(*hdr->color_cache_)); @@ -868,7 +870,6 @@ static int DecodeImageStream(int xsize, int ysize, goto End; } } - UpdateDecoder(dec, transform_xsize, transform_ysize); if (is_level0) { // level 0 complete @@ -883,11 +884,11 @@ static int DecodeImageStream(int xsize, int ysize, 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 = 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); End: diff --git a/src/enc/vp8l.c b/src/enc/vp8l.c index 69b009e5..d7825671 100644 --- a/src/enc/vp8l.c +++ b/src/enc/vp8l.c @@ -27,18 +27,12 @@ extern "C" { #endif -static const uint32_t kImageSizeBits = 14; +static const int kImageSizeBits = 14; static int CompareColors(const void* p1, const void* p2) { const uint32_t a = *(const uint32_t*)p1; const uint32_t b = *(const uint32_t*)p2; - if (a < b) { - return -1; - } - if (a == b) { - return 0; - } - return 1; + return (a < b) ? -1 : (a > b) ? 1 : 0; } // 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; } -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, uint8_t* lengths, uint16_t* symbols) { @@ -758,8 +744,8 @@ static int EncodeImageInternal(VP8LBitWriter* const bw, VP8LSubSampleSize(height, histogram_bits); VP8LHistogram** histogram_image; PixOrCopy* backward_refs; - uint32_t* histogram_symbols = (uint32_t*) - calloc(histogram_image_xysize, sizeof(*histogram_symbols)); + const size_t histo_size = histogram_image_xysize * sizeof(uint32_t); + uint32_t* const histogram_symbols = (uint32_t*)calloc(1, histo_size); if (histogram_symbols == NULL) goto Error; @@ -790,38 +776,37 @@ static int EncodeImageInternal(VP8LBitWriter* const bw, 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. VP8LWriteBits(bw, 1, use_color_cache); if (use_color_cache) { 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. for (i = 0; i < histogram_image_size; ++i) { int k;