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