mirror of
https://github.com/webmproject/libwebp.git
synced 2025-04-18 14:56:47 +02:00
libwebp interface changes for lossless encoding.
Change-Id: I703a1a18347acf78378cb23fddc6e5ca6dc6a0bb
This commit is contained in:
parent
c04eb7be9d
commit
227110c4c3
@ -44,6 +44,7 @@ int WebPConfigInitInternal(WebPConfig* const config,
|
|||||||
config->alpha_compression = 1;
|
config->alpha_compression = 1;
|
||||||
config->alpha_filtering = 1;
|
config->alpha_filtering = 1;
|
||||||
config->alpha_quality = 100;
|
config->alpha_quality = 100;
|
||||||
|
config->lossless = 0;
|
||||||
|
|
||||||
// TODO(skal): tune.
|
// TODO(skal): tune.
|
||||||
switch (preset) {
|
switch (preset) {
|
||||||
@ -116,6 +117,8 @@ int WebPValidateConfig(const WebPConfig* const config) {
|
|||||||
return 0;
|
return 0;
|
||||||
if (config->alpha_quality < 0 || config->alpha_quality > 100)
|
if (config->alpha_quality < 0 || config->alpha_quality > 100)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (config->lossless < 0 || config->lossless > 1)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,75 +32,88 @@ int WebPPictureAlloc(WebPPicture* const picture) {
|
|||||||
const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
|
const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
|
||||||
const int width = picture->width;
|
const int width = picture->width;
|
||||||
const int height = picture->height;
|
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
|
if (!picture->use_argb_input) {
|
||||||
switch (uv_csp) {
|
const int y_stride = width;
|
||||||
case WEBP_YUV420:
|
const int uv_width = HALVE(width);
|
||||||
break;
|
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
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
case WEBP_YUV400: // for now, we'll just reset the U/V samples
|
case WEBP_YUV400: // for now, we'll just reset the U/V samples
|
||||||
break;
|
break;
|
||||||
case WEBP_YUV422:
|
case WEBP_YUV422:
|
||||||
uv0_stride = uv_width;
|
uv0_stride = uv_width;
|
||||||
break;
|
break;
|
||||||
case WEBP_YUV444:
|
case WEBP_YUV444:
|
||||||
uv0_stride = width;
|
uv0_stride = width;
|
||||||
break;
|
break;
|
||||||
#endif
|
#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;
|
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
|
picture->y = mem;
|
||||||
a_width = has_alpha ? width : 0;
|
mem += y_size;
|
||||||
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;
|
picture->u = mem;
|
||||||
|
mem += uv_size;
|
||||||
|
picture->v = mem;
|
||||||
|
mem += uv_size;
|
||||||
|
|
||||||
// Security and validation checks
|
if (a_size) {
|
||||||
if (width <= 0 || height <= 0 || // check for luma/alpha param error
|
picture->a = mem;
|
||||||
uv_width < 0 || uv_height < 0 || // check for u/v param error
|
mem += a_size;
|
||||||
y_size >= (1ULL << 40) || // check for reasonable global size
|
}
|
||||||
(size_t)total_size != total_size) { // check for overflow on 32bit
|
if (uv0_size) {
|
||||||
return 0;
|
picture->u0 = mem;
|
||||||
}
|
mem += uv0_size;
|
||||||
picture->y_stride = y_stride;
|
picture->v0 = mem;
|
||||||
picture->uv_stride = uv_stride;
|
mem += uv0_size;
|
||||||
picture->a_stride = a_stride;
|
}
|
||||||
picture->uv0_stride = uv0_stride;
|
} else {
|
||||||
WebPPictureFree(picture); // erase previous buffer
|
if (width <= 0 || height <= 0 ||
|
||||||
mem = (uint8_t*)malloc((size_t)total_size);
|
width >= 0x4000 || height >= 0x4000) {
|
||||||
if (mem == NULL) return 0;
|
return 0;
|
||||||
|
}
|
||||||
picture->y = mem;
|
WebPPictureFree(picture); // erase previous buffer
|
||||||
mem += y_size;
|
picture->argb = (uint32_t*)malloc(width * height *
|
||||||
|
sizeof(*picture->argb));
|
||||||
picture->u = mem;
|
if (picture->argb == NULL) return 0;
|
||||||
mem += uv_size;
|
picture->argb_stride = width;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -114,12 +127,14 @@ static void WebPPictureGrabSpecs(const WebPPicture* const src,
|
|||||||
dst->y = dst->u = dst->v = NULL;
|
dst->y = dst->u = dst->v = NULL;
|
||||||
dst->u0 = dst->v0 = NULL;
|
dst->u0 = dst->v0 = NULL;
|
||||||
dst->a = NULL;
|
dst->a = NULL;
|
||||||
|
dst->argb = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release memory owned by 'picture'.
|
// Release memory owned by 'picture'.
|
||||||
void WebPPictureFree(WebPPicture* const picture) {
|
void WebPPictureFree(WebPPicture* const picture) {
|
||||||
if (picture != NULL) {
|
if (picture != NULL) {
|
||||||
free(picture->y);
|
free(picture->y);
|
||||||
|
free(picture->argb);
|
||||||
WebPPictureGrabSpecs(NULL, picture);
|
WebPPictureGrabSpecs(NULL, picture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,28 +159,34 @@ int WebPPictureCopy(const WebPPicture* const src, WebPPicture* const dst) {
|
|||||||
WebPPictureGrabSpecs(src, dst);
|
WebPPictureGrabSpecs(src, dst);
|
||||||
if (!WebPPictureAlloc(dst)) return 0;
|
if (!WebPPictureAlloc(dst)) return 0;
|
||||||
|
|
||||||
CopyPlane(src->y, src->y_stride,
|
if (!src->use_argb_input) {
|
||||||
dst->y, dst->y_stride, dst->width, dst->height);
|
CopyPlane(src->y, src->y_stride,
|
||||||
CopyPlane(src->u, src->uv_stride,
|
dst->y, dst->y_stride, dst->width, dst->height);
|
||||||
dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
|
CopyPlane(src->u, src->uv_stride,
|
||||||
CopyPlane(src->v, src->uv_stride,
|
dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
|
||||||
dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
|
CopyPlane(src->v, src->uv_stride,
|
||||||
if (dst->a != NULL) {
|
dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
|
||||||
CopyPlane(src->a, src->a_stride,
|
if (dst->a != NULL) {
|
||||||
dst->a, dst->a_stride, dst->width, dst->height);
|
CopyPlane(src->a, src->a_stride,
|
||||||
}
|
dst->a, dst->a_stride, dst->width, dst->height);
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
}
|
||||||
if (dst->u0 != NULL) {
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
int uv0_width = src->width;
|
if (dst->u0 != NULL) {
|
||||||
if ((dst->colorspace & WEBP_CSP_UV_MASK) == WEBP_YUV422) {
|
int uv0_width = src->width;
|
||||||
uv0_width = HALVE(uv0_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
|
#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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,64 +459,88 @@ static int Import(WebPPicture* const picture,
|
|||||||
const int width = picture->width;
|
const int width = picture->width;
|
||||||
const int height = picture->height;
|
const int height = picture->height;
|
||||||
|
|
||||||
// Import luma plane
|
if (!picture->use_argb_input) {
|
||||||
for (y = 0; y < height; ++y) {
|
// Import luma plane
|
||||||
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);
|
|
||||||
for (y = 0; y < height; ++y) {
|
for (y = 0; y < height; ++y) {
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
picture->a[x + y * picture->a_stride] =
|
const int offset = step * x + y * rgb_stride;
|
||||||
a_ptr[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
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
|
69
src/enc/vp8li.h
Normal file
69
src/enc/vp8li.h
Normal 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_ */
|
@ -15,6 +15,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "./vp8enci.h"
|
#include "./vp8enci.h"
|
||||||
|
#include "./vp8li.h"
|
||||||
|
|
||||||
// #define PRINT_MEMORY_INFO
|
// #define PRINT_MEMORY_INFO
|
||||||
|
|
||||||
@ -142,8 +143,8 @@ static void MapConfigToTools(VP8Encoder* const enc) {
|
|||||||
// LFStats: 2048
|
// LFStats: 2048
|
||||||
// Picture size (yuv): 589824
|
// Picture size (yuv): 589824
|
||||||
|
|
||||||
static VP8Encoder* InitEncoder(const WebPConfig* const config,
|
static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
|
||||||
WebPPicture* const picture) {
|
WebPPicture* const picture) {
|
||||||
const int use_filter =
|
const int use_filter =
|
||||||
(config->filter_strength > 0) || (config->autofilter > 0);
|
(config->filter_strength > 0) || (config->autofilter > 0);
|
||||||
const int mb_w = (picture->width + 15) >> 4;
|
const int mb_w = (picture->width + 15) >> 4;
|
||||||
@ -259,7 +260,7 @@ static VP8Encoder* InitEncoder(const WebPConfig* const config,
|
|||||||
return enc;
|
return enc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DeleteEncoder(VP8Encoder* enc) {
|
static void DeleteVP8Encoder(VP8Encoder* enc) {
|
||||||
if (enc) {
|
if (enc) {
|
||||||
VP8EncDeleteAlpha(enc);
|
VP8EncDeleteAlpha(enc);
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
@ -327,7 +328,6 @@ int WebPReportProgress(VP8Encoder* const enc, int percent) {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
||||||
VP8Encoder* enc;
|
|
||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
if (pic == NULL)
|
if (pic == NULL)
|
||||||
@ -339,27 +339,36 @@ int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
|||||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
|
return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
|
||||||
if (pic->width <= 0 || pic->height <= 0)
|
if (pic->width <= 0 || pic->height <= 0)
|
||||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
|
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)
|
if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION)
|
||||||
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
|
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
|
||||||
|
|
||||||
enc = InitEncoder(config, pic);
|
if (!config->lossless) {
|
||||||
if (enc == NULL) return 0; // pic->error is already set.
|
VP8Encoder* enc = NULL;
|
||||||
// Note: each of the tasks below account for 20% in the progress report.
|
if (pic->y == NULL || pic->u == NULL || pic->v == NULL)
|
||||||
ok = VP8EncAnalyze(enc)
|
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
|
||||||
&& VP8StatLoop(enc)
|
|
||||||
&& VP8EncLoop(enc)
|
enc = InitVP8Encoder(config, pic);
|
||||||
&& VP8EncFinishAlpha(enc)
|
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
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
&& VP8EncFinishLayer(enc)
|
&& VP8EncFinishLayer(enc)
|
||||||
#endif
|
#endif
|
||||||
&& VP8EncWrite(enc);
|
&& VP8EncWrite(enc);
|
||||||
StoreStats(enc);
|
StoreStats(enc);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
VP8EncFreeBitWriters(enc);
|
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;
|
return ok;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
// Bit writing and boolean coder
|
// Bit writing and boolean coder
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
// Vikas Arora (vikaas.arora@gmail.com)
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h> // for memcpy()
|
#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)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -64,6 +64,56 @@ static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) {
|
|||||||
return bw->pos_;
|
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)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -76,6 +76,7 @@ typedef struct {
|
|||||||
// 0: none, 1: fast, 2: best. Default if 1.
|
// 0: none, 1: fast, 2: best. Default if 1.
|
||||||
int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
|
int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
|
||||||
// Default is 100.
|
// Default is 100.
|
||||||
|
int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
|
||||||
} WebPConfig;
|
} WebPConfig;
|
||||||
|
|
||||||
// Enumerate some predefined settings for WebPConfig, depending on the type
|
// 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)
|
int width, height; // dimensions (less or equal to WEBP_MAX_DIMENSION)
|
||||||
uint8_t *y, *u, *v; // pointers to luma/chroma planes.
|
uint8_t *y, *u, *v; // pointers to luma/chroma planes.
|
||||||
int y_stride, uv_stride; // luma/chroma strides.
|
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
|
int a_stride; // stride of the alpha plane
|
||||||
|
|
||||||
// output
|
// output
|
||||||
@ -216,6 +217,10 @@ struct WebPPicture {
|
|||||||
WebPEncodingError error_code; // error code in case of problem.
|
WebPEncodingError error_code; // error code in case of problem.
|
||||||
|
|
||||||
WebPProgressHook progress_hook; // if not NULL, called while encoding.
|
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
|
// Internal, version-checked, entry point
|
||||||
|
Loading…
x
Reference in New Issue
Block a user