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