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