mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-19 07:20:02 +02:00
libwebp interface changes for lossless encoding.
Change-Id: I703a1a18347acf78378cb23fddc6e5ca6dc6a0bb
This commit is contained in:
230
src/enc/vp8l.c
Normal file
230
src/enc/vp8l.c
Normal file
@ -0,0 +1,230 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// This code is licensed under the same terms as WebM:
|
||||
// Software License Agreement: http://www.webmproject.org/license/software/
|
||||
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// main entry for the decoder
|
||||
//
|
||||
// Author: Vikas Arora (vikaas.arora@gmail.com)
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "./vp8enci.h"
|
||||
#include "./vp8li.h"
|
||||
#include "../utils/bit_writer.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static const uint32_t kImageSizeBits = 14;
|
||||
|
||||
static int VP8LEncAnalyze(VP8LEncoder* const enc) {
|
||||
(void)enc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int EncodeImageInternal(VP8LEncoder* const enc) {
|
||||
(void)enc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int CreatePalette(VP8LEncoder* const enc) {
|
||||
(void)enc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void EvalSubtractGreen(VP8LEncoder* const enc) {
|
||||
(void)enc;
|
||||
}
|
||||
|
||||
static int ApplyPredictFilter(VP8LEncoder* const enc) {
|
||||
(void)enc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ApplyCrossColorFilter(VP8LEncoder* const enc) {
|
||||
(void)enc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void EvalEmergingPalette(VP8LEncoder* const enc) {
|
||||
(void)enc;
|
||||
}
|
||||
|
||||
static void PutLE32(uint8_t* const data, uint32_t val) {
|
||||
data[0] = (val >> 0) & 0xff;
|
||||
data[1] = (val >> 8) & 0xff;
|
||||
data[2] = (val >> 16) & 0xff;
|
||||
data[3] = (val >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static WebPEncodingError WriteRiffHeader(VP8LEncoder* const enc,
|
||||
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,
|
||||
};
|
||||
if (riff_size < (vp8l_size + TAG_SIZE + CHUNK_HEADER_SIZE)) {
|
||||
return VP8_ENC_ERROR_INVALID_CONFIGURATION;
|
||||
}
|
||||
PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
|
||||
PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
|
||||
if (!pic->writer(riff, sizeof(riff), pic)) {
|
||||
return VP8_ENC_ERROR_BAD_WRITE;
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
}
|
||||
|
||||
static WebPEncodingError WriteImage(VP8LEncoder* const enc) {
|
||||
size_t riff_size, vp8l_size, webpll_size, pad;
|
||||
WebPPicture* const pic = enc->pic_;
|
||||
WebPEncodingError err = VP8_ENC_OK;
|
||||
const uint8_t* const webpll_data = VP8LBitWriterFinish(&enc->bw_);
|
||||
|
||||
webpll_size = VP8LBitWriterNumBytes(&enc->bw_);
|
||||
vp8l_size = SIGNATURE_SIZE + webpll_size;
|
||||
pad = vp8l_size & 1;
|
||||
vp8l_size += pad;
|
||||
|
||||
riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size;
|
||||
err = WriteRiffHeader(enc, riff_size, vp8l_size);
|
||||
if (err != VP8_ENC_OK) goto Error;
|
||||
|
||||
if (!pic->writer(webpll_data, webpll_size, pic)) {
|
||||
err = VP8_ENC_ERROR_BAD_WRITE;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if (pad) {
|
||||
const uint8_t pad_byte[1] = { 0 };
|
||||
if (!pic->writer(pad_byte, 1, pic)) {
|
||||
err = VP8_ENC_ERROR_BAD_WRITE;
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
return VP8_ENC_OK;
|
||||
|
||||
Error:
|
||||
WebPEncodingSetError(pic, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static VP8LEncoder* InitVP8LEncoder(const WebPConfig* const config,
|
||||
WebPPicture* const picture) {
|
||||
VP8LEncoder* enc;
|
||||
const int kEstmatedEncodeSize = (picture->width * picture->height) >> 1;
|
||||
(void)config;
|
||||
|
||||
enc = (VP8LEncoder*)malloc(sizeof(*enc));
|
||||
if (enc == NULL) {
|
||||
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
enc->pic_ = picture;
|
||||
enc->use_lz77_ = 1;
|
||||
enc->palette_bits_ = 7;
|
||||
|
||||
// TODO: Use config.quality to initialize histo_bits_ and transform_bits_.
|
||||
enc->histo_bits_ = 4;
|
||||
enc->transform_bits_ = 4;
|
||||
VP8LBitWriterInit(&enc->bw_, kEstmatedEncodeSize);
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
static WebPEncodingError WriteImageSize(VP8LEncoder* const enc) {
|
||||
WebPEncodingError status = VP8_ENC_OK;
|
||||
WebPPicture* const pic = enc->pic_;
|
||||
const int width = pic->width - 1;
|
||||
const int height = pic->height - 1;
|
||||
if (width < 0x4000 && height < 0x4000) {
|
||||
VP8LWriteBits(&enc->bw_, kImageSizeBits, width);
|
||||
VP8LWriteBits(&enc->bw_, kImageSizeBits, height);
|
||||
} else {
|
||||
status = VP8_ENC_ERROR_BAD_DIMENSION;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void DeleteVP8LEncoder(VP8LEncoder* enc) {
|
||||
free(enc);
|
||||
}
|
||||
|
||||
int VP8LEncodeImage(const WebPConfig* const config,
|
||||
WebPPicture* const picture) {
|
||||
int ok = 0;
|
||||
VP8LEncoder* enc = NULL;
|
||||
WebPEncodingError err = VP8_ENC_OK;
|
||||
|
||||
if (config == NULL || picture == NULL) return 0;
|
||||
if (picture->argb == NULL) return 0;
|
||||
enc = InitVP8LEncoder(config, picture);
|
||||
if (enc == NULL) goto Error;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Analyze image (entropy, num_palettes etc)
|
||||
|
||||
if (!VP8LEncAnalyze(enc)) goto Error;
|
||||
|
||||
if (enc->use_palette_) {
|
||||
CreatePalette(enc);
|
||||
}
|
||||
|
||||
// Write image size.
|
||||
err = WriteImageSize(enc);
|
||||
if (err != VP8_ENC_OK) {
|
||||
ok = 0;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Apply transforms and write transform data.
|
||||
|
||||
EvalSubtractGreen(enc);
|
||||
|
||||
if (enc->use_predict_) {
|
||||
if (!ApplyPredictFilter(enc)) goto Error;
|
||||
}
|
||||
|
||||
if (enc->use_cross_color_) {
|
||||
if (!ApplyCrossColorFilter(enc)) goto Error;
|
||||
}
|
||||
|
||||
if (enc->use_emerging_palette_) {
|
||||
EvalEmergingPalette(enc);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Encode and write the transformed image.
|
||||
|
||||
ok = EncodeImageInternal(enc);
|
||||
if (!ok) goto Error;
|
||||
|
||||
err = WriteImage(enc);
|
||||
if (err != VP8_ENC_OK) {
|
||||
ok = 0;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
Error:
|
||||
VP8LBitWriterDestroy(&enc->bw_);
|
||||
DeleteVP8LEncoder(enc);
|
||||
if (!ok) {
|
||||
// TODO(vikasa): err is not set for all error paths. Set default err.
|
||||
if (err == VP8_ENC_OK) err = VP8_ENC_ERROR_BAD_WRITE;
|
||||
WebPEncodingSetError(picture, err);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} // extern "C"
|
||||
#endif
|
Reference in New Issue
Block a user