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 //------------------------------------------------------------------------------ 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 int y_stride = abs(buf->y_stride); 46 const int u_stride = abs(buf->u_stride); 47 const int v_stride = abs(buf->v_stride); 48 const int a_stride = abs(buf->a_stride); 49 const uint64_t y_size = (uint64_t)y_stride * height; 50 const uint64_t u_size = (uint64_t)u_stride * ((height + 1) / 2); 51 const uint64_t v_size = (uint64_t)v_stride * ((height + 1) / 2); 52 const uint64_t a_size = (uint64_t)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 &= (y_stride >= width); 57 ok &= (u_stride >= (width + 1) / 2); 58 ok &= (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 &= (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 int stride = abs(buf->stride); 70 const uint64_t size = (uint64_t)stride * height; 71 ok &= (size <= buf->size); 72 ok &= (stride >= width * kModeBpp[mode]); 73 ok &= (buf->rgba != NULL); 74 } 75 return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM; 76 } 77 78 static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) { 79 const int w = buffer->width; 80 const int h = buffer->height; 81 const WEBP_CSP_MODE mode = buffer->colorspace; 82 83 if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) { 84 return VP8_STATUS_INVALID_PARAM; 85 } 86 87 if (!buffer->is_external_memory && buffer->private_memory == NULL) { 88 uint8_t* output; 89 int uv_stride = 0, a_stride = 0; 90 uint64_t uv_size = 0, a_size = 0, total_size; 91 // We need memory and it hasn't been allocated yet. 92 // => initialize output buffer, now that dimensions are known. 93 const int stride = w * kModeBpp[mode]; 94 const uint64_t size = (uint64_t)stride * h; 95 96 if (!WebPIsRGBMode(mode)) { 97 uv_stride = (w + 1) / 2; 98 uv_size = (uint64_t)uv_stride * ((h + 1) / 2); 99 if (mode == MODE_YUVA) { 100 a_stride = w; 101 a_size = (uint64_t)a_stride * h; 102 } 103 } 104 total_size = size + 2 * uv_size + a_size; 105 106 // Security/sanity checks 107 output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output)); 108 if (output == NULL) { 109 return VP8_STATUS_OUT_OF_MEMORY; 110 } 111 buffer->private_memory = output; 112 113 if (!WebPIsRGBMode(mode)) { // YUVA initialization 114 WebPYUVABuffer* const buf = &buffer->u.YUVA; 115 buf->y = output; 116 buf->y_stride = stride; 117 buf->y_size = (size_t)size; 118 buf->u = output + size; 119 buf->u_stride = uv_stride; 120 buf->u_size = (size_t)uv_size; 121 buf->v = output + size + uv_size; 122 buf->v_stride = uv_stride; 123 buf->v_size = (size_t)uv_size; 124 if (mode == MODE_YUVA) { 125 buf->a = output + size + 2 * uv_size; 126 } 127 buf->a_size = (size_t)a_size; 128 buf->a_stride = a_stride; 129 } else { // RGBA initialization 130 WebPRGBABuffer* const buf = &buffer->u.RGBA; 131 buf->rgba = output; 132 buf->stride = stride; 133 buf->size = (size_t)size; 134 } 135 } 136 return CheckDecBuffer(buffer); 137 } 138 139 VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) { 140 if (buffer == NULL) { 141 return VP8_STATUS_INVALID_PARAM; 142 } 143 if (WebPIsRGBMode(buffer->colorspace)) { 144 WebPRGBABuffer* const buf = &buffer->u.RGBA; 145 buf->rgba += (buffer->height - 1) * buf->stride; 146 buf->stride = -buf->stride; 147 } else { 148 WebPYUVABuffer* const buf = &buffer->u.YUVA; 149 const int H = buffer->height; 150 buf->y += (H - 1) * buf->y_stride; 151 buf->y_stride = -buf->y_stride; 152 buf->u += ((H - 1) >> 1) * buf->u_stride; 153 buf->u_stride = -buf->u_stride; 154 buf->v += ((H - 1) >> 1) * buf->v_stride; 155 buf->v_stride = -buf->v_stride; 156 if (buf->a != NULL) { 157 buf->a += (H - 1) * buf->a_stride; 158 buf->a_stride = -buf->a_stride; 159 } 160 } 161 return VP8_STATUS_OK; 162 } 163 164 VP8StatusCode WebPAllocateDecBuffer(int w, int h, 165 const WebPDecoderOptions* const options, 166 WebPDecBuffer* const out) { 167 VP8StatusCode status; 168 if (out == NULL || w <= 0 || h <= 0) { 169 return VP8_STATUS_INVALID_PARAM; 170 } 171 if (options != NULL) { // First, apply options if there is any. 172 if (options->use_cropping) { 173 const int cw = options->crop_width; 174 const int ch = options->crop_height; 175 const int x = options->crop_left & ~1; 176 const int y = options->crop_top & ~1; 177 if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) { 178 return VP8_STATUS_INVALID_PARAM; // out of frame boundary. 179 } 180 w = cw; 181 h = ch; 182 } 183 if (options->use_scaling) { 184 if (options->scaled_width <= 0 || options->scaled_height <= 0) { 185 return VP8_STATUS_INVALID_PARAM; 186 } 187 w = options->scaled_width; 188 h = options->scaled_height; 189 } 190 } 191 out->width = w; 192 out->height = h; 193 194 // Then, allocate buffer for real. 195 status = AllocateBuffer(out); 196 if (status != VP8_STATUS_OK) return status; 197 198 #if WEBP_DECODER_ABI_VERSION > 0x0203 199 // Use the stride trick if vertical flip is needed. 200 if (options != NULL && options->flip) { 201 status = WebPFlipBuffer(out); 202 } 203 #endif 204 return status; 205 } 206 207 //------------------------------------------------------------------------------ 208 // constructors / destructors 209 210 int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) { 211 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { 212 return 0; // version mismatch 213 } 214 if (buffer == NULL) return 0; 215 memset(buffer, 0, sizeof(*buffer)); 216 return 1; 217 } 218 219 void WebPFreeDecBuffer(WebPDecBuffer* buffer) { 220 if (buffer != NULL) { 221 if (!buffer->is_external_memory) { 222 WebPSafeFree(buffer->private_memory); 223 } 224 buffer->private_memory = NULL; 225 } 226 } 227 228 void WebPCopyDecBuffer(const WebPDecBuffer* const src, 229 WebPDecBuffer* const dst) { 230 if (src != NULL && dst != NULL) { 231 *dst = *src; 232 if (src->private_memory != NULL) { 233 dst->is_external_memory = 1; // dst buffer doesn't own the memory. 234 dst->private_memory = NULL; 235 } 236 } 237 } 238 239 // Copy and transfer ownership from src to dst (beware of parameter order!) 240 void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) { 241 if (src != NULL && dst != NULL) { 242 *dst = *src; 243 if (src->private_memory != NULL) { 244 src->is_external_memory = 1; // src relinquishes ownership 245 src->private_memory = NULL; 246 } 247 } 248 } 249 250 //------------------------------------------------------------------------------ 251 252