mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 02:15:42 +01:00 
			
		
		
		
	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:
		
				
					committed by
					
						 James Zern
						James Zern
					
				
			
			
				
	
			
			
			
						parent
						
							e491729905
						
					
				
				
					commit
					8415ddf3be
				
			| @@ -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: | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user