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