Path: blob/master/thirdparty/libwebp/src/enc/picture_enc.c
9913 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 <limits.h>15#include <stdlib.h>1617#include "src/enc/vp8i_enc.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//------------------------------------------------------------------------------4647int WebPValidatePicture(const WebPPicture* const picture) {48if (picture == NULL) return 0;49if (picture->width <= 0 || picture->height <= 0) {50return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);51}52if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 ||53picture->height <= 0 || picture->height / 4 > INT_MAX / 4) {54return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);55}56if (picture->colorspace != WEBP_YUV420 &&57picture->colorspace != WEBP_YUV420A) {58return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);59}60return 1;61}6263static void WebPPictureResetBufferARGB(WebPPicture* const picture) {64picture->memory_argb_ = NULL;65picture->argb = NULL;66picture->argb_stride = 0;67}6869static void WebPPictureResetBufferYUVA(WebPPicture* const picture) {70picture->memory_ = NULL;71picture->y = picture->u = picture->v = picture->a = NULL;72picture->y_stride = picture->uv_stride = 0;73picture->a_stride = 0;74}7576void WebPPictureResetBuffers(WebPPicture* const picture) {77WebPPictureResetBufferARGB(picture);78WebPPictureResetBufferYUVA(picture);79}8081int WebPPictureAllocARGB(WebPPicture* const picture) {82void* memory;83const int width = picture->width;84const int height = picture->height;85const uint64_t argb_size = (uint64_t)width * height;8687if (!WebPValidatePicture(picture)) return 0;8889WebPSafeFree(picture->memory_argb_);90WebPPictureResetBufferARGB(picture);9192// allocate a new buffer.93memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));94if (memory == NULL) {95return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);96}97picture->memory_argb_ = memory;98picture->argb = (uint32_t*)WEBP_ALIGN(memory);99picture->argb_stride = width;100return 1;101}102103int WebPPictureAllocYUVA(WebPPicture* const picture) {104const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;105const int width = picture->width;106const int height = picture->height;107const int y_stride = width;108const int uv_width = (int)(((int64_t)width + 1) >> 1);109const int uv_height = (int)(((int64_t)height + 1) >> 1);110const int uv_stride = uv_width;111int a_width, a_stride;112uint64_t y_size, uv_size, a_size, total_size;113uint8_t* mem;114115if (!WebPValidatePicture(picture)) return 0;116117WebPSafeFree(picture->memory_);118WebPPictureResetBufferYUVA(picture);119120// alpha121a_width = has_alpha ? width : 0;122a_stride = a_width;123y_size = (uint64_t)y_stride * height;124uv_size = (uint64_t)uv_stride * uv_height;125a_size = (uint64_t)a_stride * height;126127total_size = y_size + a_size + 2 * uv_size;128129// Security and validation checks130if (width <= 0 || height <= 0 || // luma/alpha param error131uv_width <= 0 || uv_height <= 0) { // u/v param error132return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);133}134// allocate a new buffer.135mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));136if (mem == NULL) {137return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);138}139140// From now on, we're in the clear, we can no longer fail...141picture->memory_ = (void*)mem;142picture->y_stride = y_stride;143picture->uv_stride = uv_stride;144picture->a_stride = a_stride;145146// TODO(skal): we could align the y/u/v planes and adjust stride.147picture->y = mem;148mem += y_size;149150picture->u = mem;151mem += uv_size;152picture->v = mem;153mem += uv_size;154155if (a_size > 0) {156picture->a = mem;157mem += a_size;158}159(void)mem; // makes the static analyzer happy160return 1;161}162163int WebPPictureAlloc(WebPPicture* picture) {164if (picture != NULL) {165WebPPictureFree(picture); // erase previous buffer166167if (!picture->use_argb) {168return WebPPictureAllocYUVA(picture);169} else {170return WebPPictureAllocARGB(picture);171}172}173return 1;174}175176void WebPPictureFree(WebPPicture* picture) {177if (picture != NULL) {178WebPSafeFree(picture->memory_);179WebPSafeFree(picture->memory_argb_);180WebPPictureResetBuffers(picture);181}182}183184//------------------------------------------------------------------------------185// WebPMemoryWriter: Write-to-memory186187void WebPMemoryWriterInit(WebPMemoryWriter* writer) {188writer->mem = NULL;189writer->size = 0;190writer->max_size = 0;191}192193int WebPMemoryWrite(const uint8_t* data, size_t data_size,194const WebPPicture* picture) {195WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;196uint64_t next_size;197if (w == NULL) {198return 1;199}200next_size = (uint64_t)w->size + data_size;201if (next_size > w->max_size) {202uint8_t* new_mem;203uint64_t next_max_size = 2ULL * w->max_size;204if (next_max_size < next_size) next_max_size = next_size;205if (next_max_size < 8192ULL) next_max_size = 8192ULL;206new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1);207if (new_mem == NULL) {208return 0;209}210if (w->size > 0) {211memcpy(new_mem, w->mem, w->size);212}213WebPSafeFree(w->mem);214w->mem = new_mem;215// down-cast is ok, thanks to WebPSafeMalloc216w->max_size = (size_t)next_max_size;217}218if (data_size > 0) {219memcpy(w->mem + w->size, data, data_size);220w->size += data_size;221}222return 1;223}224225void WebPMemoryWriterClear(WebPMemoryWriter* writer) {226if (writer != NULL) {227WebPSafeFree(writer->mem);228writer->mem = NULL;229writer->size = 0;230writer->max_size = 0;231}232}233234//------------------------------------------------------------------------------235// Simplest high-level calls:236237typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);238239static size_t Encode(const uint8_t* rgba, int width, int height, int stride,240Importer import, float quality_factor, int lossless,241uint8_t** output) {242WebPPicture pic;243WebPConfig config;244WebPMemoryWriter wrt;245int ok;246247if (output == NULL) return 0;248249if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||250!WebPPictureInit(&pic)) {251return 0; // shouldn't happen, except if system installation is broken252}253254config.lossless = !!lossless;255pic.use_argb = !!lossless;256pic.width = width;257pic.height = height;258pic.writer = WebPMemoryWrite;259pic.custom_ptr = &wrt;260WebPMemoryWriterInit(&wrt);261262ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);263WebPPictureFree(&pic);264if (!ok) {265WebPMemoryWriterClear(&wrt);266*output = NULL;267return 0;268}269*output = wrt.mem;270return wrt.size;271}272273#define ENCODE_FUNC(NAME, IMPORTER) \274size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \275uint8_t** out) { \276return Encode(in, w, h, bps, IMPORTER, q, 0, out); \277}278279ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB)280ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA)281#if !defined(WEBP_REDUCE_CSP)282ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR)283ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA)284#endif // WEBP_REDUCE_CSP285286#undef ENCODE_FUNC287288#define LOSSLESS_DEFAULT_QUALITY 70.289#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \290size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \291return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \292}293294LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB)295LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA)296#if !defined(WEBP_REDUCE_CSP)297LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR)298LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)299#endif // WEBP_REDUCE_CSP300301#undef LOSSLESS_ENCODE_FUNC302303//------------------------------------------------------------------------------304305306