mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
Merge "make error-code reporting consistent upon malloc failure"
This commit is contained in:
commit
790207679d
@ -933,7 +933,8 @@ static double ComputeCacheEntropy(const uint32_t* const argb,
|
||||
return entropy;
|
||||
}
|
||||
|
||||
// Returns how many bits are to be used for a color cache.
|
||||
// *best_cache_bits will contain how many bits are to be used for a color cache.
|
||||
// Returns 0 in case of memory error.
|
||||
int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
|
||||
int xsize, int ysize, int quality,
|
||||
VP8LHashChain* const hash_chain,
|
||||
|
@ -398,8 +398,8 @@ static void RecordResiduals(VP8EncIterator* const it,
|
||||
|
||||
#if !defined(DISABLE_TOKEN_BUFFER)
|
||||
|
||||
static void RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd,
|
||||
VP8TBuffer* const tokens) {
|
||||
static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd,
|
||||
VP8TBuffer* const tokens) {
|
||||
int x, y, ch;
|
||||
VP8Residual res;
|
||||
VP8Encoder* const enc = it->enc_;
|
||||
@ -445,6 +445,7 @@ static void RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd,
|
||||
}
|
||||
}
|
||||
VP8IteratorBytesToNz(it);
|
||||
return !tokens->error_;
|
||||
}
|
||||
|
||||
#endif // !DISABLE_TOKEN_BUFFER
|
||||
@ -651,7 +652,10 @@ static int PreLoopInitialize(VP8Encoder* const enc) {
|
||||
for (p = 0; ok && p < enc->num_parts_; ++p) {
|
||||
ok = VP8BitWriterInit(enc->parts_ + p, bytes_per_parts);
|
||||
}
|
||||
if (!ok) VP8EncFreeBitWriters(enc); // malloc error occurred
|
||||
if (!ok) {
|
||||
VP8EncFreeBitWriters(enc); // malloc error occurred
|
||||
WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -780,7 +784,11 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
|
||||
cnt = max_count;
|
||||
}
|
||||
VP8Decimate(&it, &info, rd_opt);
|
||||
RecordTokens(&it, &info, &enc->tokens_);
|
||||
ok = RecordTokens(&it, &info, &enc->tokens_);
|
||||
if (!ok) {
|
||||
WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
break;
|
||||
}
|
||||
size_p0 += info.H;
|
||||
distortion += info.D;
|
||||
if (is_last_pass) {
|
||||
|
@ -263,13 +263,15 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static size_t GeneratePartition0(VP8Encoder* const enc) {
|
||||
static int GeneratePartition0(VP8Encoder* const enc) {
|
||||
VP8BitWriter* const bw = &enc->bw_;
|
||||
const int mb_size = enc->mb_w_ * enc->mb_h_;
|
||||
uint64_t pos1, pos2, pos3;
|
||||
|
||||
pos1 = VP8BitWriterPos(bw);
|
||||
VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock
|
||||
if (!VP8BitWriterInit(bw, mb_size * 7 / 8)) { // ~7 bits per macroblock
|
||||
return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
VP8PutBitUniform(bw, 0); // colorspace
|
||||
VP8PutBitUniform(bw, 0); // clamp type
|
||||
|
||||
@ -292,7 +294,10 @@ static size_t GeneratePartition0(VP8Encoder* const enc) {
|
||||
enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
|
||||
enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_;
|
||||
}
|
||||
return !bw->error_;
|
||||
if (bw->error_) {
|
||||
return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VP8EncFreeBitWriters(VP8Encoder* const enc) {
|
||||
@ -314,7 +319,8 @@ int VP8EncWrite(VP8Encoder* const enc) {
|
||||
int p;
|
||||
|
||||
// Partition #0 with header and partition sizes
|
||||
ok = !!GeneratePartition0(enc);
|
||||
ok = GeneratePartition0(enc);
|
||||
if (!ok) return 0;
|
||||
|
||||
// Compute VP8 size
|
||||
vp8_size = VP8_FRAME_HEADER_SIZE +
|
||||
|
@ -225,7 +225,7 @@ int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
|
||||
const uint8_t* const probas, int final_pass) {
|
||||
const VP8Tokens* p = b->pages_;
|
||||
(void)final_pass;
|
||||
if (b->error_) return 0;
|
||||
assert(!b->error_);
|
||||
while (p != NULL) {
|
||||
const VP8Tokens* const next = p->next_;
|
||||
const int N = (next == NULL) ? b->left_ : 0;
|
||||
@ -251,7 +251,7 @@ int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
|
||||
size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) {
|
||||
size_t size = 0;
|
||||
const VP8Tokens* p = b->pages_;
|
||||
if (b->error_) return 0;
|
||||
assert(!b->error_);
|
||||
while (p != NULL) {
|
||||
const VP8Tokens* const next = p->next_;
|
||||
const int N = (next == NULL) ? b->left_ : 0;
|
||||
|
154
src/enc/vp8l.c
154
src/enc/vp8l.c
@ -181,6 +181,7 @@ static int AnalyzeAndInit(VP8LEncoder* const enc, WebPImageHint image_hint) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns false in case of memory error.
|
||||
static int GetHuffBitLengthsAndCodes(
|
||||
const VP8LHistogramSet* const histogram_image,
|
||||
HuffmanTreeCode* const huffman_codes) {
|
||||
@ -426,7 +427,7 @@ static void WriteHuffmanCode(VP8LBitWriter* const bw,
|
||||
VP8LWriteBits(bw, depth, symbol);
|
||||
}
|
||||
|
||||
static void StoreImageToBitMask(
|
||||
static WebPEncodingError StoreImageToBitMask(
|
||||
VP8LBitWriter* const bw, int width, int histo_bits,
|
||||
VP8LBackwardRefs* const refs,
|
||||
const uint16_t* histogram_symbols,
|
||||
@ -473,17 +474,19 @@ static void StoreImageToBitMask(
|
||||
}
|
||||
VP8LRefsCursorNext(&c);
|
||||
}
|
||||
return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK;
|
||||
}
|
||||
|
||||
// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
|
||||
static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
|
||||
const uint32_t* const argb,
|
||||
VP8LHashChain* const hash_chain,
|
||||
VP8LBackwardRefs refs_array[2],
|
||||
int width, int height, int quality) {
|
||||
static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
|
||||
const uint32_t* const argb,
|
||||
VP8LHashChain* const hash_chain,
|
||||
VP8LBackwardRefs refs_array[2],
|
||||
int width, int height,
|
||||
int quality) {
|
||||
int i;
|
||||
int ok = 0;
|
||||
int max_tokens = 0;
|
||||
WebPEncodingError err = VP8_ENC_OK;
|
||||
VP8LBackwardRefs* refs;
|
||||
HuffmanTreeToken* tokens = NULL;
|
||||
HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
|
||||
@ -491,12 +494,16 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
|
||||
VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0);
|
||||
HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
|
||||
3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
|
||||
if (histogram_image == NULL || huff_tree == NULL) goto Error;
|
||||
if (histogram_image == NULL || huff_tree == NULL) {
|
||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// Calculate backward references from ARGB image.
|
||||
refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, 1,
|
||||
hash_chain, refs_array);
|
||||
if (refs == NULL) {
|
||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
// Build histogram image and symbols from backward references.
|
||||
@ -505,6 +512,7 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
|
||||
// Create Huffman bit lengths and codes for each histogram image.
|
||||
assert(histogram_image->size == 1);
|
||||
if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
|
||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
@ -520,7 +528,10 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
|
||||
}
|
||||
|
||||
tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
|
||||
if (tokens == NULL) goto Error;
|
||||
if (tokens == NULL) {
|
||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// Store Huffman codes.
|
||||
for (i = 0; i < 5; ++i) {
|
||||
@ -530,24 +541,25 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
|
||||
}
|
||||
|
||||
// Store actual literals.
|
||||
StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, huffman_codes);
|
||||
ok = 1;
|
||||
err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols,
|
||||
huffman_codes);
|
||||
|
||||
Error:
|
||||
WebPSafeFree(tokens);
|
||||
WebPSafeFree(huff_tree);
|
||||
VP8LFreeHistogramSet(histogram_image);
|
||||
WebPSafeFree(huffman_codes[0].codes);
|
||||
return ok;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
const uint32_t* const argb,
|
||||
VP8LHashChain* const hash_chain,
|
||||
VP8LBackwardRefs refs_array[2],
|
||||
int width, int height, int quality,
|
||||
int cache_bits, int histogram_bits) {
|
||||
int ok = 0;
|
||||
static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
const uint32_t* const argb,
|
||||
VP8LHashChain* const hash_chain,
|
||||
VP8LBackwardRefs refs_array[2],
|
||||
int width, int height, int quality,
|
||||
int cache_bits,
|
||||
int histogram_bits) {
|
||||
WebPEncodingError err = VP8_ENC_OK;
|
||||
const int use_2d_locality = 1;
|
||||
const int use_color_cache = (cache_bits > 0);
|
||||
const uint32_t histogram_image_xysize =
|
||||
@ -631,12 +643,12 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
histogram_image_size = max_index;
|
||||
|
||||
VP8LWriteBits(bw, 3, histogram_bits - 2);
|
||||
ok = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array,
|
||||
VP8LSubSampleSize(width, histogram_bits),
|
||||
VP8LSubSampleSize(height, histogram_bits),
|
||||
quality);
|
||||
err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array,
|
||||
VP8LSubSampleSize(width, histogram_bits),
|
||||
VP8LSubSampleSize(height, histogram_bits),
|
||||
quality);
|
||||
WebPSafeFree(histogram_argb);
|
||||
if (!ok) goto Error;
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -665,9 +677,8 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
}
|
||||
|
||||
// Store actual literals.
|
||||
StoreImageToBitMask(bw, width, histogram_bits, &refs,
|
||||
histogram_symbols, huffman_codes);
|
||||
ok = 1;
|
||||
err = StoreImageToBitMask(bw, width, histogram_bits, &refs,
|
||||
histogram_symbols, huffman_codes);
|
||||
|
||||
Error:
|
||||
WebPSafeFree(tokens);
|
||||
@ -679,7 +690,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
WebPSafeFree(huffman_codes);
|
||||
}
|
||||
WebPSafeFree(histogram_symbols);
|
||||
return ok;
|
||||
return err;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -687,16 +698,16 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
||||
|
||||
// Check if it would be a good idea to subtract green from red and blue. We
|
||||
// only impact entropy in red/blue components, don't bother to look at others.
|
||||
static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
|
||||
int width, int height,
|
||||
VP8LBitWriter* const bw) {
|
||||
static WebPEncodingError EvalAndApplySubtractGreen(VP8LEncoder* const enc,
|
||||
int width, int height,
|
||||
VP8LBitWriter* const bw) {
|
||||
if (!enc->use_palette_) {
|
||||
int i;
|
||||
const uint32_t* const argb = enc->argb_;
|
||||
double bit_cost_before, bit_cost_after;
|
||||
// Allocate histogram with cache_bits = 1.
|
||||
VP8LHistogram* const histo = VP8LAllocateHistogram(1);
|
||||
if (histo == NULL) return 0;
|
||||
if (histo == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
for (i = 0; i < width * height; ++i) {
|
||||
const uint32_t c = argb[i];
|
||||
++histo->red_[(c >> 16) & 0xff];
|
||||
@ -722,12 +733,12 @@ static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
|
||||
VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
static int ApplyPredictFilter(const VP8LEncoder* const enc,
|
||||
int width, int height, int quality,
|
||||
VP8LBitWriter* const bw) {
|
||||
static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
|
||||
int width, int height, int quality,
|
||||
VP8LBitWriter* const bw) {
|
||||
const int pred_bits = enc->transform_bits_;
|
||||
const int transform_width = VP8LSubSampleSize(width, pred_bits);
|
||||
const int transform_height = VP8LSubSampleSize(height, pred_bits);
|
||||
@ -738,19 +749,17 @@ static int ApplyPredictFilter(const VP8LEncoder* const enc,
|
||||
VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
|
||||
assert(pred_bits >= 2);
|
||||
VP8LWriteBits(bw, 3, pred_bits - 2);
|
||||
if (!EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||
(VP8LHashChain*)&enc->hash_chain_,
|
||||
(VP8LBackwardRefs*)enc->refs_, // cast const away
|
||||
transform_width, transform_height,
|
||||
quality)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||
(VP8LHashChain*)&enc->hash_chain_,
|
||||
(VP8LBackwardRefs*)enc->refs_, // cast const away
|
||||
transform_width, transform_height,
|
||||
quality);
|
||||
}
|
||||
|
||||
static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
|
||||
int width, int height, int quality,
|
||||
VP8LBitWriter* const bw) {
|
||||
static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
|
||||
int width, int height,
|
||||
int quality,
|
||||
VP8LBitWriter* const bw) {
|
||||
const int ccolor_transform_bits = enc->transform_bits_;
|
||||
const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
|
||||
const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
|
||||
@ -761,14 +770,11 @@ static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
|
||||
VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
|
||||
assert(ccolor_transform_bits >= 2);
|
||||
VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
|
||||
if (!EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||
(VP8LHashChain*)&enc->hash_chain_,
|
||||
(VP8LBackwardRefs*)enc->refs_, // cast const away
|
||||
transform_width, transform_height,
|
||||
quality)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return EncodeImageNoHuffman(bw, enc->transform_data_,
|
||||
(VP8LHashChain*)&enc->hash_chain_,
|
||||
(VP8LBackwardRefs*)enc->refs_, // cast const away
|
||||
transform_width, transform_height,
|
||||
quality);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -963,11 +969,8 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
|
||||
for (i = palette_size - 1; i >= 1; --i) {
|
||||
palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
|
||||
}
|
||||
if (!EncodeImageNoHuffman(bw, palette, &enc->hash_chain_, enc->refs_,
|
||||
palette_size, 1, quality)) {
|
||||
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||
goto Error;
|
||||
}
|
||||
err = EncodeImageNoHuffman(bw, palette, &enc->hash_chain_, enc->refs_,
|
||||
palette_size, 1, quality);
|
||||
|
||||
Error:
|
||||
WebPSafeFree(row);
|
||||
@ -1089,23 +1092,17 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
||||
// ---------------------------------------------------------------------------
|
||||
// Apply transforms and write transform data.
|
||||
|
||||
if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw)) {
|
||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
err = EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
|
||||
if (enc->use_predict_) {
|
||||
if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, bw)) {
|
||||
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||
goto Error;
|
||||
}
|
||||
err = ApplyPredictFilter(enc, enc->current_width_, height, quality, bw);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
}
|
||||
|
||||
if (enc->use_cross_color_) {
|
||||
if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) {
|
||||
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||
goto Error;
|
||||
}
|
||||
err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
}
|
||||
|
||||
VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
|
||||
@ -1117,7 +1114,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
||||
if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
|
||||
height, quality, &enc->hash_chain_,
|
||||
&enc->refs_[0], &enc->cache_bits_)) {
|
||||
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
@ -1125,12 +1122,10 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
||||
// ---------------------------------------------------------------------------
|
||||
// Encode and write the transformed image.
|
||||
|
||||
if (!EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
|
||||
enc->current_width_, height, quality,
|
||||
enc->cache_bits_, enc->histo_bits_)) {
|
||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
|
||||
enc->current_width_, height, quality,
|
||||
enc->cache_bits_, enc->histo_bits_);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
|
||||
if (picture->stats != NULL) {
|
||||
WebPAuxStats* const stats = picture->stats;
|
||||
@ -1247,4 +1242,3 @@ int VP8LEncodeImage(const WebPConfig* const config,
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user