Path: blob/master/thirdparty/libwebp/src/dec/buffer_dec.c
20818 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// Everything about WebPDecBuffer10//11// Author: Skal ([email protected])1213#include <assert.h>14#include <stdlib.h>15#include <string.h>1617#include "src/dec/vp8i_dec.h"18#include "src/dec/webpi_dec.h"19#include "src/utils/rescaler_utils.h"20#include "src/utils/utils.h"21#include "src/webp/decode.h"22#include "src/webp/types.h"2324//------------------------------------------------------------------------------25// WebPDecBuffer2627// Number of bytes per pixel for the different color-spaces.28static const uint8_t kModeBpp[MODE_LAST] = {293, 4, 3, 4, 4, 2, 2,304, 4, 4, 2, // pre-multiplied modes311, 1 };3233// Convert to an integer to handle both the unsigned/signed enum cases34// without the need for casting to remove type limit warnings.35int IsValidColorspace(int webp_csp_mode) {36return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);37}3839// strictly speaking, the very last (or first, if flipped) row40// doesn't require padding.41#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \42((uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH))4344static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {45int ok = 1;46const WEBP_CSP_MODE mode = buffer->colorspace;47const int width = buffer->width;48const int height = buffer->height;49if (!IsValidColorspace(mode)) {50ok = 0;51} else if (!WebPIsRGBMode(mode)) { // YUV checks52const WebPYUVABuffer* const buf = &buffer->u.YUVA;53const int uv_width = (width + 1) / 2;54const int uv_height = (height + 1) / 2;55const int y_stride = abs(buf->y_stride);56const int u_stride = abs(buf->u_stride);57const int v_stride = abs(buf->v_stride);58const int a_stride = abs(buf->a_stride);59const uint64_t y_size = MIN_BUFFER_SIZE(width, height, y_stride);60const uint64_t u_size = MIN_BUFFER_SIZE(uv_width, uv_height, u_stride);61const uint64_t v_size = MIN_BUFFER_SIZE(uv_width, uv_height, v_stride);62const uint64_t a_size = MIN_BUFFER_SIZE(width, height, a_stride);63ok &= (y_size <= buf->y_size);64ok &= (u_size <= buf->u_size);65ok &= (v_size <= buf->v_size);66ok &= (y_stride >= width);67ok &= (u_stride >= uv_width);68ok &= (v_stride >= uv_width);69ok &= (buf->y != NULL);70ok &= (buf->u != NULL);71ok &= (buf->v != NULL);72if (mode == MODE_YUVA) {73ok &= (a_stride >= width);74ok &= (a_size <= buf->a_size);75ok &= (buf->a != NULL);76}77} else { // RGB checks78const WebPRGBABuffer* const buf = &buffer->u.RGBA;79const int stride = abs(buf->stride);80const uint64_t size =81MIN_BUFFER_SIZE((uint64_t)width * kModeBpp[mode], height, stride);82ok &= (size <= buf->size);83ok &= (stride >= width * kModeBpp[mode]);84ok &= (buf->rgba != NULL);85}86return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;87}88#undef MIN_BUFFER_SIZE8990static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {91const int w = buffer->width;92const int h = buffer->height;93const WEBP_CSP_MODE mode = buffer->colorspace;9495if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) {96return VP8_STATUS_INVALID_PARAM;97}9899if (buffer->is_external_memory <= 0 && buffer->private_memory == NULL) {100uint8_t* output;101int uv_stride = 0, a_stride = 0;102uint64_t uv_size = 0, a_size = 0, total_size;103// We need memory and it hasn't been allocated yet.104// => initialize output buffer, now that dimensions are known.105int stride;106uint64_t size;107108if ((uint64_t)w * kModeBpp[mode] >= (1ull << 31)) {109return VP8_STATUS_INVALID_PARAM;110}111stride = w * kModeBpp[mode];112size = (uint64_t)stride * h;113if (!WebPIsRGBMode(mode)) {114uv_stride = (w + 1) / 2;115uv_size = (uint64_t)uv_stride * ((h + 1) / 2);116if (mode == MODE_YUVA) {117a_stride = w;118a_size = (uint64_t)a_stride * h;119}120}121total_size = size + 2 * uv_size + a_size;122123output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));124if (output == NULL) {125return VP8_STATUS_OUT_OF_MEMORY;126}127buffer->private_memory = output;128129if (!WebPIsRGBMode(mode)) { // YUVA initialization130WebPYUVABuffer* const buf = &buffer->u.YUVA;131buf->y = output;132buf->y_stride = stride;133buf->y_size = (size_t)size;134buf->u = output + size;135buf->u_stride = uv_stride;136buf->u_size = (size_t)uv_size;137buf->v = output + size + uv_size;138buf->v_stride = uv_stride;139buf->v_size = (size_t)uv_size;140if (mode == MODE_YUVA) {141buf->a = output + size + 2 * uv_size;142}143buf->a_size = (size_t)a_size;144buf->a_stride = a_stride;145} else { // RGBA initialization146WebPRGBABuffer* const buf = &buffer->u.RGBA;147buf->rgba = output;148buf->stride = stride;149buf->size = (size_t)size;150}151}152return CheckDecBuffer(buffer);153}154155VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {156if (buffer == NULL) {157return VP8_STATUS_INVALID_PARAM;158}159if (WebPIsRGBMode(buffer->colorspace)) {160WebPRGBABuffer* const buf = &buffer->u.RGBA;161buf->rgba += (int64_t)(buffer->height - 1) * buf->stride;162buf->stride = -buf->stride;163} else {164WebPYUVABuffer* const buf = &buffer->u.YUVA;165const int64_t H = buffer->height;166buf->y += (H - 1) * buf->y_stride;167buf->y_stride = -buf->y_stride;168buf->u += ((H - 1) >> 1) * buf->u_stride;169buf->u_stride = -buf->u_stride;170buf->v += ((H - 1) >> 1) * buf->v_stride;171buf->v_stride = -buf->v_stride;172if (buf->a != NULL) {173buf->a += (H - 1) * buf->a_stride;174buf->a_stride = -buf->a_stride;175}176}177return VP8_STATUS_OK;178}179180VP8StatusCode WebPAllocateDecBuffer(int width, int height,181const WebPDecoderOptions* const options,182WebPDecBuffer* const buffer) {183VP8StatusCode status;184if (buffer == NULL || width <= 0 || height <= 0) {185return VP8_STATUS_INVALID_PARAM;186}187if (options != NULL) { // First, apply options if there is any.188if (options->use_cropping) {189const int cw = options->crop_width;190const int ch = options->crop_height;191const int x = options->crop_left & ~1;192const int y = options->crop_top & ~1;193if (!WebPCheckCropDimensions(width, height, x, y, cw, ch)) {194return VP8_STATUS_INVALID_PARAM; // out of frame boundary.195}196width = cw;197height = ch;198}199200if (options->use_scaling) {201#if !defined(WEBP_REDUCE_SIZE)202int scaled_width = options->scaled_width;203int scaled_height = options->scaled_height;204if (!WebPRescalerGetScaledDimensions(205width, height, &scaled_width, &scaled_height)) {206return VP8_STATUS_INVALID_PARAM;207}208width = scaled_width;209height = scaled_height;210#else211return VP8_STATUS_INVALID_PARAM; // rescaling not supported212#endif213}214}215buffer->width = width;216buffer->height = height;217218// Then, allocate buffer for real.219status = AllocateBuffer(buffer);220if (status != VP8_STATUS_OK) return status;221222// Use the stride trick if vertical flip is needed.223if (options != NULL && options->flip) {224status = WebPFlipBuffer(buffer);225}226return status;227}228229//------------------------------------------------------------------------------230// constructors / destructors231232int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {233if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {234return 0; // version mismatch235}236if (buffer == NULL) return 0;237memset(buffer, 0, sizeof(*buffer));238return 1;239}240241void WebPFreeDecBuffer(WebPDecBuffer* buffer) {242if (buffer != NULL) {243if (buffer->is_external_memory <= 0) {244WebPSafeFree(buffer->private_memory);245}246buffer->private_memory = NULL;247}248}249250void WebPCopyDecBuffer(const WebPDecBuffer* const src,251WebPDecBuffer* const dst) {252if (src != NULL && dst != NULL) {253*dst = *src;254if (src->private_memory != NULL) {255dst->is_external_memory = 1; // dst buffer doesn't own the memory.256dst->private_memory = NULL;257}258}259}260261// Copy and transfer ownership from src to dst (beware of parameter order!)262void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {263if (src != NULL && dst != NULL) {264*dst = *src;265if (src->private_memory != NULL) {266src->is_external_memory = 1; // src relinquishes ownership267src->private_memory = NULL;268}269}270}271272VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src_buf,273WebPDecBuffer* const dst_buf) {274assert(src_buf != NULL && dst_buf != NULL);275assert(src_buf->colorspace == dst_buf->colorspace);276277dst_buf->width = src_buf->width;278dst_buf->height = src_buf->height;279if (CheckDecBuffer(dst_buf) != VP8_STATUS_OK) {280return VP8_STATUS_INVALID_PARAM;281}282if (WebPIsRGBMode(src_buf->colorspace)) {283const WebPRGBABuffer* const src = &src_buf->u.RGBA;284const WebPRGBABuffer* const dst = &dst_buf->u.RGBA;285WebPCopyPlane(src->rgba, src->stride, dst->rgba, dst->stride,286src_buf->width * kModeBpp[src_buf->colorspace],287src_buf->height);288} else {289const WebPYUVABuffer* const src = &src_buf->u.YUVA;290const WebPYUVABuffer* const dst = &dst_buf->u.YUVA;291WebPCopyPlane(src->y, src->y_stride, dst->y, dst->y_stride,292src_buf->width, src_buf->height);293WebPCopyPlane(src->u, src->u_stride, dst->u, dst->u_stride,294(src_buf->width + 1) / 2, (src_buf->height + 1) / 2);295WebPCopyPlane(src->v, src->v_stride, dst->v, dst->v_stride,296(src_buf->width + 1) / 2, (src_buf->height + 1) / 2);297if (WebPIsAlphaMode(src_buf->colorspace)) {298WebPCopyPlane(src->a, src->a_stride, dst->a, dst->a_stride,299src_buf->width, src_buf->height);300}301}302return VP8_STATUS_OK;303}304305int WebPAvoidSlowMemory(const WebPDecBuffer* const output,306const WebPBitstreamFeatures* const features) {307assert(output != NULL);308return (output->is_external_memory >= 2) &&309WebPIsPremultipliedMode(output->colorspace) &&310(features != NULL && features->has_alpha);311}312313//------------------------------------------------------------------------------314315316