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 #include "vpx/vpx_integer.h"
16
17 #define ADDRESS_STORAGE_SIZE sizeof(size_t)
18 /*returns an addr aligned to the byte boundary specified by align*/
19 #define align_addr(addr,align) (void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))
20
21 /* Memalign code is copied from vpx_mem.c */
img_buf_memalign(size_t align,size_t size)22 static void *img_buf_memalign(size_t align, size_t size) {
23 void *addr,
24 * x = NULL;
25
26 addr = malloc(size + align - 1 + ADDRESS_STORAGE_SIZE);
27
28 if (addr) {
29 x = align_addr((unsigned char *)addr + ADDRESS_STORAGE_SIZE, (int)align);
30 /* save the actual malloc address */
31 ((size_t *)x)[-1] = (size_t)addr;
32 }
33
34 return x;
35 }
36
img_buf_free(void * memblk)37 static void img_buf_free(void *memblk) {
38 if (memblk) {
39 void *addr = (void *)(((size_t *)memblk)[-1]);
40 free(addr);
41 }
42 }
43
img_alloc_helper(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int buf_align,unsigned int stride_align,unsigned char * img_data)44 static vpx_image_t *img_alloc_helper(vpx_image_t *img,
45 vpx_img_fmt_t fmt,
46 unsigned int d_w,
47 unsigned int d_h,
48 unsigned int buf_align,
49 unsigned int stride_align,
50 unsigned char *img_data) {
51
52 unsigned int h, w, s, xcs, ycs, bps;
53 int align;
54
55 /* Treat align==0 like align==1 */
56 if (!buf_align)
57 buf_align = 1;
58
59 /* Validate alignment (must be power of 2) */
60 if (buf_align & (buf_align - 1))
61 goto fail;
62
63 /* Treat align==0 like align==1 */
64 if (!stride_align)
65 stride_align = 1;
66
67 /* Validate alignment (must be power of 2) */
68 if (stride_align & (stride_align - 1))
69 goto fail;
70
71 /* Get sample size for this format */
72 switch (fmt) {
73 case VPX_IMG_FMT_RGB32:
74 case VPX_IMG_FMT_RGB32_LE:
75 case VPX_IMG_FMT_ARGB:
76 case VPX_IMG_FMT_ARGB_LE:
77 bps = 32;
78 break;
79 case VPX_IMG_FMT_RGB24:
80 case VPX_IMG_FMT_BGR24:
81 bps = 24;
82 break;
83 case VPX_IMG_FMT_RGB565:
84 case VPX_IMG_FMT_RGB565_LE:
85 case VPX_IMG_FMT_RGB555:
86 case VPX_IMG_FMT_RGB555_LE:
87 case VPX_IMG_FMT_UYVY:
88 case VPX_IMG_FMT_YUY2:
89 case VPX_IMG_FMT_YVYU:
90 bps = 16;
91 break;
92 case VPX_IMG_FMT_I420:
93 case VPX_IMG_FMT_YV12:
94 case VPX_IMG_FMT_VPXI420:
95 case VPX_IMG_FMT_VPXYV12:
96 bps = 12;
97 break;
98 case VPX_IMG_FMT_I422:
99 bps = 16;
100 break;
101 case VPX_IMG_FMT_I444:
102 bps = 24;
103 break;
104 case VPX_IMG_FMT_I42016:
105 bps = 24;
106 break;
107 case VPX_IMG_FMT_I42216:
108 bps = 32;
109 break;
110 case VPX_IMG_FMT_I44416:
111 bps = 48;
112 break;
113 default:
114 bps = 16;
115 break;
116 }
117
118 /* Get chroma shift values for this format */
119 switch (fmt) {
120 case VPX_IMG_FMT_I420:
121 case VPX_IMG_FMT_YV12:
122 case VPX_IMG_FMT_VPXI420:
123 case VPX_IMG_FMT_VPXYV12:
124 case VPX_IMG_FMT_I422:
125 case VPX_IMG_FMT_I42016:
126 case VPX_IMG_FMT_I42216:
127 xcs = 1;
128 break;
129 default:
130 xcs = 0;
131 break;
132 }
133
134 switch (fmt) {
135 case VPX_IMG_FMT_I420:
136 case VPX_IMG_FMT_YV12:
137 case VPX_IMG_FMT_VPXI420:
138 case VPX_IMG_FMT_VPXYV12:
139 ycs = 1;
140 break;
141 default:
142 ycs = 0;
143 break;
144 }
145
146 /* Calculate storage sizes given the chroma subsampling */
147 align = (1 << xcs) - 1;
148 w = (d_w + align) & ~align;
149 align = (1 << ycs) - 1;
150 h = (d_h + align) & ~align;
151 s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
152 s = (s + stride_align - 1) & ~(stride_align - 1);
153
154 /* Allocate the new image */
155 if (!img) {
156 img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t));
157
158 if (!img)
159 goto fail;
160
161 img->self_allocd = 1;
162 } else {
163 memset(img, 0, sizeof(vpx_image_t));
164 }
165
166 img->img_data = img_data;
167
168 if (!img_data) {
169 const uint64_t alloc_size = (fmt & VPX_IMG_FMT_PLANAR) ?
170 (uint64_t)h * s * bps / 8 : (uint64_t)h * s;
171
172 if (alloc_size != (size_t)alloc_size)
173 goto fail;
174
175 img->img_data = img_buf_memalign(buf_align, (size_t)alloc_size);
176 img->img_data_owner = 1;
177 }
178
179 if (!img->img_data)
180 goto fail;
181
182 img->fmt = fmt;
183 img->bit_depth = (fmt & VPX_IMG_FMT_HIGH) ? 16 : 8;
184 img->w = w;
185 img->h = h;
186 img->x_chroma_shift = xcs;
187 img->y_chroma_shift = ycs;
188 img->bps = bps;
189
190 /* Calculate strides */
191 img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = s;
192 img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = s >> xcs;
193
194 /* Default viewport to entire image */
195 if (!vpx_img_set_rect(img, 0, 0, d_w, d_h))
196 return img;
197
198 fail:
199 vpx_img_free(img);
200 return NULL;
201 }
202
vpx_img_alloc(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int align)203 vpx_image_t *vpx_img_alloc(vpx_image_t *img,
204 vpx_img_fmt_t fmt,
205 unsigned int d_w,
206 unsigned int d_h,
207 unsigned int align) {
208 return img_alloc_helper(img, fmt, d_w, d_h, align, align, NULL);
209 }
210
vpx_img_wrap(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int stride_align,unsigned char * img_data)211 vpx_image_t *vpx_img_wrap(vpx_image_t *img,
212 vpx_img_fmt_t fmt,
213 unsigned int d_w,
214 unsigned int d_h,
215 unsigned int stride_align,
216 unsigned char *img_data) {
217 /* By setting buf_align = 1, we don't change buffer alignment in this
218 * function. */
219 return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, img_data);
220 }
221
vpx_img_set_rect(vpx_image_t * img,unsigned int x,unsigned int y,unsigned int w,unsigned int h)222 int vpx_img_set_rect(vpx_image_t *img,
223 unsigned int x,
224 unsigned int y,
225 unsigned int w,
226 unsigned int h) {
227 unsigned char *data;
228
229 if (x + w <= img->w && y + h <= img->h) {
230 img->d_w = w;
231 img->d_h = h;
232
233 /* Calculate plane pointers */
234 if (!(img->fmt & VPX_IMG_FMT_PLANAR)) {
235 img->planes[VPX_PLANE_PACKED] =
236 img->img_data + x * img->bps / 8 + y * img->stride[VPX_PLANE_PACKED];
237 } else {
238 data = img->img_data;
239
240 if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) {
241 img->planes[VPX_PLANE_ALPHA] =
242 data + x + y * img->stride[VPX_PLANE_ALPHA];
243 data += img->h * img->stride[VPX_PLANE_ALPHA];
244 }
245
246 img->planes[VPX_PLANE_Y] = data + x + y * img->stride[VPX_PLANE_Y];
247 data += img->h * img->stride[VPX_PLANE_Y];
248
249 if (!(img->fmt & VPX_IMG_FMT_UV_FLIP)) {
250 img->planes[VPX_PLANE_U] = data
251 + (x >> img->x_chroma_shift)
252 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
253 data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
254 img->planes[VPX_PLANE_V] = data
255 + (x >> img->x_chroma_shift)
256 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
257 } else {
258 img->planes[VPX_PLANE_V] = data
259 + (x >> img->x_chroma_shift)
260 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
261 data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
262 img->planes[VPX_PLANE_U] = data
263 + (x >> img->x_chroma_shift)
264 + (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
265 }
266 }
267
268 return 0;
269 }
270
271 return -1;
272 }
273
vpx_img_flip(vpx_image_t * img)274 void vpx_img_flip(vpx_image_t *img) {
275 /* Note: In the calculation pointer adjustment calculation, we want the
276 * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
277 * standard indicates that if the adjustment parameter is unsigned, the
278 * stride parameter will be promoted to unsigned, causing errors when
279 * the lhs is a larger type than the rhs.
280 */
281 img->planes[VPX_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_Y];
282 img->stride[VPX_PLANE_Y] = -img->stride[VPX_PLANE_Y];
283
284 img->planes[VPX_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
285 * img->stride[VPX_PLANE_U];
286 img->stride[VPX_PLANE_U] = -img->stride[VPX_PLANE_U];
287
288 img->planes[VPX_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1)
289 * img->stride[VPX_PLANE_V];
290 img->stride[VPX_PLANE_V] = -img->stride[VPX_PLANE_V];
291
292 img->planes[VPX_PLANE_ALPHA] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_ALPHA];
293 img->stride[VPX_PLANE_ALPHA] = -img->stride[VPX_PLANE_ALPHA];
294 }
295
vpx_img_free(vpx_image_t * img)296 void vpx_img_free(vpx_image_t *img) {
297 if (img) {
298 if (img->img_data && img->img_data_owner)
299 img_buf_free(img->img_data);
300
301 if (img->self_allocd)
302 free(img);
303 }
304 }
305