mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
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:
parent
15ebcbaaf4
commit
231ec1fb6d
113
src/dec/vp8l.c
113
src/dec/vp8l.c
@ -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_);
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user