Merge "Alpha decoding: significantly reduce memory usage"

This commit is contained in:
pascal massimino 2013-05-07 09:14:56 -07:00 committed by Gerrit Code Review
commit 55d1c150ea

View File

@ -20,20 +20,10 @@
extern "C" { extern "C" {
#endif #endif
// TODO(skal): move to dsp/ ?
static void CopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, int width, int height) {
while (height-- > 0) {
memcpy(dst, src, width);
src += src_stride;
dst += dst_stride;
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Decodes the compressed data 'data' of size 'data_size' into the 'output'. // Decodes the compressed data 'data' of size 'data_size' into the 'output'.
// The 'output' buffer should be pre-allocated and must be of the same // The 'output' buffer should be pre-allocated and must be of the same
// dimension 'height'x'stride', as that of the image. // dimension 'height'x'width', as that of the image.
// //
// Returns 1 on successfully decoding the compressed alpha and // Returns 1 on successfully decoding the compressed alpha and
// 0 if either: // 0 if either:
@ -41,16 +31,16 @@ static void CopyPlane(const uint8_t* src, int src_stride,
// error returned by appropriate compression method. // error returned by appropriate compression method.
static int DecodeAlpha(const uint8_t* data, size_t data_size, static int DecodeAlpha(const uint8_t* data, size_t data_size,
int width, int height, int stride, uint8_t* output) { int width, int height, uint8_t* output) {
uint8_t* decoded_data = NULL;
const size_t decoded_size = height * width;
WEBP_FILTER_TYPE filter; WEBP_FILTER_TYPE filter;
int pre_processing; int pre_processing;
int rsrv; int rsrv;
int ok = 0; int ok = 0;
int method; int method;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
assert(width > 0 && height > 0 && stride >= width); assert(width > 0 && height > 0);
assert(data != NULL && output != NULL); assert(data != NULL && output != NULL);
if (data_size <= ALPHA_HEADER_LEN) { if (data_size <= ALPHA_HEADER_LEN) {
@ -70,15 +60,12 @@ static int DecodeAlpha(const uint8_t* data, size_t data_size,
} }
if (method == ALPHA_NO_COMPRESSION) { if (method == ALPHA_NO_COMPRESSION) {
ok = (data_size >= decoded_size); const size_t alpha_decoded_size = height * width;
decoded_data = (uint8_t*)data + ALPHA_HEADER_LEN; ok = (alpha_data_size >= alpha_decoded_size);
if (ok) memcpy(output, alpha_data, alpha_decoded_size);
} else { } else {
decoded_data = (uint8_t*)malloc(decoded_size); ok = VP8LDecodeAlphaImageStream(width, height, alpha_data, alpha_data_size,
if (decoded_data == NULL) return 0; output);
ok = VP8LDecodeAlphaImageStream(width, height,
data + ALPHA_HEADER_LEN,
data_size - ALPHA_HEADER_LEN,
decoded_data);
} }
if (ok) { if (ok) {
@ -86,18 +73,13 @@ static int DecodeAlpha(const uint8_t* data, size_t data_size,
if (unfilter_func != NULL) { if (unfilter_func != NULL) {
// TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode
// and apply filter per image-row. // and apply filter per image-row.
unfilter_func(width, height, width, decoded_data); unfilter_func(width, height, width, output);
} }
// Construct raw_data (height x stride) from alpha data (height x width).
CopyPlane(decoded_data, width, output, stride, width, height);
if (pre_processing == ALPHA_PREPROCESSED_LEVELS) { if (pre_processing == ALPHA_PREPROCESSED_LEVELS) {
ok = DequantizeLevels(decoded_data, width, height); ok = DequantizeLevels(output, width, height);
} }
} }
if (method != ALPHA_NO_COMPRESSION) {
free(decoded_data);
}
return ok; return ok;
} }
@ -105,9 +87,10 @@ static int DecodeAlpha(const uint8_t* data, size_t data_size,
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
int row, int num_rows) { int row, int num_rows) {
const int stride = dec->pic_hdr_.width_; const int width = dec->pic_hdr_.width_;
const int height = dec->pic_hdr_.height_;
if (row < 0 || num_rows < 0 || row + num_rows > dec->pic_hdr_.height_) { if (row < 0 || num_rows < 0 || row + num_rows > height) {
return NULL; // sanity check. return NULL; // sanity check.
} }
@ -115,15 +98,14 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
// Decode everything during the first call. // Decode everything during the first call.
assert(!dec->is_alpha_decoded_); assert(!dec->is_alpha_decoded_);
if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_, if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_,
dec->pic_hdr_.width_, dec->pic_hdr_.height_, stride, width, height, dec->alpha_plane_)) {
dec->alpha_plane_)) {
return NULL; // Error. return NULL; // Error.
} }
dec->is_alpha_decoded_ = 1; dec->is_alpha_decoded_ = 1;
} }
// Return a pointer to the current decoded row. // Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * stride; return dec->alpha_plane_ + row * width;
} }
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)