mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-24 17:59:52 +02:00
Compare commits
29 Commits
v0.2.0-rc1
...
0.2.0
Author | SHA1 | Date | |
---|---|---|---|
74fefc8ce8 | |||
abc06044e7 | |||
57cf313bba | |||
25f585c4f2 | |||
fed7c0485a | |||
552cd9bce0 | |||
b14fea993a | |||
4a8fb27223 | |||
d662158010 | |||
72b96a6905 | |||
734f762a08 | |||
f9cb58fbce | |||
b30add2017 | |||
3de58d7730 | |||
77aa7d50a4 | |||
e5970bda8a | |||
ef5cc47ee7 | |||
c4ea259db4 | |||
4238bc0adb | |||
c655380c36 | |||
fe1958f17d | |||
681cb30ad2 | |||
f06c1d8f7b | |||
f56e98fd11 | |||
6fe843baeb | |||
528a11af35 | |||
a0a488554d | |||
62dd9bb242 | |||
6f4272b090 |
29
ChangeLog
29
ChangeLog
@ -1,3 +1,32 @@
|
|||||||
|
abc0604 Merge "update NEWS" into 0.2.0
|
||||||
|
57cf313 update NEWS
|
||||||
|
25f585c bump version to 0.2.1
|
||||||
|
fed7c04 libwebp: validate chunk size in ParseOptionalChunks
|
||||||
|
552cd9b cwebp (windows): fix alpha image import on XP
|
||||||
|
b14fea9 autoconf/libwebp: enable dll builds for mingw
|
||||||
|
4a8fb27 [cd]webp: always output windows errors
|
||||||
|
d662158 fix double to float conversion warning
|
||||||
|
72b96a6 cwebp: fix jpg encodes on XP
|
||||||
|
734f762 VP8LAllocateHistogramSet: fix overflow in size calculation
|
||||||
|
f9cb58f GetHistoBits: fix integer overflow
|
||||||
|
b30add2 EncodeImageInternal: fix uninitialized free
|
||||||
|
3de58d7 fix the -g/O3 discrepancy for 32bit compile
|
||||||
|
77aa7d5 fix the BITS=8 case
|
||||||
|
e5970bd Make *InitSSE2() functions be empty on non-SSE2 platform
|
||||||
|
ef5cc47 make *InitSSE2() functions be empty on non-SSE2 platform
|
||||||
|
c4ea259 make VP8DspInitNEON() public
|
||||||
|
4238bc0 Update ChangeLog (v0.2.0)
|
||||||
|
c655380 dec/io.c: cosmetics
|
||||||
|
fe1958f RGBA4444: harmonize lossless/lossy alpha values
|
||||||
|
681cb30 fix RGBA4444 output w/fancy upsampling
|
||||||
|
f06c1d8 Merge "Alignment fix" into 0.2.0
|
||||||
|
f56e98f Alignment fix
|
||||||
|
6fe843b avoid rgb-premultiply if there's only trivial alpha values
|
||||||
|
528a11a fix the ARGB4444 premultiply arithmetic
|
||||||
|
a0a4885 Lossless decoder fix for a special transform order
|
||||||
|
62dd9bb Update encoding heuristic w.r.t palette colors.
|
||||||
|
6f4272b remove unused ApplyInverseTransform()
|
||||||
|
93bf0fa Update ChangeLog (v0.2.0-rc1)
|
||||||
5934fc5 update AUTHORS
|
5934fc5 update AUTHORS
|
||||||
014a711 update NEWS
|
014a711 update NEWS
|
||||||
43b0d61 add support for ARGB -> YUVA conversion for lossless decoder
|
43b0d61 add support for ARGB -> YUVA conversion for lossless decoder
|
||||||
|
5
NEWS
5
NEWS
@ -1,3 +1,8 @@
|
|||||||
|
- 10/30/12: version 0.2.1
|
||||||
|
* Various security related fixes
|
||||||
|
* cwebp.exe: fix import errors on Windows XP
|
||||||
|
* enable DLL builds for mingw targets
|
||||||
|
|
||||||
- 8/3/12: version 0.2.0
|
- 8/3/12: version 0.2.0
|
||||||
* Add support for ARGB -> YUVA conversion for lossless decoder
|
* Add support for ARGB -> YUVA conversion for lossless decoder
|
||||||
New functions: WebPINewYUVA, WebPIDecGetYUVA
|
New functions: WebPINewYUVA, WebPIDecGetYUVA
|
||||||
|
2
README
2
README
@ -4,7 +4,7 @@
|
|||||||
\__\__/\____/\_____/__/ ____ ___
|
\__\__/\____/\_____/__/ ____ ___
|
||||||
/ _/ / \ \ / _ \/ _/
|
/ _/ / \ \ / _ \/ _/
|
||||||
/ \_/ / / \ \ __/ \__
|
/ \_/ / / \ \ __/ \__
|
||||||
\____/____/\_____/_____/____/v0.2.0
|
\____/____/\_____/_____/____/v0.2.1
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
============
|
============
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
AC_INIT([libwebp], [0.2.0],
|
AC_INIT([libwebp], [0.2.1],
|
||||||
[http://code.google.com/p/webp/issues],,
|
[http://code.google.com/p/webp/issues],,
|
||||||
[http://developers.google.com/speed/webp])
|
[http://developers.google.com/speed/webp])
|
||||||
AC_CANONICAL_TARGET
|
AC_CANONICAL_TARGET
|
||||||
|
104
examples/cwebp.c
104
examples/cwebp.c
@ -95,14 +95,12 @@ static int ReadYUV(FILE* in_file, WebPPicture* const pic) {
|
|||||||
|
|
||||||
#ifdef HAVE_WINCODEC_H
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
|
||||||
#define IFS(fn) \
|
#define IFS(fn) \
|
||||||
do { \
|
do { \
|
||||||
if (SUCCEEDED(hr)) \
|
if (SUCCEEDED(hr)) { \
|
||||||
{ \
|
hr = (fn); \
|
||||||
hr = (fn); \
|
if (FAILED(hr)) fprintf(stderr, #fn " failed %08x\n", hr); \
|
||||||
if (FAILED(hr) && verbose) \
|
} \
|
||||||
fprintf(stderr, #fn " failed %08x\n", hr); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// modified version of DEFINE_GUID from guiddef.h.
|
// modified version of DEFINE_GUID from guiddef.h.
|
||||||
@ -115,6 +113,12 @@ static int ReadYUV(FILE* in_file, WebPPicture* const pic) {
|
|||||||
#define MAKE_REFGUID(x) &(x)
|
#define MAKE_REFGUID(x) &(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct WICFormatImporter {
|
||||||
|
const GUID* pixel_format;
|
||||||
|
int bytes_per_pixel;
|
||||||
|
int (*import)(WebPPicture* const, const uint8_t* const, int);
|
||||||
|
} WICFormatImporter;
|
||||||
|
|
||||||
static HRESULT OpenInputStream(const char* filename, IStream** ppStream) {
|
static HRESULT OpenInputStream(const char* filename, IStream** ppStream) {
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
IFS(SHCreateStreamOnFileA(filename, STGM_READ, ppStream));
|
IFS(SHCreateStreamOnFileA(filename, STGM_READ, ppStream));
|
||||||
@ -125,6 +129,31 @@ static HRESULT OpenInputStream(const char* filename, IStream** ppStream) {
|
|||||||
|
|
||||||
static HRESULT ReadPictureWithWIC(const char* filename,
|
static HRESULT ReadPictureWithWIC(const char* filename,
|
||||||
WebPPicture* const pic, int keep_alpha) {
|
WebPPicture* const pic, int keep_alpha) {
|
||||||
|
// From Microsoft SDK 7.0a -- wincodec.h
|
||||||
|
// Create local copies for compatibility when building against earlier
|
||||||
|
// versions of the SDK.
|
||||||
|
WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_,
|
||||||
|
0x6fddc324, 0x4e03, 0x4bfe,
|
||||||
|
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c);
|
||||||
|
WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_,
|
||||||
|
0x6fddc324, 0x4e03, 0x4bfe,
|
||||||
|
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
|
||||||
|
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_,
|
||||||
|
0x6fddc324, 0x4e03, 0x4bfe,
|
||||||
|
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
|
||||||
|
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_,
|
||||||
|
0xf5c7ad2d, 0x6a8d, 0x43dd,
|
||||||
|
0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
|
||||||
|
const WICFormatImporter alphaFormatImporters[] = {
|
||||||
|
{ &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA },
|
||||||
|
{ &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA },
|
||||||
|
{ NULL, 0, NULL },
|
||||||
|
};
|
||||||
|
const WICFormatImporter nonAlphaFormatImporters[] = {
|
||||||
|
{ &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR },
|
||||||
|
{ &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB },
|
||||||
|
{ NULL, 0, NULL },
|
||||||
|
};
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
IWICBitmapFrameDecode* pFrame = NULL;
|
IWICBitmapFrameDecode* pFrame = NULL;
|
||||||
IWICFormatConverter* pConverter = NULL;
|
IWICFormatConverter* pConverter = NULL;
|
||||||
@ -135,6 +164,7 @@ static HRESULT ReadPictureWithWIC(const char* filename,
|
|||||||
UINT width = 0, height = 0;
|
UINT width = 0, height = 0;
|
||||||
BYTE* rgb = NULL;
|
BYTE* rgb = NULL;
|
||||||
WICPixelFormatGUID srcPixelFormat = { 0 };
|
WICPixelFormatGUID srcPixelFormat = { 0 };
|
||||||
|
const WICFormatImporter* importer = NULL;
|
||||||
GUID srcContainerFormat = { 0 };
|
GUID srcContainerFormat = { 0 };
|
||||||
const GUID* alphaContainers[] = {
|
const GUID* alphaContainers[] = {
|
||||||
&GUID_ContainerFormatBmp,
|
&GUID_ContainerFormatBmp,
|
||||||
@ -143,18 +173,6 @@ static HRESULT ReadPictureWithWIC(const char* filename,
|
|||||||
};
|
};
|
||||||
int has_alpha = 0;
|
int has_alpha = 0;
|
||||||
int i, stride;
|
int i, stride;
|
||||||
// From Microsoft SDK 7.0a
|
|
||||||
// Create local copies for compatibility when building against earlier
|
|
||||||
// versions of the SDK.
|
|
||||||
WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_,
|
|
||||||
0x6fddc324, 0x4e03, 0x4bfe,
|
|
||||||
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
|
|
||||||
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_,
|
|
||||||
0xf5c7ad2d, 0x6a8d, 0x43dd,
|
|
||||||
0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
|
|
||||||
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_,
|
|
||||||
0x6fddc324, 0x4e03, 0x4bfe,
|
|
||||||
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
|
|
||||||
|
|
||||||
IFS(CoInitialize(NULL));
|
IFS(CoInitialize(NULL));
|
||||||
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
|
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
|
||||||
@ -179,32 +197,45 @@ static HRESULT ReadPictureWithWIC(const char* filename,
|
|||||||
IFS(IWICBitmapFrameDecode_GetPixelFormat(pFrame, &srcPixelFormat));
|
IFS(IWICBitmapFrameDecode_GetPixelFormat(pFrame, &srcPixelFormat));
|
||||||
IFS(IWICBitmapDecoder_GetContainerFormat(pDecoder, &srcContainerFormat));
|
IFS(IWICBitmapDecoder_GetContainerFormat(pDecoder, &srcContainerFormat));
|
||||||
|
|
||||||
has_alpha = keep_alpha;
|
if (keep_alpha) {
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
has_alpha && i < sizeof(alphaContainers)/sizeof(alphaContainers[0]);
|
i < sizeof(alphaContainers) / sizeof(alphaContainers[0]);
|
||||||
++i) {
|
++i) {
|
||||||
if (IsEqualGUID(MAKE_REFGUID(srcContainerFormat),
|
if (IsEqualGUID(MAKE_REFGUID(srcContainerFormat),
|
||||||
MAKE_REFGUID(*alphaContainers[i]))) {
|
MAKE_REFGUID(*alphaContainers[i]))) {
|
||||||
has_alpha =
|
has_alpha =
|
||||||
IsEqualGUID(MAKE_REFGUID(srcPixelFormat),
|
IsEqualGUID(MAKE_REFGUID(srcPixelFormat),
|
||||||
MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) ||
|
MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) ||
|
||||||
IsEqualGUID(MAKE_REFGUID(srcPixelFormat),
|
IsEqualGUID(MAKE_REFGUID(srcPixelFormat),
|
||||||
MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_));
|
MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for pixel format conversion (if necessary).
|
// Prepare for pixel format conversion (if necessary).
|
||||||
IFS(IWICImagingFactory_CreateFormatConverter(pFactory, &pConverter));
|
IFS(IWICImagingFactory_CreateFormatConverter(pFactory, &pConverter));
|
||||||
|
|
||||||
|
for (importer = has_alpha ? alphaFormatImporters : nonAlphaFormatImporters;
|
||||||
|
hr == S_OK && importer->import != NULL; ++importer) {
|
||||||
|
BOOL canConvert;
|
||||||
|
const HRESULT cchr = IWICFormatConverter_CanConvert(
|
||||||
|
pConverter,
|
||||||
|
MAKE_REFGUID(srcPixelFormat),
|
||||||
|
MAKE_REFGUID(*importer->pixel_format),
|
||||||
|
&canConvert);
|
||||||
|
if (SUCCEEDED(cchr) && canConvert) break;
|
||||||
|
}
|
||||||
|
if (importer->import == NULL) hr = E_FAIL;
|
||||||
|
|
||||||
IFS(IWICFormatConverter_Initialize(pConverter, (IWICBitmapSource*)pFrame,
|
IFS(IWICFormatConverter_Initialize(pConverter, (IWICBitmapSource*)pFrame,
|
||||||
has_alpha ? MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)
|
importer->pixel_format,
|
||||||
: MAKE_REFGUID(GUID_WICPixelFormat24bppRGB_),
|
|
||||||
WICBitmapDitherTypeNone,
|
WICBitmapDitherTypeNone,
|
||||||
NULL, 0.0, WICBitmapPaletteTypeCustom));
|
NULL, 0.0, WICBitmapPaletteTypeCustom));
|
||||||
|
|
||||||
// Decode.
|
// Decode.
|
||||||
IFS(IWICFormatConverter_GetSize(pConverter, &width, &height));
|
IFS(IWICFormatConverter_GetSize(pConverter, &width, &height));
|
||||||
stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
|
stride = importer->bytes_per_pixel * width * sizeof(*rgb);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
rgb = (BYTE*)malloc(stride * height);
|
rgb = (BYTE*)malloc(stride * height);
|
||||||
if (rgb == NULL)
|
if (rgb == NULL)
|
||||||
@ -218,8 +249,7 @@ static HRESULT ReadPictureWithWIC(const char* filename,
|
|||||||
int ok;
|
int ok;
|
||||||
pic->width = width;
|
pic->width = width;
|
||||||
pic->height = height;
|
pic->height = height;
|
||||||
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
|
ok = importer->import(pic, rgb, stride);
|
||||||
: WebPPictureImportRGB(pic, rgb, stride);
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -67,14 +67,12 @@ typedef enum {
|
|||||||
|
|
||||||
#ifdef HAVE_WINCODEC_H
|
#ifdef HAVE_WINCODEC_H
|
||||||
|
|
||||||
#define IFS(fn) \
|
#define IFS(fn) \
|
||||||
do { \
|
do { \
|
||||||
if (SUCCEEDED(hr)) \
|
if (SUCCEEDED(hr)) { \
|
||||||
{ \
|
hr = (fn); \
|
||||||
hr = (fn); \
|
if (FAILED(hr)) fprintf(stderr, #fn " failed %08x\n", hr); \
|
||||||
if (FAILED(hr) && verbose) \
|
} \
|
||||||
fprintf(stderr, #fn " failed %08x\n", hr); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -20,7 +20,11 @@ libwebp_la_LIBADD += dsp/libwebpdsp.la
|
|||||||
libwebp_la_LIBADD += enc/libwebpencode.la
|
libwebp_la_LIBADD += enc/libwebpencode.la
|
||||||
libwebp_la_LIBADD += utils/libwebputils.la
|
libwebp_la_LIBADD += utils/libwebputils.la
|
||||||
|
|
||||||
libwebp_la_LDFLAGS = -version-info 4:0:0
|
# Use '-no-undefined' to declare that libwebp does not depend on any libraries
|
||||||
|
# other than the ones listed on the command line, i.e., after linking, it will
|
||||||
|
# not have unresolved symbols. Some platforms (Windows among them) require all
|
||||||
|
# symbols in shared libraries to be resolved at library creation.
|
||||||
|
libwebp_la_LDFLAGS = -no-undefined -version-info 4:1:0
|
||||||
libwebpincludedir = $(includedir)/webp
|
libwebpincludedir = $(includedir)/webp
|
||||||
|
|
||||||
pkgconfig_DATA = libwebp.pc
|
pkgconfig_DATA = libwebp.pc
|
||||||
|
122
src/dec/io.c
122
src/dec/io.c
@ -111,7 +111,7 @@ static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const uint8_t* top_u = p->tmp_u;
|
const uint8_t* top_u = p->tmp_u;
|
||||||
const uint8_t* top_v = p->tmp_v;
|
const uint8_t* top_v = p->tmp_v;
|
||||||
int y = io->mb_y;
|
int y = io->mb_y;
|
||||||
int y_end = io->mb_y + io->mb_h;
|
const int y_end = io->mb_y + io->mb_h;
|
||||||
const int mb_w = io->mb_w;
|
const int mb_w = io->mb_w;
|
||||||
const int uv_w = (mb_w + 1) / 2;
|
const int uv_w = (mb_w + 1) / 2;
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
// Process the very last row of even-sized picture
|
// Process the very last row of even-sized picture
|
||||||
if (!(y_end & 1)) {
|
if (!(y_end & 1)) {
|
||||||
upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,
|
upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,
|
||||||
dst + buf->stride, NULL, mb_w);
|
dst + buf->stride, NULL, mb_w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return num_lines_out;
|
return num_lines_out;
|
||||||
@ -184,49 +184,60 @@ static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetAlphaSourceRow(const VP8Io* const io,
|
||||||
|
const uint8_t** alpha, int* const num_rows) {
|
||||||
|
int start_y = io->mb_y;
|
||||||
|
*num_rows = io->mb_h;
|
||||||
|
|
||||||
|
// Compensate for the 1-line delay of the fancy upscaler.
|
||||||
|
// This is similar to EmitFancyRGB().
|
||||||
|
if (io->fancy_upsampling) {
|
||||||
|
if (start_y == 0) {
|
||||||
|
// We don't process the last row yet. It'll be done during the next call.
|
||||||
|
--*num_rows;
|
||||||
|
} else {
|
||||||
|
--start_y;
|
||||||
|
// Fortunately, *alpha data is persistent, so we can go back
|
||||||
|
// one row and finish alpha blending, now that the fancy upscaler
|
||||||
|
// completed the YUV->RGB interpolation.
|
||||||
|
*alpha -= io->width;
|
||||||
|
}
|
||||||
|
if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) {
|
||||||
|
// If it's the very last call, we process all the remaining rows!
|
||||||
|
*num_rows = io->crop_bottom - io->crop_top - start_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return start_y;
|
||||||
|
}
|
||||||
|
|
||||||
static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
|
static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
|
||||||
const uint8_t* alpha = io->a;
|
const uint8_t* alpha = io->a;
|
||||||
if (alpha != NULL) {
|
if (alpha != NULL) {
|
||||||
const int mb_w = io->mb_w;
|
const int mb_w = io->mb_w;
|
||||||
const int mb_h = io->mb_h;
|
|
||||||
int i, j;
|
|
||||||
const WEBP_CSP_MODE colorspace = p->output->colorspace;
|
const WEBP_CSP_MODE colorspace = p->output->colorspace;
|
||||||
const int alpha_first =
|
const int alpha_first =
|
||||||
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
|
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
|
||||||
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
||||||
int start_y = io->mb_y;
|
int num_rows;
|
||||||
int num_rows = mb_h;
|
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
|
||||||
|
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
|
||||||
|
uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
|
||||||
|
uint32_t alpha_mask = 0xff;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
// We compensate for the 1-line delay of fancy upscaler.
|
for (j = 0; j < num_rows; ++j) {
|
||||||
// This is similar to EmitFancyRGB().
|
for (i = 0; i < mb_w; ++i) {
|
||||||
if (io->fancy_upsampling) {
|
const uint32_t alpha_value = alpha[i];
|
||||||
if (start_y == 0) {
|
dst[4 * i] = alpha_value;
|
||||||
// We don't process the last row yet. It'll be done during next call.
|
alpha_mask &= alpha_value;
|
||||||
--num_rows;
|
|
||||||
} else {
|
|
||||||
--start_y;
|
|
||||||
// Fortunately, *alpha data is persistent, so we can go back
|
|
||||||
// one row and finish alpha blending, now that the fancy upscaler
|
|
||||||
// completed the YUV->RGB interpolation.
|
|
||||||
alpha -= io->width;
|
|
||||||
}
|
|
||||||
if (io->crop_top + io->mb_y + mb_h == io->crop_bottom) {
|
|
||||||
// If it's the very last call, we process all the remaing rows!
|
|
||||||
num_rows = io->crop_bottom - io->crop_top - start_y;
|
|
||||||
}
|
}
|
||||||
|
alpha += io->width;
|
||||||
|
dst += buf->stride;
|
||||||
}
|
}
|
||||||
{
|
// alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
|
||||||
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
|
if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) {
|
||||||
uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
|
WebPApplyAlphaMultiply(base_rgba, alpha_first,
|
||||||
for (j = 0; j < num_rows; ++j) {
|
mb_w, num_rows, buf->stride);
|
||||||
for (i = 0; i < mb_w; ++i) dst[4 * i] = alpha[i];
|
|
||||||
alpha += io->width;
|
|
||||||
dst += buf->stride;
|
|
||||||
}
|
|
||||||
if (WebPIsPremultipliedMode(colorspace)) {
|
|
||||||
WebPApplyAlphaMultiply(base_rgba, alpha_first,
|
|
||||||
mb_w, num_rows, buf->stride);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -236,22 +247,27 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const uint8_t* alpha = io->a;
|
const uint8_t* alpha = io->a;
|
||||||
if (alpha != NULL) {
|
if (alpha != NULL) {
|
||||||
const int mb_w = io->mb_w;
|
const int mb_w = io->mb_w;
|
||||||
const int mb_h = io->mb_h;
|
const WEBP_CSP_MODE colorspace = p->output->colorspace;
|
||||||
int i, j;
|
|
||||||
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
||||||
uint8_t* const base_rgba = buf->rgba + io->mb_y * buf->stride;
|
int num_rows;
|
||||||
|
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
|
||||||
|
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
|
||||||
uint8_t* alpha_dst = base_rgba + 1;
|
uint8_t* alpha_dst = base_rgba + 1;
|
||||||
for (j = 0; j < mb_h; ++j) {
|
uint32_t alpha_mask = 0x0f;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (j = 0; j < num_rows; ++j) {
|
||||||
for (i = 0; i < mb_w; ++i) {
|
for (i = 0; i < mb_w; ++i) {
|
||||||
// Fill in the alpha value (converted to 4 bits).
|
// Fill in the alpha value (converted to 4 bits).
|
||||||
const uint32_t alpha_val = VP8Clip4Bits(alpha[i]);
|
const uint32_t alpha_value = alpha[i] >> 4;
|
||||||
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_val;
|
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
|
||||||
|
alpha_mask &= alpha_value;
|
||||||
}
|
}
|
||||||
alpha += io->width;
|
alpha += io->width;
|
||||||
alpha_dst += buf->stride;
|
alpha_dst += buf->stride;
|
||||||
}
|
}
|
||||||
if (p->output->colorspace == MODE_rgbA_4444) {
|
if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) {
|
||||||
WebPApplyAlphaMultiply4444(base_rgba, mb_w, mb_h, buf->stride);
|
WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -396,17 +412,22 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos) {
|
|||||||
uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
|
uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
||||||
|
uint32_t alpha_mask = 0xff;
|
||||||
const int width = p->scaler_a.dst_width;
|
const int width = p->scaler_a.dst_width;
|
||||||
|
|
||||||
while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
|
while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
|
||||||
int i;
|
int i;
|
||||||
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
assert(p->last_y + y_pos + num_lines_out < p->output->height);
|
||||||
WebPRescalerExportRow(&p->scaler_a);
|
WebPRescalerExportRow(&p->scaler_a);
|
||||||
for (i = 0; i < width; ++i) dst[4 * i] = p->scaler_a.dst[i];
|
for (i = 0; i < width; ++i) {
|
||||||
|
const uint32_t alpha_value = p->scaler_a.dst[i];
|
||||||
|
dst[4 * i] = alpha_value;
|
||||||
|
alpha_mask &= alpha_value;
|
||||||
|
}
|
||||||
dst += buf->stride;
|
dst += buf->stride;
|
||||||
++num_lines_out;
|
++num_lines_out;
|
||||||
}
|
}
|
||||||
if (is_premult_alpha) {
|
if (is_premult_alpha && alpha_mask != 0xff) {
|
||||||
WebPApplyAlphaMultiply(base_rgba, alpha_first,
|
WebPApplyAlphaMultiply(base_rgba, alpha_first,
|
||||||
width, num_lines_out, buf->stride);
|
width, num_lines_out, buf->stride);
|
||||||
}
|
}
|
||||||
@ -421,6 +442,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
|
|||||||
const WEBP_CSP_MODE colorspace = p->output->colorspace;
|
const WEBP_CSP_MODE colorspace = p->output->colorspace;
|
||||||
const int width = p->scaler_a.dst_width;
|
const int width = p->scaler_a.dst_width;
|
||||||
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
|
||||||
|
uint32_t alpha_mask = 0x0f;
|
||||||
|
|
||||||
while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
|
while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
|
||||||
int i;
|
int i;
|
||||||
@ -428,13 +450,14 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
|
|||||||
WebPRescalerExportRow(&p->scaler_a);
|
WebPRescalerExportRow(&p->scaler_a);
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
// Fill in the alpha value (converted to 4 bits).
|
// Fill in the alpha value (converted to 4 bits).
|
||||||
const uint32_t alpha_val = VP8Clip4Bits(p->scaler_a.dst[i]);
|
const uint32_t alpha_value = p->scaler_a.dst[i] >> 4;
|
||||||
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_val;
|
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
|
||||||
|
alpha_mask &= alpha_value;
|
||||||
}
|
}
|
||||||
alpha_dst += buf->stride;
|
alpha_dst += buf->stride;
|
||||||
++num_lines_out;
|
++num_lines_out;
|
||||||
}
|
}
|
||||||
if (is_premult_alpha) {
|
if (is_premult_alpha && alpha_mask != 0x0f) {
|
||||||
WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
|
WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
|
||||||
}
|
}
|
||||||
return num_lines_out;
|
return num_lines_out;
|
||||||
@ -471,8 +494,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
tmp_size1 += work_size;
|
tmp_size1 += work_size;
|
||||||
tmp_size2 += out_width;
|
tmp_size2 += out_width;
|
||||||
}
|
}
|
||||||
p->memory =
|
p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
|
||||||
calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
|
|
||||||
if (p->memory == NULL) {
|
if (p->memory == NULL) {
|
||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
@ -569,7 +591,7 @@ static int CustomSetup(VP8Io* io) {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static int CustomPut(const VP8Io* io) {
|
static int CustomPut(const VP8Io* io) {
|
||||||
WebPDecParams* p = (WebPDecParams*)io->opaque;
|
WebPDecParams* const p = (WebPDecParams*)io->opaque;
|
||||||
const int mb_w = io->mb_w;
|
const int mb_w = io->mb_w;
|
||||||
const int mb_h = io->mb_h;
|
const int mb_h = io->mb_h;
|
||||||
int num_lines_out;
|
int num_lines_out;
|
||||||
|
@ -28,7 +28,7 @@ extern "C" {
|
|||||||
// version numbers
|
// version numbers
|
||||||
#define DEC_MAJ_VERSION 0
|
#define DEC_MAJ_VERSION 0
|
||||||
#define DEC_MIN_VERSION 2
|
#define DEC_MIN_VERSION 2
|
||||||
#define DEC_REV_VERSION 0
|
#define DEC_REV_VERSION 1
|
||||||
|
|
||||||
#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames
|
#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames
|
||||||
|
|
||||||
|
@ -615,20 +615,22 @@ static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr,
|
|||||||
|
|
||||||
typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row);
|
typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row);
|
||||||
|
|
||||||
static void ApplyTransforms(VP8LDecoder* const dec, int num_rows,
|
static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
|
||||||
const uint32_t* const rows) {
|
const uint32_t* const rows) {
|
||||||
int n = dec->next_transform_;
|
int n = dec->next_transform_;
|
||||||
const int cache_pixs = dec->width_ * num_rows;
|
const int cache_pixs = dec->width_ * num_rows;
|
||||||
uint32_t* rows_data = dec->argb_cache_;
|
|
||||||
const int start_row = dec->last_row_;
|
const int start_row = dec->last_row_;
|
||||||
const int end_row = start_row + num_rows;
|
const int end_row = start_row + num_rows;
|
||||||
|
const uint32_t* rows_in = rows;
|
||||||
|
uint32_t* const rows_out = dec->argb_cache_;
|
||||||
|
|
||||||
// Inverse transforms.
|
// Inverse transforms.
|
||||||
// TODO: most transforms only need to operate on the cropped region only.
|
// TODO: most transforms only need to operate on the cropped region only.
|
||||||
memcpy(rows_data, rows, cache_pixs * sizeof(*rows_data));
|
memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
VP8LTransform* const transform = &dec->transforms_[n];
|
VP8LTransform* const transform = &dec->transforms_[n];
|
||||||
VP8LInverseTransform(transform, start_row, end_row, rows, rows_data);
|
VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
|
||||||
|
rows_in = rows_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,7 +641,7 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
|
|||||||
const int num_rows = row - dec->last_row_;
|
const int num_rows = row - dec->last_row_;
|
||||||
|
|
||||||
if (num_rows <= 0) return; // Nothing to be done.
|
if (num_rows <= 0) return; // Nothing to be done.
|
||||||
ApplyTransforms(dec, num_rows, rows);
|
ApplyInverseTransforms(dec, num_rows, rows);
|
||||||
|
|
||||||
// Emit output.
|
// Emit output.
|
||||||
{
|
{
|
||||||
@ -797,19 +799,6 @@ static void ClearTransform(VP8LTransform* const transform) {
|
|||||||
transform->data_ = NULL;
|
transform->data_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyInverseTransforms(VP8LDecoder* const dec, int start_idx,
|
|
||||||
uint32_t* const decoded_data) {
|
|
||||||
int n = dec->next_transform_;
|
|
||||||
assert(start_idx >= 0);
|
|
||||||
while (n-- > start_idx) {
|
|
||||||
VP8LTransform* const transform = &dec->transforms_[n];
|
|
||||||
VP8LInverseTransform(transform, 0, transform->ysize_,
|
|
||||||
decoded_data, decoded_data);
|
|
||||||
ClearTransform(transform);
|
|
||||||
}
|
|
||||||
dec->next_transform_ = start_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For security reason, we need to remap the color map to span
|
// For security reason, we need to remap the color map to span
|
||||||
// the total possible bundled values, and not just the num_colors.
|
// the total possible bundled values, and not just the num_colors.
|
||||||
static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
|
static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
|
||||||
@ -964,7 +953,6 @@ static int DecodeImageStream(int xsize, int ysize,
|
|||||||
VP8LBitReader* const br = &dec->br_;
|
VP8LBitReader* const br = &dec->br_;
|
||||||
VP8LMetadata* const hdr = &dec->hdr_;
|
VP8LMetadata* const hdr = &dec->hdr_;
|
||||||
uint32_t* data = NULL;
|
uint32_t* data = NULL;
|
||||||
const int transform_start_idx = dec->next_transform_;
|
|
||||||
int color_cache_bits = 0;
|
int color_cache_bits = 0;
|
||||||
|
|
||||||
// Read the transforms (may recurse).
|
// Read the transforms (may recurse).
|
||||||
@ -1024,9 +1012,6 @@ static int DecodeImageStream(int xsize, int ysize,
|
|||||||
ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, NULL);
|
ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, NULL);
|
||||||
ok = ok && !br->error_;
|
ok = ok && !br->error_;
|
||||||
|
|
||||||
// Apply transforms on the decoded data.
|
|
||||||
if (ok) ApplyInverseTransforms(dec, transform_start_idx, data);
|
|
||||||
|
|
||||||
End:
|
End:
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@ -1083,7 +1068,7 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int row) {
|
|||||||
const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_;
|
const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_;
|
||||||
|
|
||||||
if (num_rows <= 0) return; // Nothing to be done.
|
if (num_rows <= 0) return; // Nothing to be done.
|
||||||
ApplyTransforms(dec, num_rows, in);
|
ApplyInverseTransforms(dec, num_rows, in);
|
||||||
|
|
||||||
// Extract alpha (which is stored in the green plane).
|
// Extract alpha (which is stored in the green plane).
|
||||||
{
|
{
|
||||||
|
@ -76,6 +76,9 @@ static VP8StatusCode ParseRIFF(const uint8_t** const data,
|
|||||||
if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
|
if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
|
||||||
return VP8_STATUS_BITSTREAM_ERROR;
|
return VP8_STATUS_BITSTREAM_ERROR;
|
||||||
}
|
}
|
||||||
|
if (size > MAX_CHUNK_PAYLOAD) {
|
||||||
|
return VP8_STATUS_BITSTREAM_ERROR;
|
||||||
|
}
|
||||||
// We have a RIFF container. Skip it.
|
// We have a RIFF container. Skip it.
|
||||||
*riff_size = size;
|
*riff_size = size;
|
||||||
*data += RIFF_HEADER_SIZE;
|
*data += RIFF_HEADER_SIZE;
|
||||||
@ -177,6 +180,9 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
chunk_size = get_le32(buf + TAG_SIZE);
|
chunk_size = get_le32(buf + TAG_SIZE);
|
||||||
|
if (chunk_size > MAX_CHUNK_PAYLOAD) {
|
||||||
|
return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
|
||||||
|
}
|
||||||
// For odd-sized chunk-payload, there's one byte padding at the end.
|
// For odd-sized chunk-payload, there's one byte padding at the end.
|
||||||
disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
|
disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
|
||||||
total_size += disk_chunk_size;
|
total_size += disk_chunk_size;
|
||||||
|
@ -12,14 +12,14 @@
|
|||||||
|
|
||||||
#include "./dsp.h"
|
#include "./dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
|
|
||||||
#include "../dec/vp8i.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
|
||||||
|
#include "../dec/vp8i.h"
|
||||||
|
|
||||||
#define QRegs "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", \
|
#define QRegs "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", \
|
||||||
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
|
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
|
||||||
|
|
||||||
@ -311,19 +311,24 @@ static void TransformTwoNEON(const int16_t* in, uint8_t* dst, int do_two) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_USE_NEON
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Entry point
|
||||||
|
|
||||||
extern void VP8DspInitNEON(void);
|
extern void VP8DspInitNEON(void);
|
||||||
|
|
||||||
void VP8DspInitNEON(void) {
|
void VP8DspInitNEON(void) {
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
VP8Transform = TransformTwoNEON;
|
VP8Transform = TransformTwoNEON;
|
||||||
|
|
||||||
VP8SimpleVFilter16 = SimpleVFilter16NEON;
|
VP8SimpleVFilter16 = SimpleVFilter16NEON;
|
||||||
VP8SimpleHFilter16 = SimpleHFilter16NEON;
|
VP8SimpleHFilter16 = SimpleHFilter16NEON;
|
||||||
VP8SimpleVFilter16i = SimpleVFilter16iNEON;
|
VP8SimpleVFilter16i = SimpleVFilter16iNEON;
|
||||||
VP8SimpleHFilter16i = SimpleHFilter16iNEON;
|
VP8SimpleHFilter16i = SimpleHFilter16iNEON;
|
||||||
|
#endif // WEBP_USE_NEON
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_USE_NEON
|
|
||||||
|
@ -12,15 +12,15 @@
|
|||||||
|
|
||||||
#include "./dsp.h"
|
#include "./dsp.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
#include "../dec/vp8i.h"
|
#include "../dec/vp8i.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Transforms (Paragraph 14.4)
|
// Transforms (Paragraph 14.4)
|
||||||
|
|
||||||
@ -876,9 +876,15 @@ static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
|
|||||||
Store16x4(u, v, stride, &p1, &p0, &q0, &q1);
|
Store16x4(u, v, stride, &p1, &p0, &q0, &q1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE2
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Entry point
|
||||||
|
|
||||||
extern void VP8DspInitSSE2(void);
|
extern void VP8DspInitSSE2(void);
|
||||||
|
|
||||||
void VP8DspInitSSE2(void) {
|
void VP8DspInitSSE2(void) {
|
||||||
|
#if defined(WEBP_USE_SSE2)
|
||||||
VP8Transform = TransformSSE2;
|
VP8Transform = TransformSSE2;
|
||||||
|
|
||||||
VP8VFilter16 = VFilter16SSE2;
|
VP8VFilter16 = VFilter16SSE2;
|
||||||
@ -894,10 +900,9 @@ void VP8DspInitSSE2(void) {
|
|||||||
VP8SimpleHFilter16 = SimpleHFilter16SSE2;
|
VP8SimpleHFilter16 = SimpleHFilter16SSE2;
|
||||||
VP8SimpleVFilter16i = SimpleVFilter16iSSE2;
|
VP8SimpleVFilter16i = SimpleVFilter16iSSE2;
|
||||||
VP8SimpleHFilter16i = SimpleHFilter16iSSE2;
|
VP8SimpleHFilter16i = SimpleHFilter16iSSE2;
|
||||||
|
#endif // WEBP_USE_SSE2
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_USE_SSE2
|
|
||||||
|
@ -11,16 +11,16 @@
|
|||||||
|
|
||||||
#include "./dsp.h"
|
#include "./dsp.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
#include <stdlib.h> // for abs()
|
#include <stdlib.h> // for abs()
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
#include "../enc/vp8enci.h"
|
#include "../enc/vp8enci.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Compute susceptibility based on DCT-coeff histograms:
|
// Compute susceptibility based on DCT-coeff histograms:
|
||||||
// the higher, the "easier" the macroblock is to compress.
|
// the higher, the "easier" the macroblock is to compress.
|
||||||
@ -819,8 +819,15 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE2
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Entry point
|
||||||
|
|
||||||
extern void VP8EncDspInitSSE2(void);
|
extern void VP8EncDspInitSSE2(void);
|
||||||
|
|
||||||
void VP8EncDspInitSSE2(void) {
|
void VP8EncDspInitSSE2(void) {
|
||||||
|
#if defined(WEBP_USE_SSE2)
|
||||||
VP8CollectHistogram = CollectHistogramSSE2;
|
VP8CollectHistogram = CollectHistogramSSE2;
|
||||||
VP8EncQuantizeBlock = QuantizeBlockSSE2;
|
VP8EncQuantizeBlock = QuantizeBlockSSE2;
|
||||||
VP8ITransform = ITransformSSE2;
|
VP8ITransform = ITransformSSE2;
|
||||||
@ -828,10 +835,9 @@ void VP8EncDspInitSSE2(void) {
|
|||||||
VP8SSE4x4 = SSE4x4SSE2;
|
VP8SSE4x4 = SSE4x4SSE2;
|
||||||
VP8TDisto4x4 = Disto4x4SSE2;
|
VP8TDisto4x4 = Disto4x4SSE2;
|
||||||
VP8TDisto16x16 = Disto16x16SSE2;
|
VP8TDisto16x16 = Disto16x16SSE2;
|
||||||
|
#endif // WEBP_USE_SSE2
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_USE_SSE2
|
|
||||||
|
@ -935,7 +935,7 @@ static void ColorIndexInverseTransform(
|
|||||||
uint32_t packed_pixels = 0;
|
uint32_t packed_pixels = 0;
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
// We need to load fresh 'packed_pixels' once every 'bytes_per_pixels'
|
// We need to load fresh 'packed_pixels' once every 'pixels_per_byte'
|
||||||
// increments of x. Fortunately, pixels_per_byte is a power of 2, so
|
// increments of x. Fortunately, pixels_per_byte is a power of 2, so
|
||||||
// can just use a mask for that, instead of decrementing a counter.
|
// can just use a mask for that, instead of decrementing a counter.
|
||||||
if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff;
|
if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff;
|
||||||
@ -976,7 +976,21 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
|
|||||||
ColorSpaceInverseTransform(transform, row_start, row_end, out);
|
ColorSpaceInverseTransform(transform, row_start, row_end, out);
|
||||||
break;
|
break;
|
||||||
case COLOR_INDEXING_TRANSFORM:
|
case COLOR_INDEXING_TRANSFORM:
|
||||||
ColorIndexInverseTransform(transform, row_start, row_end, in, out);
|
if (in == out && transform->bits_ > 0) {
|
||||||
|
// Move packed pixels to the end of unpacked region, so that unpacking
|
||||||
|
// can occur seamlessly.
|
||||||
|
// Also, note that this is the only transform that applies on
|
||||||
|
// the effective width of VP8LSubSampleSize(xsize_, bits_). All other
|
||||||
|
// transforms work on effective width of xsize_.
|
||||||
|
const int out_stride = (row_end - row_start) * transform->xsize_;
|
||||||
|
const int in_stride = (row_end - row_start) *
|
||||||
|
VP8LSubSampleSize(transform->xsize_, transform->bits_);
|
||||||
|
uint32_t* const src = out + out_stride - in_stride;
|
||||||
|
memmove(src, out, in_stride * sizeof(*src));
|
||||||
|
ColorIndexInverseTransform(transform, row_start, row_end, src, out);
|
||||||
|
} else {
|
||||||
|
ColorIndexInverseTransform(transform, row_start, row_end, in, out);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,8 +271,7 @@ static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
|
|||||||
|
|
||||||
// rgbA4444
|
// rgbA4444
|
||||||
|
|
||||||
#define MULTIPLIER(a) ((a) * 0x11)
|
#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
|
||||||
#define PREMULTIPLY(x, m) (((x) * (m)) >> 12)
|
|
||||||
|
|
||||||
static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
|
static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
|
||||||
return (x & 0xf0) | (x >> 4);
|
return (x & 0xf0) | (x >> 4);
|
||||||
@ -282,24 +281,27 @@ static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
|
|||||||
return (x & 0x0f) | (x << 4);
|
return (x & 0x0f) | (x << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
|
||||||
|
return (x * m) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
static void ApplyAlphaMultiply4444(uint8_t* rgba4444,
|
static void ApplyAlphaMultiply4444(uint8_t* rgba4444,
|
||||||
int w, int h, int stride) {
|
int w, int h, int stride) {
|
||||||
while (h-- > 0) {
|
while (h-- > 0) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < w; ++i) {
|
for (i = 0; i < w; ++i) {
|
||||||
const uint8_t a = dither_lo(rgba4444[2 * i + 1]);
|
const uint8_t a = (rgba4444[2 * i + 1] & 0x0f);
|
||||||
const uint32_t mult = MULTIPLIER(a);
|
const uint32_t mult = MULTIPLIER(a);
|
||||||
const uint8_t r = PREMULTIPLY(dither_hi(rgba4444[2 * i + 0]), mult);
|
const uint8_t r = multiply(dither_hi(rgba4444[2 * i + 0]), mult);
|
||||||
const uint8_t g = PREMULTIPLY(dither_lo(rgba4444[2 * i + 0]), mult);
|
const uint8_t g = multiply(dither_lo(rgba4444[2 * i + 0]), mult);
|
||||||
const uint8_t b = PREMULTIPLY(dither_hi(rgba4444[2 * i + 1]), mult);
|
const uint8_t b = multiply(dither_hi(rgba4444[2 * i + 1]), mult);
|
||||||
rgba4444[2 * i + 0] = (r & 0xf0) | (g & 0x0f);
|
rgba4444[2 * i + 0] = (r & 0xf0) | ((g >> 4) & 0x0f);
|
||||||
rgba4444[2 * i + 1] = (b & 0xf0) | a;
|
rgba4444[2 * i + 1] = (b & 0xf0) | a;
|
||||||
}
|
}
|
||||||
rgba4444 += stride;
|
rgba4444 += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef MULTIPLIER
|
#undef MULTIPLIER
|
||||||
#undef PREMULTIPLY
|
|
||||||
|
|
||||||
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
|
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
|
||||||
= ApplyAlphaMultiply;
|
= ApplyAlphaMultiply;
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
#include "./dsp.h"
|
#include "./dsp.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -18,10 +22,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "./yuv.h"
|
#include "./yuv.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
#ifdef FANCY_UPSAMPLING
|
||||||
|
|
||||||
// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows
|
// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows
|
||||||
@ -184,26 +184,32 @@ SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4)
|
|||||||
#undef CONVERT2RGB
|
#undef CONVERT2RGB
|
||||||
#undef SSE2_UPSAMPLE_FUNC
|
#undef SSE2_UPSAMPLE_FUNC
|
||||||
|
|
||||||
|
#endif // FANCY_UPSAMPLING
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE2
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
||||||
|
|
||||||
void WebPInitUpsamplersSSE2(void) {
|
void WebPInitUpsamplersSSE2(void) {
|
||||||
|
#if defined(WEBP_USE_SSE2)
|
||||||
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairSSE2;
|
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairSSE2;
|
||||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2;
|
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2;
|
||||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2;
|
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2;
|
||||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2;
|
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2;
|
||||||
|
#endif // WEBP_USE_SSE2
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPInitPremultiplySSE2(void) {
|
void WebPInitPremultiplySSE2(void) {
|
||||||
|
#if defined(WEBP_USE_SSE2)
|
||||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2;
|
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2;
|
||||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2;
|
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2;
|
||||||
|
#endif // WEBP_USE_SSE2
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FANCY_UPSAMPLING
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_USE_SSE2
|
|
||||||
|
@ -90,11 +90,6 @@ static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
|
|||||||
rgba[3] = 0xff;
|
rgba[3] = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t VP8Clip4Bits(uint8_t c) {
|
|
||||||
const uint32_t v = (c + 8) >> 4;
|
|
||||||
return (v > 15) ? 15 : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be called before everything, to initialize the tables.
|
// Must be called before everything, to initialize the tables.
|
||||||
void VP8YUVInit(void);
|
void VP8YUVInit(void);
|
||||||
|
|
||||||
|
@ -459,8 +459,8 @@ static int BackwardReferencesHashChainDistanceOnly(
|
|||||||
const int quality = 100;
|
const int quality = 100;
|
||||||
const int pix_count = xsize * ysize;
|
const int pix_count = xsize * ysize;
|
||||||
const int use_color_cache = (cache_bits > 0);
|
const int use_color_cache = (cache_bits > 0);
|
||||||
double* const cost =
|
float* const cost =
|
||||||
(double*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
|
(float*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
|
||||||
CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model));
|
CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model));
|
||||||
HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
|
HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
|
||||||
VP8LColorCache hashers;
|
VP8LColorCache hashers;
|
||||||
@ -481,7 +481,7 @@ static int BackwardReferencesHashChainDistanceOnly(
|
|||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < pix_count; ++i) cost[i] = 1e100;
|
for (i = 0; i < pix_count; ++i) cost[i] = 1e38f;
|
||||||
|
|
||||||
// We loop one pixel at a time, but store all currently best points to
|
// We loop one pixel at a time, but store all currently best points to
|
||||||
// non-processed locations from this point.
|
// non-processed locations from this point.
|
||||||
@ -509,10 +509,9 @@ static int BackwardReferencesHashChainDistanceOnly(
|
|||||||
prev_cost + GetDistanceCost(cost_model, code);
|
prev_cost + GetDistanceCost(cost_model, code);
|
||||||
int k;
|
int k;
|
||||||
for (k = 1; k < len; ++k) {
|
for (k = 1; k < len; ++k) {
|
||||||
const double cost_val =
|
const double cost_val = distance_cost + GetLengthCost(cost_model, k);
|
||||||
distance_cost + GetLengthCost(cost_model, k);
|
|
||||||
if (cost[i + k] > cost_val) {
|
if (cost[i + k] > cost_val) {
|
||||||
cost[i + k] = cost_val;
|
cost[i + k] = (float)cost_val;
|
||||||
dist_array[i + k] = k + 1;
|
dist_array[i + k] = k + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,7 +553,7 @@ static int BackwardReferencesHashChainDistanceOnly(
|
|||||||
cost_val += GetLiteralCost(cost_model, argb[i]) * mul1;
|
cost_val += GetLiteralCost(cost_model, argb[i]) * mul1;
|
||||||
}
|
}
|
||||||
if (cost[i] > cost_val) {
|
if (cost[i] > cost_val) {
|
||||||
cost[i] = cost_val;
|
cost[i] = (float)cost_val;
|
||||||
dist_array[i] = 1; // only one is inserted.
|
dist_array[i] = 1; // only one is inserted.
|
||||||
}
|
}
|
||||||
if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
|
if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
|
||||||
|
@ -55,9 +55,9 @@ VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
|
|||||||
int i;
|
int i;
|
||||||
VP8LHistogramSet* set;
|
VP8LHistogramSet* set;
|
||||||
VP8LHistogram* bulk;
|
VP8LHistogram* bulk;
|
||||||
const uint64_t total_size = (uint64_t)sizeof(*set)
|
const uint64_t total_size = sizeof(*set)
|
||||||
+ size * sizeof(*set->histograms)
|
+ (uint64_t)size * sizeof(*set->histograms)
|
||||||
+ size * sizeof(**set->histograms);
|
+ (uint64_t)size * sizeof(**set->histograms);
|
||||||
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
|
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
|
||||||
if (memory == NULL) return NULL;
|
if (memory == NULL) return NULL;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ extern "C" {
|
|||||||
// version numbers
|
// version numbers
|
||||||
#define ENC_MAJ_VERSION 0
|
#define ENC_MAJ_VERSION 0
|
||||||
#define ENC_MIN_VERSION 2
|
#define ENC_MIN_VERSION 2
|
||||||
#define ENC_REV_VERSION 0
|
#define ENC_REV_VERSION 1
|
||||||
|
|
||||||
// size of histogram used by CollectHistogram.
|
// size of histogram used by CollectHistogram.
|
||||||
#define MAX_COEFF_THRESH 64
|
#define MAX_COEFF_THRESH 64
|
||||||
|
@ -29,6 +29,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
|
#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
|
||||||
#define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
|
#define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
|
||||||
|
#define MAX_COLORS_FOR_GRAPH 64
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Palette
|
// Palette
|
||||||
@ -98,11 +99,11 @@ static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int AnalyzeEntropy(const WebPPicture* const pic,
|
static int AnalyzeEntropy(const uint32_t* argb,
|
||||||
|
int width, int height, int argb_stride,
|
||||||
double* const nonpredicted_bits,
|
double* const nonpredicted_bits,
|
||||||
double* const predicted_bits) {
|
double* const predicted_bits) {
|
||||||
int x, y;
|
int x, y;
|
||||||
const uint32_t* argb = pic->argb;
|
|
||||||
const uint32_t* last_line = NULL;
|
const uint32_t* last_line = NULL;
|
||||||
uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
|
uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
|
||||||
|
|
||||||
@ -114,8 +115,8 @@ static int AnalyzeEntropy(const WebPPicture* const pic,
|
|||||||
|
|
||||||
VP8LHistogramInit(predicted, 0);
|
VP8LHistogramInit(predicted, 0);
|
||||||
VP8LHistogramInit(nonpredicted, 0);
|
VP8LHistogramInit(nonpredicted, 0);
|
||||||
for (y = 0; y < pic->height; ++y) {
|
for (y = 0; y < height; ++y) {
|
||||||
for (x = 0; x < pic->width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
const uint32_t pix = argb[x];
|
const uint32_t pix = argb[x];
|
||||||
const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
|
const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
|
||||||
if (pix_diff == 0) continue;
|
if (pix_diff == 0) continue;
|
||||||
@ -131,7 +132,7 @@ static int AnalyzeEntropy(const WebPPicture* const pic,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
last_line = argb;
|
last_line = argb;
|
||||||
argb += pic->argb_stride;
|
argb += argb_stride;
|
||||||
}
|
}
|
||||||
*nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
|
*nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
|
||||||
*predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
|
*predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
|
||||||
@ -143,24 +144,35 @@ static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
|
|||||||
const WebPPicture* const pic = enc->pic_;
|
const WebPPicture* const pic = enc->pic_;
|
||||||
assert(pic != NULL && pic->argb != NULL);
|
assert(pic != NULL && pic->argb != NULL);
|
||||||
|
|
||||||
enc->use_palette_ = (image_hint == WEBP_HINT_GRAPH) ? 0 :
|
enc->use_palette_ =
|
||||||
AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
|
AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
|
||||||
if (!enc->use_palette_) {
|
|
||||||
if (image_hint == WEBP_HINT_DEFAULT) {
|
|
||||||
double non_pred_entropy, pred_entropy;
|
|
||||||
if (!AnalyzeEntropy(pic, &non_pred_entropy, &pred_entropy)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pred_entropy < 0.95 * non_pred_entropy) {
|
if (image_hint == WEBP_HINT_GRAPH) {
|
||||||
enc->use_predict_ = 1;
|
if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) {
|
||||||
enc->use_cross_color_ = 1;
|
enc->use_palette_ = 0;
|
||||||
}
|
|
||||||
} else if (image_hint == WEBP_HINT_PHOTO) {
|
|
||||||
enc->use_predict_ = 1;
|
|
||||||
enc->use_cross_color_ = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!enc->use_palette_) {
|
||||||
|
if (image_hint == WEBP_HINT_PHOTO) {
|
||||||
|
enc->use_predict_ = 1;
|
||||||
|
enc->use_cross_color_ = 1;
|
||||||
|
} else {
|
||||||
|
double non_pred_entropy, pred_entropy;
|
||||||
|
if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride,
|
||||||
|
&non_pred_entropy, &pred_entropy)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (pred_entropy < 0.95 * non_pred_entropy) {
|
||||||
|
enc->use_predict_ = 1;
|
||||||
|
// TODO(vikasa): Observed some correlation of cross_color transform with
|
||||||
|
// predict. Need to investigate this further and add separate heuristic
|
||||||
|
// for setting use_cross_color flag.
|
||||||
|
enc->use_cross_color_ = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,7 +529,12 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
|
|||||||
sizeof(*histogram_symbols));
|
sizeof(*histogram_symbols));
|
||||||
assert(histogram_bits >= MIN_HUFFMAN_BITS);
|
assert(histogram_bits >= MIN_HUFFMAN_BITS);
|
||||||
assert(histogram_bits <= MAX_HUFFMAN_BITS);
|
assert(histogram_bits <= MAX_HUFFMAN_BITS);
|
||||||
if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
|
|
||||||
|
if (histogram_image == NULL || histogram_symbols == NULL) {
|
||||||
|
free(histogram_image);
|
||||||
|
free(histogram_symbols);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate backward references from ARGB image.
|
// Calculate backward references from ARGB image.
|
||||||
if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
|
if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
|
||||||
@ -886,13 +903,13 @@ static int GetHistoBits(const WebPConfig* const config,
|
|||||||
const WebPPicture* const pic) {
|
const WebPPicture* const pic) {
|
||||||
const int width = pic->width;
|
const int width = pic->width;
|
||||||
const int height = pic->height;
|
const int height = pic->height;
|
||||||
const size_t hist_size = sizeof(VP8LHistogram);
|
const uint64_t hist_size = sizeof(VP8LHistogram);
|
||||||
// Make tile size a function of encoding method (Range: 0 to 6).
|
// Make tile size a function of encoding method (Range: 0 to 6).
|
||||||
int histo_bits = 7 - config->method;
|
int histo_bits = 7 - config->method;
|
||||||
while (1) {
|
while (1) {
|
||||||
const size_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
|
const uint64_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
|
||||||
VP8LSubSampleSize(height, histo_bits) *
|
VP8LSubSampleSize(height, histo_bits) *
|
||||||
hist_size;
|
hist_size;
|
||||||
if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
|
if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
|
||||||
++histo_bits;
|
++histo_bits;
|
||||||
}
|
}
|
||||||
@ -961,6 +978,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
|||||||
if (enc->use_palette_) {
|
if (enc->use_palette_) {
|
||||||
err = ApplyPalette(bw, enc, quality);
|
err = ApplyPalette(bw, enc, quality);
|
||||||
if (err != VP8_ENC_OK) goto Error;
|
if (err != VP8_ENC_OK) goto Error;
|
||||||
|
// Color cache is disabled for palette.
|
||||||
enc->cache_bits_ = 0;
|
enc->cache_bits_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,8 @@ static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) {
|
|||||||
#elif (BITS == 16)
|
#elif (BITS == 16)
|
||||||
// gcc will recognize a 'rorw $8, ...' here:
|
// gcc will recognize a 'rorw $8, ...' here:
|
||||||
bits = (bit_t)(in_bits >> 8) | ((in_bits & 0xff) << 8);
|
bits = (bit_t)(in_bits >> 8) | ((in_bits & 0xff) << 8);
|
||||||
|
#else // BITS == 8
|
||||||
|
bits = (bit_t)in_bits;
|
||||||
#endif
|
#endif
|
||||||
#else // LITTLE_ENDIAN
|
#else // LITTLE_ENDIAN
|
||||||
bits = (bit_t)in_bits;
|
bits = (bit_t)in_bits;
|
||||||
|
Reference in New Issue
Block a user