Path: blob/master/3rdparty/libwebp/src/enc/picture_enc.c
16349 views
// Copyright 2011 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// WebPPicture class basis10//11// Author: Skal ([email protected])1213#include <assert.h>14#include <stdlib.h>1516#include "src/enc/vp8i_enc.h"17#include "src/dsp/dsp.h"18#include "src/utils/utils.h"1920//------------------------------------------------------------------------------21// WebPPicture22//------------------------------------------------------------------------------2324static int DummyWriter(const uint8_t* data, size_t data_size,25const WebPPicture* const picture) {26// The following are to prevent 'unused variable' error message.27(void)data;28(void)data_size;29(void)picture;30return 1;31}3233int WebPPictureInitInternal(WebPPicture* picture, int version) {34if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {35return 0; // caller/system version mismatch!36}37if (picture != NULL) {38memset(picture, 0, sizeof(*picture));39picture->writer = DummyWriter;40WebPEncodingSetError(picture, VP8_ENC_OK);41}42return 1;43}4445//------------------------------------------------------------------------------4647static void WebPPictureResetBufferARGB(WebPPicture* const picture) {48picture->memory_argb_ = NULL;49picture->argb = NULL;50picture->argb_stride = 0;51}5253static void WebPPictureResetBufferYUVA(WebPPicture* const picture) {54picture->memory_ = NULL;55picture->y = picture->u = picture->v = picture->a = NULL;56picture->y_stride = picture->uv_stride = 0;57picture->a_stride = 0;58}5960void WebPPictureResetBuffers(WebPPicture* const picture) {61WebPPictureResetBufferARGB(picture);62WebPPictureResetBufferYUVA(picture);63}6465int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {66void* memory;67const uint64_t argb_size = (uint64_t)width * height;6869assert(picture != NULL);7071WebPSafeFree(picture->memory_argb_);72WebPPictureResetBufferARGB(picture);7374if (width <= 0 || height <= 0) {75return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);76}77// allocate a new buffer.78memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));79if (memory == NULL) {80return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);81}82picture->memory_argb_ = memory;83picture->argb = (uint32_t*)WEBP_ALIGN(memory);84picture->argb_stride = width;85return 1;86}8788int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {89const WebPEncCSP uv_csp =90(WebPEncCSP)((int)picture->colorspace & WEBP_CSP_UV_MASK);91const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;92const int y_stride = width;93const int uv_width = (int)(((int64_t)width + 1) >> 1);94const int uv_height = (int)(((int64_t)height + 1) >> 1);95const int uv_stride = uv_width;96int a_width, a_stride;97uint64_t y_size, uv_size, a_size, total_size;98uint8_t* mem;99100assert(picture != NULL);101102WebPSafeFree(picture->memory_);103WebPPictureResetBufferYUVA(picture);104105if (uv_csp != WEBP_YUV420) {106return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);107}108109// alpha110a_width = has_alpha ? width : 0;111a_stride = a_width;112y_size = (uint64_t)y_stride * height;113uv_size = (uint64_t)uv_stride * uv_height;114a_size = (uint64_t)a_stride * height;115116total_size = y_size + a_size + 2 * uv_size;117118// Security and validation checks119if (width <= 0 || height <= 0 || // luma/alpha param error120uv_width <= 0 || uv_height <= 0) { // u/v param error121return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);122}123// allocate a new buffer.124mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));125if (mem == NULL) {126return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);127}128129// From now on, we're in the clear, we can no longer fail...130picture->memory_ = (void*)mem;131picture->y_stride = y_stride;132picture->uv_stride = uv_stride;133picture->a_stride = a_stride;134135// TODO(skal): we could align the y/u/v planes and adjust stride.136picture->y = mem;137mem += y_size;138139picture->u = mem;140mem += uv_size;141picture->v = mem;142mem += uv_size;143144if (a_size > 0) {145picture->a = mem;146mem += a_size;147}148(void)mem; // makes the static analyzer happy149return 1;150}151152int WebPPictureAlloc(WebPPicture* picture) {153if (picture != NULL) {154const int width = picture->width;155const int height = picture->height;156157WebPPictureFree(picture); // erase previous buffer158159if (!picture->use_argb) {160return WebPPictureAllocYUVA(picture, width, height);161} else {162return WebPPictureAllocARGB(picture, width, height);163}164}165return 1;166}167168void WebPPictureFree(WebPPicture* picture) {169if (picture != NULL) {170WebPSafeFree(picture->memory_);171WebPSafeFree(picture->memory_argb_);172WebPPictureResetBuffers(picture);173}174}175176//------------------------------------------------------------------------------177// WebPMemoryWriter: Write-to-memory178179void WebPMemoryWriterInit(WebPMemoryWriter* writer) {180writer->mem = NULL;181writer->size = 0;182writer->max_size = 0;183}184185int WebPMemoryWrite(const uint8_t* data, size_t data_size,186const WebPPicture* picture) {187WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;188uint64_t next_size;189if (w == NULL) {190return 1;191}192next_size = (uint64_t)w->size + data_size;193if (next_size > w->max_size) {194uint8_t* new_mem;195uint64_t next_max_size = 2ULL * w->max_size;196if (next_max_size < next_size) next_max_size = next_size;197if (next_max_size < 8192ULL) next_max_size = 8192ULL;198new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1);199if (new_mem == NULL) {200return 0;201}202if (w->size > 0) {203memcpy(new_mem, w->mem, w->size);204}205WebPSafeFree(w->mem);206w->mem = new_mem;207// down-cast is ok, thanks to WebPSafeMalloc208w->max_size = (size_t)next_max_size;209}210if (data_size > 0) {211memcpy(w->mem + w->size, data, data_size);212w->size += data_size;213}214return 1;215}216217void WebPMemoryWriterClear(WebPMemoryWriter* writer) {218if (writer != NULL) {219WebPSafeFree(writer->mem);220writer->mem = NULL;221writer->size = 0;222writer->max_size = 0;223}224}225226//------------------------------------------------------------------------------227// Simplest high-level calls:228229typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);230231static size_t Encode(const uint8_t* rgba, int width, int height, int stride,232Importer import, float quality_factor, int lossless,233uint8_t** output) {234WebPPicture pic;235WebPConfig config;236WebPMemoryWriter wrt;237int ok;238239if (output == NULL) return 0;240241if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||242!WebPPictureInit(&pic)) {243return 0; // shouldn't happen, except if system installation is broken244}245246config.lossless = !!lossless;247pic.use_argb = !!lossless;248pic.width = width;249pic.height = height;250pic.writer = WebPMemoryWrite;251pic.custom_ptr = &wrt;252WebPMemoryWriterInit(&wrt);253254ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);255WebPPictureFree(&pic);256if (!ok) {257WebPMemoryWriterClear(&wrt);258*output = NULL;259return 0;260}261*output = wrt.mem;262return wrt.size;263}264265#define ENCODE_FUNC(NAME, IMPORTER) \266size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \267uint8_t** out) { \268return Encode(in, w, h, bps, IMPORTER, q, 0, out); \269}270271ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB)272ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA)273#if !defined(WEBP_REDUCE_CSP)274ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR)275ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA)276#endif // WEBP_REDUCE_CSP277278#undef ENCODE_FUNC279280#define LOSSLESS_DEFAULT_QUALITY 70.281#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \282size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \283return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \284}285286LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB)287LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA)288#if !defined(WEBP_REDUCE_CSP)289LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR)290LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)291#endif // WEBP_REDUCE_CSP292293#undef LOSSLESS_ENCODE_FUNC294295//------------------------------------------------------------------------------296297298