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