add VP8LEncodeStream() to compress lossless image stream

* RIFF header is omitted
* rename NewVP8LEncoder and DeleteVP8Encoder
* change the signature to take a "const WebPPicture*"
  (it was non-const just because we were setting some error potentially)
* made the pic_ field const in VP8LEncoder too.
* trap the bitwriter::error_ too
* simplify some signatures to take WebPPicture* instead
  of unneeded VP8LEncoder*

VP8LEncodeStream() will be called directly to compress alpha channel
header-less.

Change-Id: Ibceef63d2b3fbc412f0dffc38dc05c2dee6b6bbf
This commit is contained in:
Pascal Massimino 2012-05-22 03:15:58 -07:00
parent fa8bc3dbca
commit 489ec335a1
2 changed files with 70 additions and 53 deletions

View File

@ -638,9 +638,8 @@ static void PutLE32(uint8_t* const data, uint32_t val) {
data[3] = (val >> 24) & 0xff; data[3] = (val >> 24) & 0xff;
} }
static WebPEncodingError WriteRiffHeader(const VP8LEncoder* const enc, static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
size_t riff_size, size_t vp8l_size) { size_t riff_size, size_t vp8l_size) {
const WebPPicture* const pic = enc->pic_;
uint8_t riff[HEADER_SIZE + SIGNATURE_SIZE] = { uint8_t riff[HEADER_SIZE + SIGNATURE_SIZE] = {
'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
'V', 'P', '8', 'L', 0, 0, 0, 0, LOSSLESS_MAGIC_BYTE, 'V', 'P', '8', 'L', 0, 0, 0, 0, LOSSLESS_MAGIC_BYTE,
@ -653,20 +652,20 @@ static WebPEncodingError WriteRiffHeader(const VP8LEncoder* const enc,
return VP8_ENC_OK; return VP8_ENC_OK;
} }
static void WriteImageSize(VP8LEncoder* const enc, VP8LBitWriter* const bw) { static int WriteImageSize(const WebPPicture* const pic,
WebPPicture* const pic = enc->pic_; VP8LBitWriter* const bw) {
const int width = pic->width - 1; const int width = pic->width - 1;
const int height = pic->height -1; const int height = pic->height -1;
assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION); assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
VP8LWriteBits(bw, IMAGE_SIZE_BITS, width); VP8LWriteBits(bw, IMAGE_SIZE_BITS, width);
VP8LWriteBits(bw, IMAGE_SIZE_BITS, height); VP8LWriteBits(bw, IMAGE_SIZE_BITS, height);
return !bw->error_;
} }
static WebPEncodingError WriteImage(const VP8LEncoder* const enc, static WebPEncodingError WriteImage(const WebPPicture* const pic,
VP8LBitWriter* const bw, VP8LBitWriter* const bw,
size_t* const coded_size) { size_t* const coded_size) {
const WebPPicture* const pic = enc->pic_;
WebPEncodingError err = VP8_ENC_OK; WebPEncodingError err = VP8_ENC_OK;
const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
const size_t webpll_size = VP8LBitWriterNumBytes(bw); const size_t webpll_size = VP8LBitWriterNumBytes(bw);
@ -674,7 +673,7 @@ static WebPEncodingError WriteImage(const VP8LEncoder* const enc,
const size_t pad = vp8l_size & 1; const size_t pad = vp8l_size & 1;
const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad; const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
err = WriteRiffHeader(enc, riff_size, vp8l_size); err = WriteRiffHeader(pic, riff_size, vp8l_size);
if (err != VP8_ENC_OK) goto Error; if (err != VP8_ENC_OK) goto Error;
if (!pic->writer(webpll_data, webpll_size, pic)) { if (!pic->writer(webpll_data, webpll_size, pic)) {
@ -835,8 +834,8 @@ static void InitEncParams(VP8LEncoder* const enc) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// VP8LEncoder // VP8LEncoder
static VP8LEncoder* NewVP8LEncoder(const WebPConfig* const config, static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
WebPPicture* const picture) { const WebPPicture* const picture) {
VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc)); VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc));
if (enc == NULL) { if (enc == NULL) {
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
@ -847,7 +846,7 @@ static VP8LEncoder* NewVP8LEncoder(const WebPConfig* const config,
return enc; return enc;
} }
static void DeleteVP8LEncoder(VP8LEncoder* enc) { static void VP8LEncoderDelete(VP8LEncoder* enc) {
free(enc->argb_); free(enc->argb_);
free(enc); free(enc);
} }
@ -855,30 +854,19 @@ static void DeleteVP8LEncoder(VP8LEncoder* enc) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Main call // Main call
int VP8LEncodeImage(const WebPConfig* const config, WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
WebPPicture* const picture) { const WebPPicture* const picture,
int ok = 0; VP8LBitWriter* const bw) {
int width, height, quality;
size_t coded_size;
VP8LEncoder* enc = NULL;
WebPEncodingError err = VP8_ENC_OK; WebPEncodingError err = VP8_ENC_OK;
VP8LBitWriter bw; const int quality = config->quality;
const int width = picture->width;
const int height = picture->height;
VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
if (config == NULL || picture == NULL) return 0;
if (picture->argb == NULL) {
err = VP8_ENC_ERROR_NULL_PARAMETER;
goto Error;
}
enc = NewVP8LEncoder(config, picture);
if (enc == NULL) { if (enc == NULL) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY; err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error; goto Error;
} }
width = picture->width;
height = picture->height;
quality = config->quality;
InitEncParams(enc); InitEncParams(enc);
@ -890,12 +878,8 @@ int VP8LEncodeImage(const WebPConfig* const config,
goto Error; goto Error;
} }
// Write image size.
VP8LBitWriterInit(&bw, (width * height) >> 1);
WriteImageSize(enc, &bw);
if (enc->use_palette_) { if (enc->use_palette_) {
err = ApplyPalette(&bw, enc, width, height, quality); err = ApplyPalette(bw, enc, width, height, quality);
if (err != VP8_ENC_OK) goto Error; if (err != VP8_ENC_OK) goto Error;
enc->cache_bits_ = 0; enc->cache_bits_ = 0;
} }
@ -912,27 +896,26 @@ int VP8LEncodeImage(const WebPConfig* const config,
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Apply transforms and write transform data. // Apply transforms and write transform data.
if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, &bw)) { if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw)) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY; err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error; goto Error;
} }
if (enc->use_predict_) { if (enc->use_predict_) {
if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, &bw)) { if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, bw)) {
err = VP8_ENC_ERROR_INVALID_CONFIGURATION; err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
goto Error; goto Error;
} }
} }
if (enc->use_cross_color_) { if (enc->use_cross_color_) {
if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) {
&bw)) {
err = VP8_ENC_ERROR_INVALID_CONFIGURATION; err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
goto Error; goto Error;
} }
} }
VP8LWriteBits(&bw, 1, !TRANSFORM_PRESENT); // No more transforms. VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Estimate the color cache size. // Estimate the color cache size.
@ -948,16 +931,47 @@ int VP8LEncodeImage(const WebPConfig* const config,
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Encode and write the transformed image. // Encode and write the transformed image.
ok = EncodeImageInternal(&bw, enc->argb_, enc->current_width_, height, if (!EncodeImageInternal(bw, enc->argb_, enc->current_width_, height,
quality, enc->cache_bits_, enc->histo_bits_); quality, enc->cache_bits_, enc->histo_bits_)) {
if (!ok) goto Error; err = VP8_ENC_ERROR_OUT_OF_MEMORY;
err = WriteImage(enc, &bw, &coded_size);
if (err != VP8_ENC_OK) {
ok = 0;
goto Error; goto Error;
} }
Error:
VP8LEncoderDelete(enc);
return err;
}
int VP8LEncodeImage(const WebPConfig* const config,
const WebPPicture* const picture) {
int width, height;
size_t coded_size;
WebPEncodingError err = VP8_ENC_OK;
VP8LBitWriter bw;
if (picture == NULL) return 0;
if (config == NULL || picture->argb == NULL) {
err = VP8_ENC_ERROR_NULL_PARAMETER;
goto Error;
}
width = picture->width;
height = picture->height;
// Write image size.
VP8LBitWriterInit(&bw, (width * height) >> 1);
if (!WriteImageSize(picture, &bw)) goto Error;
// Encode main image stream.
err = VP8LEncodeStream(config, picture, &bw);
if (err != VP8_ENC_OK) goto Error;
// Finish the RIFF chunk.
err = WriteImage(picture, &bw, &coded_size);
if (err != VP8_ENC_OK) goto Error;
// Collect some stats if needed.
if (picture->stats != NULL) { if (picture->stats != NULL) {
WebPAuxStats* const stats = picture->stats; WebPAuxStats* const stats = picture->stats;
memset(stats, 0, sizeof(*stats)); memset(stats, 0, sizeof(*stats));
@ -975,13 +989,13 @@ int VP8LEncodeImage(const WebPConfig* const config,
} }
Error: Error:
if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
VP8LBitWriterDestroy(&bw); VP8LBitWriterDestroy(&bw);
DeleteVP8LEncoder(enc); if (err != VP8_ENC_OK) {
if (!ok) {
assert(err != VP8_ENC_OK);
WebPEncodingSetError(picture, err); WebPEncodingSetError(picture, err);
return 0;
} }
return ok; return 1;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -35,7 +35,7 @@ extern "C" {
typedef struct { typedef struct {
const WebPConfig* config_; // user configuration and parameters const WebPConfig* config_; // user configuration and parameters
WebPPicture* pic_; // input picture. const WebPPicture* pic_; // input picture.
uint32_t* argb_; // Transformed argb image data. uint32_t* argb_; // Transformed argb image data.
uint32_t* argb_scratch_; // Scratch memory for argb rows uint32_t* argb_scratch_; // Scratch memory for argb rows
@ -59,13 +59,16 @@ typedef struct {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// internal functions. Not public. // internal functions. Not public.
// in vp8l.c
// Encodes the picture. // Encodes the picture.
// Returns 0 if config or picture is NULL or picture doesn't have valid argb // Returns 0 if config or picture is NULL or picture doesn't have valid argb
// input. // input.
int VP8LEncodeImage(const WebPConfig* const config, int VP8LEncodeImage(const WebPConfig* const config,
WebPPicture* const picture); const WebPPicture* const picture);
// Encodes the main image stream using the supplied bit writer.
WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture,
VP8LBitWriter* const bw);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------