1 /* 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 12 #include <stdlib.h> 13 #include <string.h> 14 #include "vpx/vpx_image.h" 15 16 static vpx_image_t *img_alloc_helper(vpx_image_t *img, 17 vpx_img_fmt_t fmt, 18 unsigned int d_w, 19 unsigned int d_h, 20 unsigned int stride_align, 21 unsigned char *img_data) 22 { 23 24 unsigned int h, w, s, xcs, ycs, bps; 25 int align; 26 27 /* Treat align==0 like align==1 */ 28 if (!stride_align) 29 stride_align = 1; 30 31 /* Validate alignment (must be power of 2) */ 32 if (stride_align & (stride_align - 1)) 33 goto fail; 34 35 /* Get sample size for this format */ 36 switch (fmt) 37 { 38 case VPX_IMG_FMT_RGB32: 39 case VPX_IMG_FMT_RGB32_LE: 40 case VPX_IMG_FMT_ARGB: 41 case VPX_IMG_FMT_ARGB_LE: 42 bps = 32; 43 break; 44 case VPX_IMG_FMT_RGB24: 45 case VPX_IMG_FMT_BGR24: 46 bps = 24; 47 break; 48 case VPX_IMG_FMT_RGB565: 49 case VPX_IMG_FMT_RGB565_LE: 50 case VPX_IMG_FMT_RGB555: 51 case VPX_IMG_FMT_RGB555_LE: 52 case VPX_IMG_FMT_UYVY: 53 case VPX_IMG_FMT_YUY2: 54 case VPX_IMG_FMT_YVYU: 55 bps = 16; 56 break; 57 case VPX_IMG_FMT_I420: 58 case VPX_IMG_FMT_YV12: 59 case VPX_IMG_FMT_VPXI420: 60 case VPX_IMG_FMT_VPXYV12: 61 bps = 12; 62 break; 63 default: 64 bps = 16; 65 break; 66 } 67 68 /* Get chroma shift values for this format */ 69 switch (fmt) 70 { 71 case VPX_IMG_FMT_I420: 72 case VPX_IMG_FMT_YV12: 73 case VPX_IMG_FMT_VPXI420: 74 case VPX_IMG_FMT_VPXYV12: 75 xcs = 1; 76 break; 77 default: 78 xcs = 0; 79 break; 80 } 81 82 switch (fmt) 83 { 84 case VPX_IMG_FMT_I420: 85 case VPX_IMG_FMT_YV12: 86 case VPX_IMG_FMT_VPXI420: 87 case VPX_IMG_FMT_VPXYV12: 88 ycs = 1; 89 break; 90 default: 91 ycs = 0; 92 break; 93 } 94 95 /* Calculate storage sizes given the chroma subsampling */ 96 align = (1 << xcs) - 1; 97 w = (d_w + align) & ~align; 98 align = (1 << ycs) - 1; 99 h = (d_h + align) & ~align; 100 s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8; 101 s = (s + stride_align - 1) & ~(stride_align - 1); 102 103 /* Allocate the new image */ 104 if (!img) 105 { 106 img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t)); 107 108 if (!img) 109 goto fail; 110 111 img->self_allocd = 1; 112 } 113 else 114 { 115 memset(img, 0, sizeof(vpx_image_t)); 116 } 117 118 img->img_data = img_data; 119 120 if (!img_data) 121 { 122 img->img_data = malloc((fmt & VPX_IMG_FMT_PLANAR) ? h * w * bps / 8 : h * s); 123 img->img_data_owner = 1; 124 } 125 126 if (!img->img_data) 127 goto fail; 128 129 img->fmt = fmt; 130 img->w = w; 131 img->h = h; 132 img->x_chroma_shift = xcs; 133 img->y_chroma_shift = ycs; 134 img->bps = bps; 135 136 /* Calculate strides */ 137 img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = s; 138 img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = s >> xcs; 139 140 /* Default viewport to entire image */ 141 if (!vpx_img_set_rect(img, 0, 0, d_w, d_h)) 142 return img; 143 144 fail: 145 vpx_img_free(img); 146 return NULL; 147 } 148 149 vpx_image_t *vpx_img_alloc(vpx_image_t *img, 150 vpx_img_fmt_t fmt, 151 unsigned int d_w, 152 unsigned int d_h, 153 unsigned int stride_align) 154 { 155 return img_alloc_helper(img, fmt, d_w, d_h, stride_align, NULL); 156 } 157 158 vpx_image_t *vpx_img_wrap(vpx_image_t *img, 159 vpx_img_fmt_t fmt, 160 unsigned int d_w, 161 unsigned int d_h, 162 unsigned int stride_align, 163 unsigned char *img_data) 164 { 165 return img_alloc_helper(img, fmt, d_w, d_h, stride_align, img_data); 166 } 167 168 int vpx_img_set_rect(vpx_image_t *img, 169 unsigned int x, 170 unsigned int y, 171 unsigned int w, 172 unsigned int h) 173 { 174 unsigned char *data; 175 176 if (x + w <= img->w && y + h <= img->h) 177 { 178 img->d_w = w; 179 img->d_h = h; 180 181 /* Calculate plane pointers */ 182 if (!(img->fmt & VPX_IMG_FMT_PLANAR)) 183 { 184 img->planes[VPX_PLANE_PACKED] = 185 img->img_data + x * img->bps / 8 + y * img->stride[VPX_PLANE_PACKED]; 186 } 187 else 188 { 189 data = img->img_data; 190 191 if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) 192 { 193 img->planes[VPX_PLANE_ALPHA] = 194 data + x + y * img->stride[VPX_PLANE_ALPHA]; 195 data += img->h * img->stride[VPX_PLANE_ALPHA]; 196 } 197 198 img->planes[VPX_PLANE_Y] = data + x + y * img->stride[VPX_PLANE_Y]; 199 data += img->h * img->stride[VPX_PLANE_Y]; 200 201 if (!(img->fmt & VPX_IMG_FMT_UV_FLIP)) 202 { 203 img->planes[VPX_PLANE_U] = data 204 + (x >> img->x_chroma_shift) 205 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U]; 206 data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U]; 207 img->planes[VPX_PLANE_V] = data 208 + (x >> img->x_chroma_shift) 209 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V]; 210 } 211 else 212 { 213 img->planes[VPX_PLANE_V] = data 214 + (x >> img->x_chroma_shift) 215 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V]; 216 data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V]; 217 img->planes[VPX_PLANE_U] = data 218 + (x >> img->x_chroma_shift) 219 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U]; 220 } 221 } 222 223 return 0; 224 } 225 226 return -1; 227 } 228 229 void vpx_img_flip(vpx_image_t *img) 230 { 231 /* Note: In the calculation pointer adjustment calculation, we want the 232 * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99 233 * standard indicates that if the adjustment parameter is unsigned, the 234 * stride parameter will be promoted to unsigned, causing errors when 235 * the lhs is a larger type than the rhs. 236 */ 237 img->planes[VPX_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_Y]; 238 img->stride[VPX_PLANE_Y] = -img->stride[VPX_PLANE_Y]; 239 240 img->planes[VPX_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1) 241 * img->stride[VPX_PLANE_U]; 242 img->stride[VPX_PLANE_U] = -img->stride[VPX_PLANE_U]; 243 244 img->planes[VPX_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1) 245 * img->stride[VPX_PLANE_V]; 246 img->stride[VPX_PLANE_V] = -img->stride[VPX_PLANE_V]; 247 248 img->planes[VPX_PLANE_ALPHA] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_ALPHA]; 249 img->stride[VPX_PLANE_ALPHA] = -img->stride[VPX_PLANE_ALPHA]; 250 } 251 252 void vpx_img_free(vpx_image_t *img) 253 { 254 if (img) 255 { 256 if (img->img_data && img->img_data_owner) 257 free(img->img_data); 258 259 if (img->self_allocd) 260 free(img); 261 } 262 } 263