Home | History | Annotate | Download | only in dec
      1 // Copyright 2011 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Everything about WebPDecBuffer
     11 //
     12 // Author: Skal (pascal.massimino (at) gmail.com)
     13 
     14 #include <stdlib.h>
     15 
     16 #include "./vp8i.h"
     17 #include "./webpi.h"
     18 #include "../utils/utils.h"
     19 
     20 #if defined(__cplusplus) || defined(c_plusplus)
     21 extern "C" {
     22 #endif
     23 
     24 //------------------------------------------------------------------------------
     25 // WebPDecBuffer
     26 
     27 // Number of bytes per pixel for the different color-spaces.
     28 static const int kModeBpp[MODE_LAST] = {
     29   3, 4, 3, 4, 4, 2, 2,
     30   4, 4, 4, 2,    // pre-multiplied modes
     31   1, 1 };
     32 
     33 // Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
     34 // Convert to an integer to handle both the unsigned/signed enum cases
     35 // without the need for casting to remove type limit warnings.
     36 static int IsValidColorspace(int webp_csp_mode) {
     37   return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
     38 }
     39 
     40 static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
     41   int ok = 1;
     42   const WEBP_CSP_MODE mode = buffer->colorspace;
     43   const int width = buffer->width;
     44   const int height = buffer->height;
     45   if (!IsValidColorspace(mode)) {
     46     ok = 0;
     47   } else if (!WebPIsRGBMode(mode)) {   // YUV checks
     48     const WebPYUVABuffer* const buf = &buffer->u.YUVA;
     49     const uint64_t y_size = (uint64_t)buf->y_stride * height;
     50     const uint64_t u_size = (uint64_t)buf->u_stride * ((height + 1) / 2);
     51     const uint64_t v_size = (uint64_t)buf->v_stride * ((height + 1) / 2);
     52     const uint64_t a_size = (uint64_t)buf->a_stride * height;
     53     ok &= (y_size <= buf->y_size);
     54     ok &= (u_size <= buf->u_size);
     55     ok &= (v_size <= buf->v_size);
     56     ok &= (buf->y_stride >= width);
     57     ok &= (buf->u_stride >= (width + 1) / 2);
     58     ok &= (buf->v_stride >= (width + 1) / 2);
     59     ok &= (buf->y != NULL);
     60     ok &= (buf->u != NULL);
     61     ok &= (buf->v != NULL);
     62     if (mode == MODE_YUVA) {
     63       ok &= (buf->a_stride >= width);
     64       ok &= (a_size <= buf->a_size);
     65       ok &= (buf->a != NULL);
     66     }
     67   } else {    // RGB checks
     68     const WebPRGBABuffer* const buf = &buffer->u.RGBA;
     69     const uint64_t size = (uint64_t)buf->stride * height;
     70     ok &= (size <= buf->size);
     71     ok &= (buf->stride >= width * kModeBpp[mode]);
     72     ok &= (buf->rgba != NULL);
     73   }
     74   return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
     75 }
     76 
     77 static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
     78   const int w = buffer->width;
     79   const int h = buffer->height;
     80   const WEBP_CSP_MODE mode = buffer->colorspace;
     81 
     82   if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) {
     83     return VP8_STATUS_INVALID_PARAM;
     84   }
     85 
     86   if (!buffer->is_external_memory && buffer->private_memory == NULL) {
     87     uint8_t* output;
     88     int uv_stride = 0, a_stride = 0;
     89     uint64_t uv_size = 0, a_size = 0, total_size;
     90     // We need memory and it hasn't been allocated yet.
     91     // => initialize output buffer, now that dimensions are known.
     92     const int stride = w * kModeBpp[mode];
     93     const uint64_t size = (uint64_t)stride * h;
     94 
     95     if (!WebPIsRGBMode(mode)) {
     96       uv_stride = (w + 1) / 2;
     97       uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
     98       if (mode == MODE_YUVA) {
     99         a_stride = w;
    100         a_size = (uint64_t)a_stride * h;
    101       }
    102     }
    103     total_size = size + 2 * uv_size + a_size;
    104 
    105     // Security/sanity checks
    106     output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
    107     if (output == NULL) {
    108       return VP8_STATUS_OUT_OF_MEMORY;
    109     }
    110     buffer->private_memory = output;
    111 
    112     if (!WebPIsRGBMode(mode)) {   // YUVA initialization
    113       WebPYUVABuffer* const buf = &buffer->u.YUVA;
    114       buf->y = output;
    115       buf->y_stride = stride;
    116       buf->y_size = (size_t)size;
    117       buf->u = output + size;
    118       buf->u_stride = uv_stride;
    119       buf->u_size = (size_t)uv_size;
    120       buf->v = output + size + uv_size;
    121       buf->v_stride = uv_stride;
    122       buf->v_size = (size_t)uv_size;
    123       if (mode == MODE_YUVA) {
    124         buf->a = output + size + 2 * uv_size;
    125       }
    126       buf->a_size = (size_t)a_size;
    127       buf->a_stride = a_stride;
    128     } else {  // RGBA initialization
    129       WebPRGBABuffer* const buf = &buffer->u.RGBA;
    130       buf->rgba = output;
    131       buf->stride = stride;
    132       buf->size = (size_t)size;
    133     }
    134   }
    135   return CheckDecBuffer(buffer);
    136 }
    137 
    138 VP8StatusCode WebPAllocateDecBuffer(int w, int h,
    139                                     const WebPDecoderOptions* const options,
    140                                     WebPDecBuffer* const out) {
    141   if (out == NULL || w <= 0 || h <= 0) {
    142     return VP8_STATUS_INVALID_PARAM;
    143   }
    144   if (options != NULL) {    // First, apply options if there is any.
    145     if (options->use_cropping) {
    146       const int cw = options->crop_width;
    147       const int ch = options->crop_height;
    148       const int x = options->crop_left & ~1;
    149       const int y = options->crop_top & ~1;
    150       if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) {
    151         return VP8_STATUS_INVALID_PARAM;   // out of frame boundary.
    152       }
    153       w = cw;
    154       h = ch;
    155     }
    156     if (options->use_scaling) {
    157       if (options->scaled_width <= 0 || options->scaled_height <= 0) {
    158         return VP8_STATUS_INVALID_PARAM;
    159       }
    160       w = options->scaled_width;
    161       h = options->scaled_height;
    162     }
    163   }
    164   out->width = w;
    165   out->height = h;
    166 
    167   // Then, allocate buffer for real
    168   return AllocateBuffer(out);
    169 }
    170 
    171 //------------------------------------------------------------------------------
    172 // constructors / destructors
    173 
    174 int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
    175   if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
    176     return 0;  // version mismatch
    177   }
    178   if (buffer == NULL) return 0;
    179   memset(buffer, 0, sizeof(*buffer));
    180   return 1;
    181 }
    182 
    183 void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
    184   if (buffer != NULL) {
    185     if (!buffer->is_external_memory)
    186       free(buffer->private_memory);
    187     buffer->private_memory = NULL;
    188   }
    189 }
    190 
    191 void WebPCopyDecBuffer(const WebPDecBuffer* const src,
    192                        WebPDecBuffer* const dst) {
    193   if (src != NULL && dst != NULL) {
    194     *dst = *src;
    195     if (src->private_memory != NULL) {
    196       dst->is_external_memory = 1;   // dst buffer doesn't own the memory.
    197       dst->private_memory = NULL;
    198     }
    199   }
    200 }
    201 
    202 // Copy and transfer ownership from src to dst (beware of parameter order!)
    203 void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
    204   if (src != NULL && dst != NULL) {
    205     *dst = *src;
    206     if (src->private_memory != NULL) {
    207       src->is_external_memory = 1;   // src relinquishes ownership
    208       src->private_memory = NULL;
    209     }
    210   }
    211 }
    212 
    213 //------------------------------------------------------------------------------
    214 
    215 #if defined(__cplusplus) || defined(c_plusplus)
    216 }    // extern "C"
    217 #endif
    218