Path: blob/master/thirdparty/libwebp/src/enc/picture_enc.c
21738 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>16#include <string.h>1718#include "src/enc/vp8i_enc.h"19#include "src/utils/utils.h"20#include "src/webp/encode.h"21#include "src/webp/types.h"2223//------------------------------------------------------------------------------24// WebPPicture25//------------------------------------------------------------------------------2627static int DummyWriter(const uint8_t* data, size_t data_size,28const WebPPicture* const picture) {29// The following are to prevent 'unused variable' error message.30(void)data;31(void)data_size;32(void)picture;33return 1;34}3536int WebPPictureInitInternal(WebPPicture* picture, int version) {37if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {38return 0; // caller/system version mismatch!39}40if (picture != NULL) {41memset(picture, 0, sizeof(*picture));42picture->writer = DummyWriter;43WebPEncodingSetError(picture, VP8_ENC_OK);44}45return 1;46}4748//------------------------------------------------------------------------------4950int WebPValidatePicture(const WebPPicture* const picture) {51if (picture == NULL) return 0;52if (picture->width <= 0 || picture->height <= 0) {53return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);54}55if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 ||56picture->height <= 0 || picture->height / 4 > INT_MAX / 4) {57return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);58}59if (picture->colorspace != WEBP_YUV420 &&60picture->colorspace != WEBP_YUV420A) {61return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);62}63return 1;64}6566static void WebPPictureResetBufferARGB(WebPPicture* const picture) {67picture->memory_argb_ = NULL;68picture->argb = NULL;69picture->argb_stride = 0;70}7172static void WebPPictureResetBufferYUVA(WebPPicture* const picture) {73picture->memory_ = NULL;74picture->y = picture->u = picture->v = picture->a = NULL;75picture->y_stride = picture->uv_stride = 0;76picture->a_stride = 0;77}7879void WebPPictureResetBuffers(WebPPicture* const picture) {80WebPPictureResetBufferARGB(picture);81WebPPictureResetBufferYUVA(picture);82}8384int WebPPictureAllocARGB(WebPPicture* const picture) {85void* memory;86const int width = picture->width;87const int height = picture->height;88const uint64_t argb_size = (uint64_t)width * height;8990if (!WebPValidatePicture(picture)) return 0;9192WebPSafeFree(picture->memory_argb_);93WebPPictureResetBufferARGB(picture);9495// allocate a new buffer.96memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));97if (memory == NULL) {98return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);99}100picture->memory_argb_ = memory;101picture->argb = (uint32_t*)WEBP_ALIGN(memory);102picture->argb_stride = width;103return 1;104}105106int WebPPictureAllocYUVA(WebPPicture* const picture) {107const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;108const int width = picture->width;109const int height = picture->height;110const int y_stride = width;111const int uv_width = (int)(((int64_t)width + 1) >> 1);112const int uv_height = (int)(((int64_t)height + 1) >> 1);113const int uv_stride = uv_width;114int a_width, a_stride;115uint64_t y_size, uv_size, a_size, total_size;116uint8_t* mem;117118if (!WebPValidatePicture(picture)) return 0;119120WebPSafeFree(picture->memory_);121WebPPictureResetBufferYUVA(picture);122123// alpha124a_width = has_alpha ? width : 0;125a_stride = a_width;126y_size = (uint64_t)y_stride * height;127uv_size = (uint64_t)uv_stride * uv_height;128a_size = (uint64_t)a_stride * height;129130total_size = y_size + a_size + 2 * uv_size;131132// Security and validation checks133if (width <= 0 || height <= 0 || // luma/alpha param error134uv_width <= 0 || uv_height <= 0) { // u/v param error135return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);136}137// allocate a new buffer.138mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));139if (mem == NULL) {140return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);141}142143// From now on, we're in the clear, we can no longer fail...144picture->memory_ = (void*)mem;145picture->y_stride = y_stride;146picture->uv_stride = uv_stride;147picture->a_stride = a_stride;148149// TODO(skal): we could align the y/u/v planes and adjust stride.150picture->y = mem;151mem += y_size;152153picture->u = mem;154mem += uv_size;155picture->v = mem;156mem += uv_size;157158if (a_size > 0) {159picture->a = mem;160mem += a_size;161}162(void)mem; // makes the static analyzer happy163return 1;164}165166int WebPPictureAlloc(WebPPicture* picture) {167if (picture != NULL) {168WebPPictureFree(picture); // erase previous buffer169170if (!picture->use_argb) {171return WebPPictureAllocYUVA(picture);172} else {173return WebPPictureAllocARGB(picture);174}175}176return 1;177}178179void WebPPictureFree(WebPPicture* picture) {180if (picture != NULL) {181WebPSafeFree(picture->memory_);182WebPSafeFree(picture->memory_argb_);183WebPPictureResetBuffers(picture);184}185}186187//------------------------------------------------------------------------------188// WebPMemoryWriter: Write-to-memory189190void WebPMemoryWriterInit(WebPMemoryWriter* writer) {191writer->mem = NULL;192writer->size = 0;193writer->max_size = 0;194}195196int WebPMemoryWrite(const uint8_t* data, size_t data_size,197const WebPPicture* picture) {198WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;199uint64_t next_size;200if (w == NULL) {201return 1;202}203next_size = (uint64_t)w->size + data_size;204if (next_size > w->max_size) {205uint8_t* new_mem;206uint64_t next_max_size = 2ULL * w->max_size;207if (next_max_size < next_size) next_max_size = next_size;208if (next_max_size < 8192ULL) next_max_size = 8192ULL;209new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1);210if (new_mem == NULL) {211return 0;212}213if (w->size > 0) {214memcpy(new_mem, w->mem, w->size);215}216WebPSafeFree(w->mem);217w->mem = new_mem;218// down-cast is ok, thanks to WebPSafeMalloc219w->max_size = (size_t)next_max_size;220}221if (data_size > 0) {222memcpy(w->mem + w->size, data, data_size);223w->size += data_size;224}225return 1;226}227228void WebPMemoryWriterClear(WebPMemoryWriter* writer) {229if (writer != NULL) {230WebPSafeFree(writer->mem);231WebPMemoryWriterInit(writer);232}233}234235//------------------------------------------------------------------------------236// Simplest high-level calls:237238typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);239240static size_t Encode(const uint8_t* rgba, int width, int height, int stride,241Importer import, float quality_factor, int lossless,242uint8_t** output) {243WebPPicture pic;244WebPConfig config;245WebPMemoryWriter wrt;246int ok;247248if (output == NULL) return 0;249250if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||251!WebPPictureInit(&pic)) {252return 0; // shouldn't happen, except if system installation is broken253}254255config.lossless = !!lossless;256pic.use_argb = !!lossless;257pic.width = width;258pic.height = height;259pic.writer = WebPMemoryWrite;260pic.custom_ptr = &wrt;261WebPMemoryWriterInit(&wrt);262263ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);264WebPPictureFree(&pic);265if (!ok) {266WebPMemoryWriterClear(&wrt);267*output = NULL;268return 0;269}270*output = wrt.mem;271return wrt.size;272}273274#define ENCODE_FUNC(NAME, IMPORTER) \275size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \276uint8_t** out) { \277return Encode(in, w, h, bps, IMPORTER, q, 0, out); \278}279280ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB)281ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA)282#if !defined(WEBP_REDUCE_CSP)283ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR)284ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA)285#endif // WEBP_REDUCE_CSP286287#undef ENCODE_FUNC288289#define LOSSLESS_DEFAULT_QUALITY 70.290#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \291size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \292return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \293}294295LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB)296LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA)297#if !defined(WEBP_REDUCE_CSP)298LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR)299LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)300#endif // WEBP_REDUCE_CSP301302#undef LOSSLESS_ENCODE_FUNC303304//------------------------------------------------------------------------------305306307