summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/dec/vp8l.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/libwebp/src/dec/vp8l.c')
-rw-r--r--src/3rdparty/libwebp/src/dec/vp8l.c132
1 files changed, 78 insertions, 54 deletions
diff --git a/src/3rdparty/libwebp/src/dec/vp8l.c b/src/3rdparty/libwebp/src/dec/vp8l.c
index ea0254d..e2780e5 100644
--- a/src/3rdparty/libwebp/src/dec/vp8l.c
+++ b/src/3rdparty/libwebp/src/dec/vp8l.c
@@ -12,13 +12,13 @@
// Authors: Vikas Arora (vikaas.arora@gmail.com)
// Jyrki Alakuijala (jyrki@google.com)
-#include <stdio.h>
#include <stdlib.h>
+
#include "./alphai.h"
#include "./vp8li.h"
+#include "../dsp/dsp.h"
#include "../dsp/lossless.h"
#include "../dsp/yuv.h"
-#include "../utils/alpha_processing.h"
#include "../utils/huffman.h"
#include "../utils/utils.h"
@@ -187,9 +187,10 @@ static int ReadHuffmanCodeLengths(
int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH;
HuffmanTree tree;
+ int huff_codes[NUM_CODE_LENGTH_CODES] = { 0 };
- if (!HuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
- NUM_CODE_LENGTH_CODES)) {
+ if (!VP8LHuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
+ huff_codes, NUM_CODE_LENGTH_CODES)) {
dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return 0;
}
@@ -232,11 +233,15 @@ static int ReadHuffmanCodeLengths(
ok = 1;
End:
- HuffmanTreeRelease(&tree);
+ VP8LHuffmanTreeFree(&tree);
+ if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return ok;
}
+// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
+// tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
+ int* const code_lengths, int* const huff_codes,
HuffmanTree* const tree) {
int ok = 0;
VP8LBitReader* const br = &dec->br_;
@@ -245,7 +250,6 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
if (simple_code) { // Read symbols, codes & code lengths directly.
int symbols[2];
int codes[2];
- int code_lengths[2];
const int num_symbols = VP8LReadBits(br, 1) + 1;
const int first_symbol_len_code = VP8LReadBits(br, 1);
// The first code is either 1 bit or 8 bit code.
@@ -258,10 +262,9 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
codes[1] = 1;
code_lengths[1] = num_symbols - 1;
}
- ok = HuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols,
- alphabet_size, num_symbols);
+ ok = VP8LHuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols,
+ alphabet_size, num_symbols);
} else { // Decode Huffman-coded code lengths.
- int* code_lengths = NULL;
int i;
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
const int num_codes = VP8LReadBits(br, 4) + 4;
@@ -270,22 +273,15 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
return 0;
}
- code_lengths =
- (int*)WebPSafeCalloc((uint64_t)alphabet_size, sizeof(*code_lengths));
- if (code_lengths == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
- }
+ memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths));
for (i = 0; i < num_codes; ++i) {
code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
}
ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size,
code_lengths);
- if (ok) {
- ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size);
- }
- free(code_lengths);
+ ok = ok && VP8LHuffmanTreeBuildImplicit(tree, code_lengths, huff_codes,
+ alphabet_size);
}
ok = ok && !br->error_;
if (!ok) {
@@ -295,19 +291,6 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
return 1;
}
-static void DeleteHtreeGroups(HTreeGroup* htree_groups, int num_htree_groups) {
- if (htree_groups != NULL) {
- int i, j;
- for (i = 0; i < num_htree_groups; ++i) {
- HuffmanTree* const htrees = htree_groups[i].htrees_;
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- HuffmanTreeRelease(&htrees[j]);
- }
- }
- free(htree_groups);
- }
-}
-
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int color_cache_bits, int allow_recursion) {
int i, j;
@@ -316,6 +299,9 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
int num_htree_groups = 1;
+ int max_alphabet_size = 0;
+ int* code_lengths = NULL;
+ int* huff_codes = NULL;
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
@@ -341,11 +327,24 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
if (br->error_) goto Error;
- assert(num_htree_groups <= 0x10000);
- htree_groups =
- (HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups,
- sizeof(*htree_groups));
- if (htree_groups == NULL) {
+ // Find maximum alphabet size for the htree group.
+ for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
+ int alphabet_size = kAlphabetSize[j];
+ if (j == 0 && color_cache_bits > 0) {
+ alphabet_size += 1 << color_cache_bits;
+ }
+ if (max_alphabet_size < alphabet_size) {
+ max_alphabet_size = alphabet_size;
+ }
+ }
+
+ htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+ code_lengths =
+ (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, sizeof(*code_lengths));
+ huff_codes =
+ (int*)WebPSafeMalloc((uint64_t)max_alphabet_size, sizeof(*huff_codes));
+
+ if (htree_groups == NULL || code_lengths == NULL || huff_codes == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
@@ -354,12 +353,18 @@ 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];
+ HuffmanTree* const htree = htrees + j;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += 1 << color_cache_bits;
}
- if (!ReadHuffmanCode(alphabet_size, dec, htrees + j)) goto Error;
+ if (!ReadHuffmanCode(alphabet_size, dec, code_lengths, huff_codes,
+ htree)) {
+ goto Error;
+ }
}
}
+ WebPSafeFree(huff_codes);
+ WebPSafeFree(code_lengths);
// All OK. Finalize pointers and return.
hdr->huffman_image_ = huffman_image;
@@ -368,8 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
return 1;
Error:
- free(huffman_image);
- DeleteHtreeGroups(htree_groups, num_htree_groups);
+ WebPSafeFree(huff_codes);
+ WebPSafeFree(code_lengths);
+ WebPSafeFree(huffman_image);
+ VP8LHtreeGroupsFree(htree_groups, num_htree_groups);
return 0;
}
@@ -420,7 +427,7 @@ static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) {
uint8_t* const dst = rgba + num_lines_out * rgba_stride;
- WebPRescalerExportRow(rescaler);
+ WebPRescalerExportRow(rescaler, 0);
WebPMultARGBRow(src, dst_width, 1);
VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
++num_lines_out;
@@ -468,6 +475,7 @@ static int EmitRows(WEBP_CSP_MODE colorspace,
//------------------------------------------------------------------------------
// Export to YUVA
+// TODO(skal): should be in yuv.c
static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
const WebPDecBuffer* const output) {
const WebPYUVABuffer* const buf = &output->u.YUVA;
@@ -537,7 +545,7 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
const int dst_width = rescaler->dst_width;
int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) {
- WebPRescalerExportRow(rescaler);
+ WebPRescalerExportRow(rescaler, 0);
WebPMultARGBRow(src, dst_width, 1);
ConvertToYUVA(src, dst_width, y_pos, dec->output_);
++y_pos;
@@ -740,6 +748,7 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
const int mask = hdr->huffman_mask_;
assert(htree_group != NULL);
+ assert(pos < end);
assert(last_row <= height);
assert(Is8bOptimizable(hdr));
@@ -793,6 +802,7 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
ok = 0;
goto End;
}
+ assert(br->eos_ == VP8LIsEndOfStream(br));
ok = !br->error_;
if (!ok) goto End;
}
@@ -830,6 +840,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
(hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
const int mask = hdr->huffman_mask_;
assert(htree_group != NULL);
+ assert(src < src_end);
assert(src_last <= src_end);
while (!br->eos_ && src < src_last) {
@@ -849,7 +860,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
VP8LFillBitWindow(br);
blue = ReadSymbol(&htree_group->htrees_[BLUE], br);
alpha = ReadSymbol(&htree_group->htrees_[ALPHA], br);
- *src = (alpha << 24) | (red << 16) | (green << 8) | blue;
+ *src = ((uint32_t)alpha << 24) | (red << 16) | (green << 8) | blue;
AdvanceByOne:
++src;
++col;
@@ -889,7 +900,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
process_func(dec, row);
}
}
- if (src < src_last) {
+ if (src < src_end) {
if (col & mask) htree_group = GetHtreeGroupForPos(hdr, col, row);
if (color_cache != NULL) {
while (last_cached < src) {
@@ -909,6 +920,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
ok = 0;
goto End;
}
+ assert(br->eos_ == VP8LIsEndOfStream(br));
ok = !br->error_;
if (!ok) goto End;
}
@@ -931,7 +943,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
// VP8LTransform
static void ClearTransform(VP8LTransform* const transform) {
- free(transform->data_);
+ WebPSafeFree(transform->data_);
transform->data_ = NULL;
}
@@ -955,7 +967,7 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
}
for (; i < 4 * final_num_colors; ++i)
new_data[i] = 0; // black tail.
- free(transform->data_);
+ WebPSafeFree(transform->data_);
transform->data_ = new_color_map;
}
return 1;
@@ -1025,8 +1037,8 @@ static void InitMetadata(VP8LMetadata* const hdr) {
static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr);
- free(hdr->huffman_image_);
- DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_);
+ WebPSafeFree(hdr->huffman_image_);
+ VP8LHtreeGroupsFree(hdr->htree_groups_, hdr->num_htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_);
InitMetadata(hdr);
}
@@ -1035,7 +1047,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
// VP8LDecoder
VP8LDecoder* VP8LNew(void) {
- VP8LDecoder* const dec = (VP8LDecoder*)calloc(1, sizeof(*dec));
+ VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec == NULL) return NULL;
dec->status_ = VP8_STATUS_OK;
dec->action_ = READ_DIM;
@@ -1051,7 +1063,7 @@ void VP8LClear(VP8LDecoder* const dec) {
if (dec == NULL) return;
ClearMetadata(&dec->hdr_);
- free(dec->pixels_);
+ WebPSafeFree(dec->pixels_);
dec->pixels_ = NULL;
for (i = 0; i < dec->next_transform_; ++i) {
ClearTransform(&dec->transforms_[i]);
@@ -1059,7 +1071,7 @@ void VP8LClear(VP8LDecoder* const dec) {
dec->next_transform_ = 0;
dec->transforms_seen_ = 0;
- free(dec->rescaler_memory);
+ WebPSafeFree(dec->rescaler_memory);
dec->rescaler_memory = NULL;
dec->output_ = NULL; // leave no trace behind
@@ -1068,7 +1080,7 @@ void VP8LClear(VP8LDecoder* const dec) {
void VP8LDelete(VP8LDecoder* const dec) {
if (dec != NULL) {
VP8LClear(dec);
- free(dec);
+ WebPSafeFree(dec);
}
}
@@ -1155,7 +1167,7 @@ static int DecodeImageStream(int xsize, int ysize,
End:
if (!ok) {
- free(data);
+ WebPSafeFree(data);
ClearMetadata(hdr);
// If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the
// status appropriately.
@@ -1294,6 +1306,10 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
assert(dec->action_ == READ_DATA);
assert(last_row <= dec->height_);
+ if (dec->last_pixel_ == dec->width_ * dec->height_) {
+ return 1; // done
+ }
+
// Decode (with special row processing).
return alph_dec->use_8b_decode ?
DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
@@ -1341,6 +1357,10 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
// Sanity checks.
if (dec == NULL) return 0;
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ assert(dec->hdr_.htree_groups_ != NULL);
+ assert(dec->hdr_.num_htree_groups_ > 0);
+
io = dec->io_;
assert(io != NULL);
params = (WebPDecParams*)io->opaque;
@@ -1358,6 +1378,11 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
+ if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
+ // need the alpha-multiply functions for premultiplied output or rescaling
+ WebPInitAlphaProcessing();
+ }
+
// Decode.
dec->action_ = READ_DATA;
if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
@@ -1377,4 +1402,3 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
}
//------------------------------------------------------------------------------
-