Removing the indirection of meta-huffman tables.

Now, the indexing refers directly to 5 huffman codes  that must be encoded separately.

Change-Id: I4deeb04de1997e6d20c376046d2053ec7ee918de
This commit is contained in:
Vikas Arora 2012-04-23 08:36:14 -07:00 committed by Pascal Massimino
parent 15ebcbaaf4
commit 231ec1fb6d
2 changed files with 52 additions and 82 deletions

View File

@ -296,18 +296,16 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
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* const color_cache_bits_ptr) {
int ok = 0; int ok = 0;
int i; 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;
HuffmanTree* htrees = NULL; HTreeGroup* htree_groups = NULL;
int num_htrees = HUFFMAN_CODES_PER_META_CODE; int num_htree_groups = 1;
uint32_t* meta_codes = NULL;
int meta_codes_size;
int color_cache_size;
if (VP8LReadBits(br, 1)) { // use meta Huffman codes if (VP8LReadBits(br, 1)) { // use meta Huffman codes
int meta_codes_nbits, num_meta_codes, nbits; 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);
@ -324,30 +322,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
} }
meta_codes_nbits = VP8LReadBits(br, 4); meta_codes_nbits = VP8LReadBits(br, 4);
num_meta_codes = 2 + VP8LReadBits(br, meta_codes_nbits); num_htree_groups = 2 + VP8LReadBits(br, meta_codes_nbits);
nbits = VP8LReadBits(br, 4);
meta_codes_size = num_meta_codes * HUFFMAN_CODES_PER_META_CODE;
meta_codes = (uint32_t*)calloc(meta_codes_size, sizeof(*meta_codes));
if (meta_codes == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
for (i = 0; i < meta_codes_size; ++i) {
const int tree_index = VP8LReadBits(br, nbits);
meta_codes[i] = tree_index;
if (num_htrees <= tree_index) {
num_htrees = tree_index + 1;
}
}
} else {
meta_codes_size = HUFFMAN_CODES_PER_META_CODE;
meta_codes = (uint32_t*)malloc(meta_codes_size * sizeof(*meta_codes));
if (meta_codes == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
for (i = 0; i < meta_codes_size; ++i) meta_codes[i] = i;
} }
if (VP8LReadBits(br, 1)) { // use color cache if (VP8LReadBits(br, 1)) { // use color cache
@ -358,39 +333,40 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
color_cache_size = 0; color_cache_size = 0;
} }
htrees = (HuffmanTree*)calloc(num_htrees, sizeof(*htrees)); htree_groups = (HTreeGroup*)calloc(num_htree_groups, sizeof(*htree_groups));
if (htrees == NULL) { if (htree_groups == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY; dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error; goto Error;
} }
ok = !br->error_; ok = !br->error_;
for (i = 0; ok && i < num_htrees; ++i) { for (i = 0; ok && i < num_htree_groups; ++i) {
const int tree_type = i % HUFFMAN_CODES_PER_META_CODE; for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[tree_type]; int alphabet_size = kAlphabetSize[j];
if (tree_type == 0) { if (j == 0) {
alphabet_size += color_cache_size; alphabet_size += color_cache_size;
} }
ok = ReadHuffmanCode(alphabet_size, dec, &htrees[i]); ok = ReadHuffmanCode(alphabet_size, dec, &htree_groups[i].htrees_[j]);
ok = ok && !br->error_; ok = ok && !br->error_;
} }
}
if (ok) { // finalize pointers and return if (ok) { // finalize pointers and return
hdr->huffman_image_ = huffman_image; hdr->huffman_image_ = huffman_image;
hdr->meta_codes_ = meta_codes; hdr->num_htree_groups_ = num_htree_groups;
hdr->num_huffman_trees_ = num_htrees; hdr->htree_groups_ = htree_groups;
hdr->htrees_ = htrees;
return ok; return ok;
} }
Error: Error:
free(huffman_image); free(huffman_image);
free(meta_codes); if (htree_groups != NULL) {
if (htrees != NULL) { for (i = 0; i < num_htree_groups; ++i) {
for (i = 0; i < num_htrees; ++i) { for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
HuffmanTreeRelease(&htrees[i]); HuffmanTreeRelease(&htree_groups[i].htrees_[j]);
} }
free(htrees); }
free(htree_groups);
} }
return 0; return 0;
} }
@ -518,19 +494,11 @@ static WEBP_INLINE int GetMetaIndex(
return image[xsize * (y >> bits) + (x >> bits)]; return image[xsize * (y >> bits) + (x >> bits)];
} }
static WEBP_INLINE void UpdateHtreeForPos(VP8LMetadata* const hdr, static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr,
int x, int y) { int x, int y) {
HuffmanTree* const htrees = hdr->htrees_; const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_,
const uint32_t* const meta_codes = hdr->meta_codes_;
const int meta_index = HUFFMAN_CODES_PER_META_CODE *
GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_,
hdr->huffman_subsample_bits_, x, y); hdr->huffman_subsample_bits_, x, y);
return hdr->htree_groups_ + meta_index;
hdr->meta_htrees_[GREEN] = &htrees[meta_codes[meta_index + GREEN]];
hdr->meta_htrees_[RED] = &htrees[meta_codes[meta_index + RED]];
hdr->meta_htrees_[BLUE] = &htrees[meta_codes[meta_index + BLUE]];
hdr->meta_htrees_[ALPHA] = &htrees[meta_codes[meta_index + ALPHA]];
hdr->meta_htrees_[DIST] = &htrees[meta_codes[meta_index + DIST]];
} }
// Processes (transforms, scales & color-converts) the rows decoded after the // Processes (transforms, scales & color-converts) the rows decoded after the
@ -589,6 +557,7 @@ static int DecodeImageData(VP8LDecoder* const dec,
VP8LBitReader* const br = &dec->br_; VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_; VP8LMetadata* const hdr = &dec->hdr_;
VP8LColorCache* const color_cache = hdr->color_cache_; VP8LColorCache* const color_cache = hdr->color_cache_;
HTreeGroup* htree_group = hdr->htree_groups_;
uint32_t* src = data; uint32_t* src = data;
uint32_t* last_cached = data; uint32_t* last_cached = data;
uint32_t* const src_end = data + width * height; uint32_t* const src_end = data + width * height;
@ -596,8 +565,7 @@ static int DecodeImageData(VP8LDecoder* const dec,
const int color_cache_limit = len_code_limit + hdr->color_cache_size_; const int color_cache_limit = len_code_limit + hdr->color_cache_size_;
const int mask = hdr->huffman_mask_; const int mask = hdr->huffman_mask_;
assert(hdr->htrees_ != NULL); assert(hdr->htree_groups_ != NULL);
assert(hdr->meta_codes_ != NULL);
while (!br->eos_ && src < src_end) { while (!br->eos_ && src < src_end) {
int code; int code;
@ -605,17 +573,17 @@ static int DecodeImageData(VP8LDecoder* const dec,
// if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed
// but that's actually slower and requires storing the previous col/row // but that's actually slower and requires storing the previous col/row
if ((col & mask) == 0) { if ((col & mask) == 0) {
UpdateHtreeForPos(hdr, col, row); htree_group = GetHtreeGroupForPos(hdr, col, row);
} }
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
code = ReadSymbol(hdr->meta_htrees_[GREEN], br); code = ReadSymbol(&htree_group->htrees_[GREEN], br);
if (code < NUM_LITERAL_CODES) { // Literal. if (code < NUM_LITERAL_CODES) { // Literal.
int red, green, blue, alpha; int red, green, blue, alpha;
red = ReadSymbol(hdr->meta_htrees_[RED], br); red = ReadSymbol(&htree_group->htrees_[RED], br);
green = code; green = code;
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
blue = ReadSymbol(hdr->meta_htrees_[BLUE], br); blue = ReadSymbol(&htree_group->htrees_[BLUE], br);
alpha = ReadSymbol(hdr->meta_htrees_[ALPHA], br); alpha = ReadSymbol(&htree_group->htrees_[ALPHA], br);
*src = (alpha << 24) + (red << 16) + (green << 8) + blue; *src = (alpha << 24) + (red << 16) + (green << 8) + blue;
AdvanceByOne: AdvanceByOne:
++src; ++src;
@ -636,7 +604,7 @@ static int DecodeImageData(VP8LDecoder* const dec,
int dist_code, dist; int dist_code, dist;
const int length_sym = code - NUM_LITERAL_CODES; const int length_sym = code - NUM_LITERAL_CODES;
const int length = GetCopyLength(length_sym, br); const int length = GetCopyLength(length_sym, br);
const int dist_symbol = ReadSymbol(hdr->meta_htrees_[DIST], br); const int dist_symbol = ReadSymbol(&htree_group->htrees_[DIST], br);
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
dist_code = GetCopyDistance(dist_symbol, br); dist_code = GetCopyDistance(dist_symbol, br);
dist = PlaneCodeToDistance(width, dist_code); dist = PlaneCodeToDistance(width, dist_code);
@ -658,7 +626,7 @@ static int DecodeImageData(VP8LDecoder* const dec,
} }
} }
if (src < src_end) { if (src < src_end) {
UpdateHtreeForPos(hdr, col, row); htree_group = GetHtreeGroupForPos(hdr, col, row);
if (color_cache != NULL) { if (color_cache != NULL) {
while (last_cached < src) { while (last_cached < src) {
VP8LColorCacheInsert(color_cache, *last_cached++); VP8LColorCacheInsert(color_cache, *last_cached++);
@ -802,13 +770,14 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr); assert(hdr);
free(hdr->huffman_image_); free(hdr->huffman_image_);
free(hdr->meta_codes_); if (hdr->htree_groups_ != NULL) {
if (hdr->htrees_ != NULL) { int i, j;
int i; for (i = 0; i < hdr->num_htree_groups_; ++i) {
for (i = 0; i < hdr->num_huffman_trees_; ++i) { for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
HuffmanTreeRelease(&(hdr->htrees_[i])); HuffmanTreeRelease(&hdr->htree_groups_[i].htrees_[j]);
} }
free(hdr->htrees_); }
free(hdr->htree_groups_);
} }
VP8LColorCacheDelete(hdr->color_cache_); VP8LColorCacheDelete(hdr->color_cache_);

View File

@ -17,6 +17,7 @@
#include "./webpi.h" #include "./webpi.h"
#include "../utils/bit_reader.h" #include "../utils/bit_reader.h"
#include "../utils/color_cache.h" #include "../utils/color_cache.h"
#include "../utils/huffman.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
@ -30,8 +31,6 @@ extern "C" {
#define LOSSLESS_MAGIC_BYTE 0x64 #define LOSSLESS_MAGIC_BYTE 0x64
#define LOSSLESS_MAGIC_BYTE_RSVD 0x65 #define LOSSLESS_MAGIC_BYTE_RSVD 0x65
struct HuffmanTree;
typedef enum { typedef enum {
READ_DATA = 0, READ_DATA = 0,
READ_HDR = 1, READ_HDR = 1,
@ -54,18 +53,20 @@ struct VP8LTransform {
uint32_t *data_; // transform data. uint32_t *data_; // transform data.
}; };
typedef struct {
HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE];
} HTreeGroup;
typedef struct { typedef struct {
int color_cache_size_; int color_cache_size_;
VP8LColorCache *color_cache_; VP8LColorCache *color_cache_;
int num_huffman_trees_;
int huffman_mask_; int huffman_mask_;
int huffman_subsample_bits_; int huffman_subsample_bits_;
int huffman_xsize_; int huffman_xsize_;
uint32_t *meta_codes_;
uint32_t *huffman_image_; uint32_t *huffman_image_;
struct HuffmanTree *htrees_; int num_htree_groups_;
struct HuffmanTree *meta_htrees_[HUFFMAN_CODES_PER_META_CODE]; HTreeGroup *htree_groups_;
} VP8LMetadata; } VP8LMetadata;
typedef struct { typedef struct {