alpha: preparatory cleanup

* make ALPHNew/Delete static
* properly init ALPHDec::io_
* introduce AllocateAlphaPlane() and WebPDeallocateAlphaMemory()
* reorganize VP8DecompressAlphaRows()

but we're still allocate the full alpha-plane. Optim will come
in another patch since it's tricky

Change-Id: Ib6f190a40abb7926a71535b0ed67c39d0974e06a
This commit is contained in:
Pascal Massimino 2016-04-04 15:50:57 +02:00
parent b95ac0a221
commit cf6c713a0b
4 changed files with 74 additions and 37 deletions

View File

@ -23,12 +23,14 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// ALPHDecoder object. // ALPHDecoder object.
ALPHDecoder* ALPHNew(void) { // Allocates a new alpha decoder instance.
static ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec; return dec;
} }
void ALPHDelete(ALPHDecoder* const dec) { // Clears and deallocates an alpha decoder instance.
static void ALPHDelete(ALPHDecoder* const dec) {
if (dec != NULL) { if (dec != NULL) {
VP8LDelete(dec->vp8l_dec_); VP8LDelete(dec->vp8l_dec_);
dec->vp8l_dec_ = NULL; dec->vp8l_dec_ = NULL;
@ -44,17 +46,19 @@ void ALPHDelete(ALPHDecoder* const dec) {
// Returns false in case of error in alpha header (data too short, invalid // Returns false in case of error in alpha header (data too short, invalid
// compression method or filter, error in lossless header data etc). // compression method or filter, error in lossless header data etc).
static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
size_t data_size, int width, int height, uint8_t* output) { size_t data_size, const VP8Io* const src_io,
uint8_t* output) {
int ok = 0; int ok = 0;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN; const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN; const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
int rsrv; int rsrv;
VP8Io* const io = &dec->io_;
assert(width > 0 && height > 0); assert(data != NULL && output != NULL && src_io != NULL);
assert(data != NULL && output != NULL);
dec->width_ = width; dec->width_ = src_io->width;
dec->height_ = height; dec->height_ = src_io->height;
assert(dec->width_ > 0 && dec->height_ > 0);
if (data_size <= ALPHA_HEADER_LEN) { if (data_size <= ALPHA_HEADER_LEN) {
return 0; return 0;
@ -80,6 +84,21 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size, output); ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size, output);
} }
VP8FiltersInit(); VP8FiltersInit();
// Copy the necessary parameters from src_io to io
VP8InitIo(io);
WebPInitCustomIo(NULL, io);
io->opaque = output; // output plane
io->width = src_io->width;
io->height = src_io->height;
io->use_cropping = src_io->use_cropping;
io->crop_left = src_io->crop_left;
io->crop_right = src_io->crop_right;
io->crop_top = src_io->crop_top;
io->crop_bottom = src_io->crop_bottom;
// No need to copy the scaling parameters.
return ok; return ok;
} }
@ -116,6 +135,27 @@ static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
return 1; return 1;
} }
static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
const int stride = io->width;
const int height = io->height;
const uint64_t alpha_size = (uint64_t)stride * height;
assert(dec->alpha_plane_mem_ == NULL);
dec->alpha_plane_mem_ =
(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));
if (dec->alpha_plane_mem_ == NULL) return 0;
dec->alpha_plane_ = dec->alpha_plane_mem_;
return 1;
}
void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
assert(dec != NULL);
WebPSafeFree(dec->alpha_plane_mem_);
dec->alpha_plane_mem_ = NULL;
dec->alpha_plane_ = NULL;
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main entry point. // Main entry point.
@ -132,41 +172,42 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
} }
if (!dec->is_alpha_decoded_) { if (!dec->is_alpha_decoded_) {
int ok;
if (dec->alph_dec_ == NULL) { // Initialize decoder. if (dec->alph_dec_ == NULL) { // Initialize decoder.
assert(dec->alpha_plane_ != NULL);
dec->alph_dec_ = ALPHNew(); dec->alph_dec_ = ALPHNew();
if (dec->alph_dec_ == NULL) return NULL; if (dec->alph_dec_ == NULL) return NULL;
if (!AllocateAlphaPlane(dec, io)) goto Error;
if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_, if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
io->width, io->height, dec->alpha_plane_)) { io, dec->alpha_plane_)) {
ALPHDelete(dec->alph_dec_); goto Error;
dec->alph_dec_ = NULL;
return NULL;
} }
// if we allowed use of alpha dithering, check whether it's needed at all // if we allowed use of alpha dithering, check whether it's needed at all
if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) { if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) {
dec->alpha_dithering_ = 0; // disable dithering dec->alpha_dithering_ = 0; // disable dithering
} else { } else {
num_rows = height; // decode everything in one pass num_rows = io->height - row; // decode everything in one pass
} }
} }
if (row + num_rows > height) {
num_rows = height - row;
}
ok = ALPHDecode(dec, row, num_rows);
assert(dec->alph_dec_ != NULL); assert(dec->alph_dec_ != NULL);
if (!ok || dec->is_alpha_decoded_) { assert(row + num_rows <= io->height);
if (!ALPHDecode(dec, row, num_rows)) goto Error;
if (dec->is_alpha_decoded_) { // finished?
ALPHDelete(dec->alph_dec_); ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL; dec->alph_dec_ = NULL;
if (dec->alpha_dithering_ > 0) {
if (!WebPDequantizeLevels(dec->alpha_plane_, width, height, width,
dec->alpha_dithering_)) {
goto Error;
}
}
} }
if (ok && dec->is_alpha_decoded_ && dec->alpha_dithering_ > 0) {
ok = WebPDequantizeLevels(dec->alpha_plane_, width, height, width,
dec->alpha_dithering_);
}
if (!ok) return NULL; // Error.
} }
// Return a pointer to the current decoded row. // Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * width; return dec->alpha_plane_ + row * width;
Error:
WebPDeallocateAlphaMemory(dec);
return NULL;
} }

View File

@ -40,11 +40,8 @@ struct ALPHDecoder {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// internal functions. Not public. // internal functions. Not public.
// Allocates a new alpha decoder instance. // Deallocate memory associated to dec->alpha_plane_ decoding
ALPHDecoder* ALPHNew(void); void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
// Clears and deallocates an alpha decoder instance.
void ALPHDelete(ALPHDecoder* const dec);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -656,8 +656,7 @@ void VP8Clear(VP8Decoder* const dec) {
return; return;
} }
WebPGetWorkerInterface()->End(&dec->worker_); WebPGetWorkerInterface()->End(&dec->worker_);
ALPHDelete(dec->alph_dec_); WebPDeallocateAlphaMemory(dec);
dec->alph_dec_ = NULL;
WebPSafeFree(dec->mem_); WebPSafeFree(dec->mem_);
dec->mem_ = NULL; dec->mem_ = NULL;
dec->mem_size_ = 0; dec->mem_size_ = 0;
@ -666,4 +665,3 @@ void VP8Clear(VP8Decoder* const dec) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -258,9 +258,10 @@ struct VP8Decoder {
struct ALPHDecoder* alph_dec_; // alpha-plane decoder object struct ALPHDecoder* alph_dec_; // alpha-plane decoder object
const uint8_t* alpha_data_; // compressed alpha data (if present) const uint8_t* alpha_data_; // compressed alpha data (if present)
size_t alpha_data_size_; size_t alpha_data_size_;
int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_ int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_
uint8_t* alpha_plane_; // output. Persistent, contains the whole data. uint8_t* alpha_plane_mem_; // memory allocated for alpha_plane_
int alpha_dithering_; // derived from decoding options (0=off, 100=full). uint8_t* alpha_plane_; // output. Persistent, contains the whole data.
int alpha_dithering_; // derived from decoding options (0=off, 100=full)
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------