mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +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:
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;
|
||||
|
Loading…
Reference in New Issue
Block a user