mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 12:28:26 +01:00
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:
parent
fa8bc3dbca
commit
489ec335a1
112
src/enc/vp8l.c
112
src/enc/vp8l.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -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);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user