libwebp interface changes for lossless encoding.

Change-Id: I703a1a18347acf78378cb23fddc6e5ca6dc6a0bb
This commit is contained in:
Vikas Arora 2012-03-28 11:07:42 +00:00 committed by James Zern
parent c04eb7be9d
commit 227110c4c3
8 changed files with 648 additions and 158 deletions

View File

@ -44,6 +44,7 @@ int WebPConfigInitInternal(WebPConfig* const config,
config->alpha_compression = 1;
config->alpha_filtering = 1;
config->alpha_quality = 100;
config->lossless = 0;
// TODO(skal): tune.
switch (preset) {
@ -116,6 +117,8 @@ int WebPValidateConfig(const WebPConfig* const config) {
return 0;
if (config->alpha_quality < 0 || config->alpha_quality > 100)
return 0;
if (config->lossless < 0 || config->lossless > 1)
return 0;
return 1;
}

View File

@ -32,75 +32,88 @@ int WebPPictureAlloc(WebPPicture* const picture) {
const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
const int width = picture->width;
const int height = picture->height;
const int y_stride = width;
const int uv_width = HALVE(width);
const int uv_height = HALVE(height);
const int uv_stride = uv_width;
int uv0_stride = 0;
int a_width, a_stride;
uint64_t y_size, uv_size, uv0_size, a_size, total_size;
uint8_t* mem;
// U/V
switch (uv_csp) {
case WEBP_YUV420:
break;
if (!picture->use_argb_input) {
const int y_stride = width;
const int uv_width = HALVE(width);
const int uv_height = HALVE(height);
const int uv_stride = uv_width;
int uv0_stride = 0;
int a_width, a_stride;
uint64_t y_size, uv_size, uv0_size, a_size, total_size;
uint8_t* mem;
// U/V
switch (uv_csp) {
case WEBP_YUV420:
break;
#ifdef WEBP_EXPERIMENTAL_FEATURES
case WEBP_YUV400: // for now, we'll just reset the U/V samples
break;
case WEBP_YUV422:
uv0_stride = uv_width;
break;
case WEBP_YUV444:
uv0_stride = width;
break;
case WEBP_YUV400: // for now, we'll just reset the U/V samples
break;
case WEBP_YUV422:
uv0_stride = uv_width;
break;
case WEBP_YUV444:
uv0_stride = width;
break;
#endif
default:
default:
return 0;
}
uv0_size = height * uv0_stride;
// alpha
a_width = has_alpha ? width : 0;
a_stride = a_width;
y_size = (uint64_t)y_stride * height;
uv_size = (uint64_t)uv_stride * uv_height;
a_size = (uint64_t)a_stride * height;
total_size = y_size + a_size + 2 * uv_size + 2 * uv0_size;
// Security and validation checks
if (width <= 0 || height <= 0 || // check for luma/alpha param error
uv_width < 0 || uv_height < 0 || // check for u/v param error
y_size >= (1ULL << 40) || // check for reasonable global size
(size_t)total_size != total_size) { // check for overflow on 32bit
return 0;
}
uv0_size = height * uv0_stride;
}
picture->y_stride = y_stride;
picture->uv_stride = uv_stride;
picture->a_stride = a_stride;
picture->uv0_stride = uv0_stride;
WebPPictureFree(picture); // erase previous buffer
mem = (uint8_t*)malloc((size_t)total_size);
if (mem == NULL) return 0;
// alpha
a_width = has_alpha ? width : 0;
a_stride = a_width;
y_size = (uint64_t)y_stride * height;
uv_size = (uint64_t)uv_stride * uv_height;
a_size = (uint64_t)a_stride * height;
picture->y = mem;
mem += y_size;
total_size = y_size + a_size + 2 * uv_size + 2 * uv0_size;
picture->u = mem;
mem += uv_size;
picture->v = mem;
mem += uv_size;
// Security and validation checks
if (width <= 0 || height <= 0 || // check for luma/alpha param error
uv_width < 0 || uv_height < 0 || // check for u/v param error
y_size >= (1ULL << 40) || // check for reasonable global size
(size_t)total_size != total_size) { // check for overflow on 32bit
return 0;
}
picture->y_stride = y_stride;
picture->uv_stride = uv_stride;
picture->a_stride = a_stride;
picture->uv0_stride = uv0_stride;
WebPPictureFree(picture); // erase previous buffer
mem = (uint8_t*)malloc((size_t)total_size);
if (mem == NULL) return 0;
picture->y = mem;
mem += y_size;
picture->u = mem;
mem += uv_size;
picture->v = mem;
mem += uv_size;
if (a_size) {
picture->a = mem;
mem += a_size;
}
if (uv0_size) {
picture->u0 = mem;
mem += uv0_size;
picture->v0 = mem;
mem += uv0_size;
if (a_size) {
picture->a = mem;
mem += a_size;
}
if (uv0_size) {
picture->u0 = mem;
mem += uv0_size;
picture->v0 = mem;
mem += uv0_size;
}
} else {
if (width <= 0 || height <= 0 ||
width >= 0x4000 || height >= 0x4000) {
return 0;
}
WebPPictureFree(picture); // erase previous buffer
picture->argb = (uint32_t*)malloc(width * height *
sizeof(*picture->argb));
if (picture->argb == NULL) return 0;
picture->argb_stride = width;
}
}
return 1;
@ -114,12 +127,14 @@ static void WebPPictureGrabSpecs(const WebPPicture* const src,
dst->y = dst->u = dst->v = NULL;
dst->u0 = dst->v0 = NULL;
dst->a = NULL;
dst->argb = NULL;
}
// Release memory owned by 'picture'.
void WebPPictureFree(WebPPicture* const picture) {
if (picture != NULL) {
free(picture->y);
free(picture->argb);
WebPPictureGrabSpecs(NULL, picture);
}
}
@ -144,28 +159,34 @@ int WebPPictureCopy(const WebPPicture* const src, WebPPicture* const dst) {
WebPPictureGrabSpecs(src, dst);
if (!WebPPictureAlloc(dst)) return 0;
CopyPlane(src->y, src->y_stride,
dst->y, dst->y_stride, dst->width, dst->height);
CopyPlane(src->u, src->uv_stride,
dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
CopyPlane(src->v, src->uv_stride,
dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
if (dst->a != NULL) {
CopyPlane(src->a, src->a_stride,
dst->a, dst->a_stride, dst->width, dst->height);
}
#ifdef WEBP_EXPERIMENTAL_FEATURES
if (dst->u0 != NULL) {
int uv0_width = src->width;
if ((dst->colorspace & WEBP_CSP_UV_MASK) == WEBP_YUV422) {
uv0_width = HALVE(uv0_width);
if (!src->use_argb_input) {
CopyPlane(src->y, src->y_stride,
dst->y, dst->y_stride, dst->width, dst->height);
CopyPlane(src->u, src->uv_stride,
dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
CopyPlane(src->v, src->uv_stride,
dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
if (dst->a != NULL) {
CopyPlane(src->a, src->a_stride,
dst->a, dst->a_stride, dst->width, dst->height);
}
#ifdef WEBP_EXPERIMENTAL_FEATURES
if (dst->u0 != NULL) {
int uv0_width = src->width;
if ((dst->colorspace & WEBP_CSP_UV_MASK) == WEBP_YUV422) {
uv0_width = HALVE(uv0_width);
}
CopyPlane(src->u0, src->uv0_stride,
dst->u0, dst->uv0_stride, uv0_width, dst->height);
CopyPlane(src->v0, src->uv0_stride,
dst->v0, dst->uv0_stride, uv0_width, dst->height);
}
CopyPlane(src->u0, src->uv0_stride,
dst->u0, dst->uv0_stride, uv0_width, dst->height);
CopyPlane(src->v0, src->uv0_stride,
dst->v0, dst->uv0_stride, uv0_width, dst->height);
}
#endif
} else {
CopyPlane((uint8_t*)src->argb, 4 * src->argb_stride,
(uint8_t*)dst->argb, 4 * dst->argb_stride,
4 * dst->width, dst->height);
}
return 1;
}
@ -438,64 +459,88 @@ static int Import(WebPPicture* const picture,
const int width = picture->width;
const int height = picture->height;
// Import luma plane
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
const int offset = step * x + y * rgb_stride;
picture->y[x + y * picture->y_stride] =
rgb_to_y(r_ptr[offset], g_ptr[offset], b_ptr[offset]);
}
}
// Downsample U/V plane
if (uv_csp != WEBP_YUV400) {
for (y = 0; y < (height >> 1); ++y) {
for (x = 0; x < (width >> 1); ++x) {
RGB_TO_UV(x, y, SUM4);
}
if (picture->width & 1) {
RGB_TO_UV(x, y, SUM2V);
}
}
if (height & 1) {
for (x = 0; x < (width >> 1); ++x) {
RGB_TO_UV(x, y, SUM2H);
}
if (width & 1) {
RGB_TO_UV(x, y, SUM1);
}
}
#ifdef WEBP_EXPERIMENTAL_FEATURES
// Store original U/V samples too
if (uv_csp == WEBP_YUV422) {
for (y = 0; y < height; ++y) {
for (x = 0; x < (width >> 1); ++x) {
RGB_TO_UV0(2 * x, x, y, SUM2H);
}
if (width & 1) {
RGB_TO_UV0(2 * x, x, y, SUM1);
}
}
} else if (uv_csp == WEBP_YUV444) {
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
RGB_TO_UV0(x, x, y, SUM1);
}
}
}
#endif
} else {
MakeGray(picture);
}
if (import_alpha) {
const uint8_t* const a_ptr = rgb + 3;
assert(step >= 4);
if (!picture->use_argb_input) {
// Import luma plane
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
picture->a[x + y * picture->a_stride] =
a_ptr[step * x + y * rgb_stride];
const int offset = step * x + y * rgb_stride;
picture->y[x + y * picture->y_stride] =
rgb_to_y(r_ptr[offset], g_ptr[offset], b_ptr[offset]);
}
}
// Downsample U/V plane
if (uv_csp != WEBP_YUV400) {
for (y = 0; y < (height >> 1); ++y) {
for (x = 0; x < (width >> 1); ++x) {
RGB_TO_UV(x, y, SUM4);
}
if (picture->width & 1) {
RGB_TO_UV(x, y, SUM2V);
}
}
if (height & 1) {
for (x = 0; x < (width >> 1); ++x) {
RGB_TO_UV(x, y, SUM2H);
}
if (width & 1) {
RGB_TO_UV(x, y, SUM1);
}
}
#ifdef WEBP_EXPERIMENTAL_FEATURES
// Store original U/V samples too
if (uv_csp == WEBP_YUV422) {
for (y = 0; y < height; ++y) {
for (x = 0; x < (width >> 1); ++x) {
RGB_TO_UV0(2 * x, x, y, SUM2H);
}
if (width & 1) {
RGB_TO_UV0(2 * x, x, y, SUM1);
}
}
} else if (uv_csp == WEBP_YUV444) {
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
RGB_TO_UV0(x, x, y, SUM1);
}
}
}
#endif
} else {
MakeGray(picture);
}
if (import_alpha) {
const uint8_t* const a_ptr = rgb + 3;
assert(step >= 4);
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
picture->a[x + y * picture->a_stride] =
a_ptr[step * x + y * rgb_stride];
}
}
}
} else {
if (!import_alpha) {
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
const int offset = step * x + y * rgb_stride;
const uint32_t argb = 0xff000000 | (r_ptr[offset] << 16) |
(g_ptr[offset] << 8) | (b_ptr[offset]);
picture->argb[x + y * picture->argb_stride] = argb;
}
}
} else {
const uint8_t* const a_ptr = rgb + 3;
assert(step >= 4);
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
const int offset = step * x + y * rgb_stride;
const uint32_t argb = (a_ptr[offset] << 24) | (r_ptr[offset] << 16) |
(g_ptr[offset] << 8) | (b_ptr[offset]);
picture->argb[x + y * picture->argb_stride] = argb;
}
}
}
}

230
src/enc/vp8l.c Normal file
View 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

69
src/enc/vp8li.h Normal file
View File

@ -0,0 +1,69 @@
// 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/
// -----------------------------------------------------------------------------
//
// Lossless encoder: internal header.
//
// Author: Vikas Arora(vikaas.arora@gmail.com)
#ifndef WEBP_ENC_VP8LI_H_
#define WEBP_ENC_VP8LI_H_
#include "../webp/encode.h"
#include "../utils/bit_writer.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
// TODO(vikasa): factorize these with ones used in lossless decoder.
#define TAG_SIZE 4
#define CHUNK_HEADER_SIZE 8
#define RIFF_HEADER_SIZE 12
#define HEADER_SIZE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE)
#define SIGNATURE_SIZE 1
#define LOSSLESS_MAGIC_BYTE 0x64
typedef struct {
const WebPConfig* config_; // user configuration and parameters
WebPPicture* pic_; // input / output picture
// Encoding parameters derived from quality parameter.
int use_lz77_;
int palette_bits_;
int histo_bits_;
int transform_bits_;
// Encoding parameters derived from image characteristics.
int predicted_bits_;
int non_predicted_bits_;
int use_palette_;
int num_palette_colors;
int use_predict_;
int use_cross_color_;
int use_emerging_palette_;
VP8LBitWriter bw_;
} VP8LEncoder;
//------------------------------------------------------------------------------
// 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);
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif /* WEBP_ENC_VP8LI_H_ */

View File

@ -15,6 +15,7 @@
#include <math.h>
#include "./vp8enci.h"
#include "./vp8li.h"
// #define PRINT_MEMORY_INFO
@ -142,8 +143,8 @@ static void MapConfigToTools(VP8Encoder* const enc) {
// LFStats: 2048
// Picture size (yuv): 589824
static VP8Encoder* InitEncoder(const WebPConfig* const config,
WebPPicture* const picture) {
static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
WebPPicture* const picture) {
const int use_filter =
(config->filter_strength > 0) || (config->autofilter > 0);
const int mb_w = (picture->width + 15) >> 4;
@ -259,7 +260,7 @@ static VP8Encoder* InitEncoder(const WebPConfig* const config,
return enc;
}
static void DeleteEncoder(VP8Encoder* enc) {
static void DeleteVP8Encoder(VP8Encoder* enc) {
if (enc) {
VP8EncDeleteAlpha(enc);
#ifdef WEBP_EXPERIMENTAL_FEATURES
@ -327,7 +328,6 @@ int WebPReportProgress(VP8Encoder* const enc, int percent) {
//------------------------------------------------------------------------------
int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
VP8Encoder* enc;
int ok;
if (pic == NULL)
@ -339,27 +339,36 @@ int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
if (pic->width <= 0 || pic->height <= 0)
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
if (pic->y == NULL || pic->u == NULL || pic->v == NULL)
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION)
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
enc = InitEncoder(config, pic);
if (enc == NULL) return 0; // pic->error is already set.
// Note: each of the tasks below account for 20% in the progress report.
ok = VP8EncAnalyze(enc)
&& VP8StatLoop(enc)
&& VP8EncLoop(enc)
&& VP8EncFinishAlpha(enc)
if (!config->lossless) {
VP8Encoder* enc = NULL;
if (pic->y == NULL || pic->u == NULL || pic->v == NULL)
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
enc = InitVP8Encoder(config, pic);
if (enc == NULL) return 0; // pic->error is already set.
// Note: each of the tasks below account for 20% in the progress report.
ok = VP8EncAnalyze(enc)
&& VP8StatLoop(enc)
&& VP8EncLoop(enc)
&& VP8EncFinishAlpha(enc)
#ifdef WEBP_EXPERIMENTAL_FEATURES
&& VP8EncFinishLayer(enc)
&& VP8EncFinishLayer(enc)
#endif
&& VP8EncWrite(enc);
StoreStats(enc);
if (!ok) {
VP8EncFreeBitWriters(enc);
&& VP8EncWrite(enc);
StoreStats(enc);
if (!ok) {
VP8EncFreeBitWriters(enc);
}
DeleteVP8Encoder(enc);
} else {
if (pic->argb == NULL)
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
ok = VP8LEncodeImage(config, pic);
}
DeleteEncoder(enc);
return ok;
}

View File

@ -8,6 +8,7 @@
// Bit writing and boolean coder
//
// Author: Skal (pascal.massimino@gmail.com)
// Vikas Arora (vikaas.arora@gmail.com)
#include <assert.h>
#include <string.h> // for memcpy()
@ -186,6 +187,84 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
}
}
//------------------------------------------------------------------------------
// VP8LBitWriter
// Returns 1 on success.
static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
uint8_t* allocated_buf;
size_t allocated_size;
const size_t size_required = VP8LBitWriterNumBytes(bw) + extra_size;
if ((bw->max_bytes_ > 0) && (size_required <= bw->max_bytes_)) return 1;
allocated_size = (3 * bw->max_bytes_) >> 1;
if (allocated_size < size_required) {
allocated_size = size_required;
}
// Make Allocated size multiple of KBs
allocated_size = (((allocated_size >> 10) + 1) << 10);
allocated_buf = (uint8_t*)malloc(allocated_size);
if (allocated_buf == NULL) return 0;
memset(allocated_buf, 0, allocated_size);
if (bw->bit_pos_ > 0) {
memcpy(allocated_buf, bw->buf_, VP8LBitWriterNumBytes(bw));
}
free(bw->buf_);
bw->buf_ = allocated_buf;
bw->max_bytes_ = allocated_size;
return 1;
}
int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) {
memset(bw, 0, sizeof(*bw));
return VP8LBitWriterResize(bw, expected_size);
}
void VP8LBitWriterDestroy(VP8LBitWriter* const bw) {
if (bw != NULL) {
free(bw->buf_);
memset(bw, 0, sizeof(*bw));
}
}
void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits) {
if (n_bits < 1) return;
#if !defined(__BIG_ENDIAN__)
// Technically, this branch of the code can write up to 25 bits at a time,
// but in deflate, the maximum number of bits written is 16 at a time.
{
uint8_t* p = &bw->buf_[bw->bit_pos_ >> 3];
uint32_t v = *(const uint32_t*)(p);
v |= bits << (bw->bit_pos_ & 7);
*(uint32_t*)(p) = v;
bw->bit_pos_ += n_bits;
}
#else // LITTLE_ENDIAN
// implicit & 0xff is assumed for uint8_t arithmetics
{
uint8_t* p = &bw->buf_[bw->bit_pos_ >> 3];
const int bits_reserved_in_first_byte = (bw->bit_pos_ & 7);
*p++ |= (bits << bits_reserved_in_first_byte);
const int bits_left_to_write = n_bits - 8 + bits_reserved_in_first_byte;
if (bits_left_to_write >= 1) {
*p++ = bits >> (8 - bits_reserved_in_first_byte);
if (bits_left_to_write >= 9) {
*p++ = bits >> (16 - bits_reserved_in_first_byte);
}
}
*p = 0;
bw->bit_pos_ += n_bits;
}
#endif // BIG_ENDIAN
if ((bw->bit_pos_ >> 3) > (bw->max_bytes_ - 8)) {
const size_t kAdditionalBuffer = 32768 + bw->max_bytes_;
if (!VP8LBitWriterResize(bw, kAdditionalBuffer)) {
bw->bit_pos_ = 0;
bw->error_ = 1;
}
}
}
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)

View File

@ -64,6 +64,56 @@ static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) {
return bw->pos_;
}
//------------------------------------------------------------------------------
// VP8LBitWriter
// TODO(vikasa): VP8LBitWriter is copied as-is from lossless code. There's scope
// of re-using VP8BitWriter. Will evaluate once basic lossless encoder is
// implemented.
typedef struct {
uint8_t* buf_;
size_t bit_pos_;
size_t max_bytes_;
// After all bits are written, the caller must observe the state of
// error_. A value of 1 indicates that a memory allocation failure
// has happened during bit writing. A value of 0 indicates successful
// writing of bits.
int error_;
} VP8LBitWriter;
static WEBP_INLINE size_t VP8LBitWriterNumBytes(VP8LBitWriter* const bw) {
return (bw->bit_pos_ + 7) >> 3;
}
static WEBP_INLINE uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) {
return bw->buf_;
}
// Returns 1 on success.
int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
void VP8LBitWriterDestroy(VP8LBitWriter* const bw);
// This function writes bits into bytes in increasing addresses, and within
// a byte least-significant-bit first.
//
// The function can write up to 16 bits in one go with WriteBits
// Example: let's assume that 3 bits (Rs below) have been written already:
//
// BYTE-0 BYTE+1 BYTE+2
//
// 0000 0RRR 0000 0000 0000 0000
//
// Now, we could write 5 or less bits in MSB by just sifting by 3
// and OR'ing to BYTE-0.
//
// For n bits, we take the last 5 bytes, OR that with high bits in BYTE-0,
// and locate the rest in BYTE+1 and BYTE+2.
//
// returns 1 on success.
void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits);
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)

View File

@ -76,6 +76,7 @@ typedef struct {
// 0: none, 1: fast, 2: best. Default if 1.
int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
// Default is 100.
int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
} WebPConfig;
// Enumerate some predefined settings for WebPConfig, depending on the type
@ -189,7 +190,7 @@ struct WebPPicture {
int width, height; // dimensions (less or equal to WEBP_MAX_DIMENSION)
uint8_t *y, *u, *v; // pointers to luma/chroma planes.
int y_stride, uv_stride; // luma/chroma strides.
uint8_t *a; // pointer to the alpha plane
uint8_t* a; // pointer to the alpha plane
int a_stride; // stride of the alpha plane
// output
@ -216,6 +217,10 @@ struct WebPPicture {
WebPEncodingError error_code; // error code in case of problem.
WebPProgressHook progress_hook; // if not NULL, called while encoding.
int use_argb_input; // Flag for encoder to read argb pixels as input.
uint32_t* argb; // Pointer to argb (32 bit) plane.
int argb_stride; // This is stride in pixels units, not bytes.
};
// Internal, version-checked, entry point