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;
}
static WebPEncodingError WriteRiffHeader(const VP8LEncoder* const enc,
static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
size_t riff_size, size_t vp8l_size) {
const WebPPicture* const pic = enc->pic_;
uint8_t riff[HEADER_SIZE + SIGNATURE_SIZE] = {
'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
'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;
}
static void WriteImageSize(VP8LEncoder* const enc, VP8LBitWriter* const bw) {
WebPPicture* const pic = enc->pic_;
static int WriteImageSize(const WebPPicture* const pic,
VP8LBitWriter* const bw) {
const int width = pic->width - 1;
const int height = pic->height -1;
assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
VP8LWriteBits(bw, IMAGE_SIZE_BITS, width);
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,
size_t* const coded_size) {
const WebPPicture* const pic = enc->pic_;
WebPEncodingError err = VP8_ENC_OK;
const uint8_t* const webpll_data = VP8LBitWriterFinish(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 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 (!pic->writer(webpll_data, webpll_size, pic)) {
@ -835,8 +834,8 @@ static void InitEncParams(VP8LEncoder* const enc) {
// -----------------------------------------------------------------------------
// VP8LEncoder
static VP8LEncoder* NewVP8LEncoder(const WebPConfig* const config,
WebPPicture* const picture) {
static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
const WebPPicture* const picture) {
VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc));
if (enc == NULL) {
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
@ -847,7 +846,7 @@ static VP8LEncoder* NewVP8LEncoder(const WebPConfig* const config,
return enc;
}
static void DeleteVP8LEncoder(VP8LEncoder* enc) {
static void VP8LEncoderDelete(VP8LEncoder* enc) {
free(enc->argb_);
free(enc);
}
@ -855,30 +854,19 @@ static void DeleteVP8LEncoder(VP8LEncoder* enc) {
// -----------------------------------------------------------------------------
// Main call
int VP8LEncodeImage(const WebPConfig* const config,
WebPPicture* const picture) {
int ok = 0;
int width, height, quality;
size_t coded_size;
VP8LEncoder* enc = NULL;
WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture,
VP8LBitWriter* const bw) {
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) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
width = picture->width;
height = picture->height;
quality = config->quality;
InitEncParams(enc);
@ -890,12 +878,8 @@ int VP8LEncodeImage(const WebPConfig* const config,
goto Error;
}
// Write image size.
VP8LBitWriterInit(&bw, (width * height) >> 1);
WriteImageSize(enc, &bw);
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;
enc->cache_bits_ = 0;
}
@ -912,27 +896,26 @@ int VP8LEncodeImage(const WebPConfig* const config,
// ---------------------------------------------------------------------------
// 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;
goto Error;
}
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;
goto Error;
}
}
if (enc->use_cross_color_) {
if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality,
&bw)) {
if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) {
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
goto Error;
}
}
VP8LWriteBits(&bw, 1, !TRANSFORM_PRESENT); // No more transforms.
VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
// ---------------------------------------------------------------------------
// Estimate the color cache size.
@ -948,16 +931,47 @@ int VP8LEncodeImage(const WebPConfig* const config,
// ---------------------------------------------------------------------------
// Encode and write the transformed image.
ok = EncodeImageInternal(&bw, enc->argb_, enc->current_width_, height,
quality, enc->cache_bits_, enc->histo_bits_);
if (!ok) goto Error;
err = WriteImage(enc, &bw, &coded_size);
if (err != VP8_ENC_OK) {
ok = 0;
if (!EncodeImageInternal(bw, enc->argb_, enc->current_width_, height,
quality, enc->cache_bits_, enc->histo_bits_)) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
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) {
WebPAuxStats* const stats = picture->stats;
memset(stats, 0, sizeof(*stats));
@ -975,13 +989,13 @@ int VP8LEncodeImage(const WebPConfig* const config,
}
Error:
if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
VP8LBitWriterDestroy(&bw);
DeleteVP8LEncoder(enc);
if (!ok) {
assert(err != VP8_ENC_OK);
if (err != VP8_ENC_OK) {
WebPEncodingSetError(picture, err);
return 0;
}
return ok;
return 1;
}
//------------------------------------------------------------------------------

View File

@ -35,7 +35,7 @@ extern "C" {
typedef struct {
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_scratch_; // Scratch memory for argb rows
@ -59,13 +59,16 @@ typedef struct {
//------------------------------------------------------------------------------
// internal functions. Not public.
// in vp8l.c
// Encodes the picture.
// Returns 0 if config or picture is NULL or picture doesn't have valid argb
// input.
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);
//------------------------------------------------------------------------------