github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/webp/libwebp/src/dec/buffer.c (about)

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