• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <limits.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "aom/aom_image.h"
17 #include "aom/aom_integer.h"
18 #include "aom/internal/aom_image_internal.h"
19 #include "aom_mem/aom_mem.h"
20 
align_image_dimension(unsigned int d,unsigned int subsampling,unsigned int size_align)21 static INLINE unsigned int align_image_dimension(unsigned int d,
22                                                  unsigned int subsampling,
23                                                  unsigned int size_align) {
24   unsigned int align;
25 
26   align = (1 << subsampling) - 1;
27   align = (size_align - 1 > align) ? (size_align - 1) : align;
28   return ((d + align) & ~align);
29 }
30 
img_alloc_helper(aom_image_t * img,aom_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int buf_align,unsigned int stride_align,unsigned int size_align,unsigned int border,unsigned char * img_data,aom_alloc_img_data_cb_fn_t alloc_cb,void * cb_priv)31 static aom_image_t *img_alloc_helper(
32     aom_image_t *img, aom_img_fmt_t fmt, unsigned int d_w, unsigned int d_h,
33     unsigned int buf_align, unsigned int stride_align, unsigned int size_align,
34     unsigned int border, unsigned char *img_data,
35     aom_alloc_img_data_cb_fn_t alloc_cb, void *cb_priv) {
36   /* NOTE: In this function, bit_depth is either 8 or 16 (if
37    * AOM_IMG_FMT_HIGHBITDEPTH is set), never 10 or 12.
38    */
39   unsigned int h, w, s, xcs, ycs, bps, bit_depth;
40   unsigned int stride_in_bytes;
41 
42   if (img != NULL) memset(img, 0, sizeof(aom_image_t));
43 
44   /* Treat align==0 like align==1 */
45   if (!buf_align) buf_align = 1;
46 
47   /* Validate alignment (must be power of 2) */
48   if (buf_align & (buf_align - 1)) goto fail;
49 
50   /* Treat align==0 like align==1 */
51   if (!stride_align) stride_align = 1;
52 
53   /* Validate alignment (must be power of 2) */
54   if (stride_align & (stride_align - 1)) goto fail;
55 
56   /* Treat align==0 like align==1 */
57   if (!size_align) size_align = 1;
58 
59   /* Validate alignment (must be power of 2) */
60   if (size_align & (size_align - 1)) goto fail;
61 
62   /* Get sample size for this format */
63   switch (fmt) {
64     case AOM_IMG_FMT_I420:
65     case AOM_IMG_FMT_YV12:
66     case AOM_IMG_FMT_NV12:
67     case AOM_IMG_FMT_AOMI420:
68     case AOM_IMG_FMT_AOMYV12: bps = 12; break;
69     case AOM_IMG_FMT_I422: bps = 16; break;
70     case AOM_IMG_FMT_I444: bps = 24; break;
71     case AOM_IMG_FMT_YV1216:
72     case AOM_IMG_FMT_I42016: bps = 24; break;
73     case AOM_IMG_FMT_I42216: bps = 32; break;
74     case AOM_IMG_FMT_I44416: bps = 48; break;
75     default: bps = 16; break;
76   }
77 
78   bit_depth = (fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
79 
80   /* Get chroma shift values for this format */
81   switch (fmt) {
82     case AOM_IMG_FMT_I420:
83     case AOM_IMG_FMT_YV12:
84     case AOM_IMG_FMT_NV12:
85     case AOM_IMG_FMT_AOMI420:
86     case AOM_IMG_FMT_AOMYV12:
87     case AOM_IMG_FMT_I422:
88     case AOM_IMG_FMT_I42016:
89     case AOM_IMG_FMT_YV1216:
90     case AOM_IMG_FMT_I42216: xcs = 1; break;
91     default: xcs = 0; break;
92   }
93 
94   switch (fmt) {
95     case AOM_IMG_FMT_I420:
96     case AOM_IMG_FMT_YV12:
97     case AOM_IMG_FMT_NV12:
98     case AOM_IMG_FMT_AOMI420:
99     case AOM_IMG_FMT_AOMYV12:
100     case AOM_IMG_FMT_YV1216:
101     case AOM_IMG_FMT_I42016: ycs = 1; break;
102     default: ycs = 0; break;
103   }
104 
105   /* Calculate storage sizes given the chroma subsampling */
106   w = align_image_dimension(d_w, xcs, size_align);
107   h = align_image_dimension(d_h, ycs, size_align);
108 
109   s = (fmt & AOM_IMG_FMT_PLANAR) ? w : bps * w / bit_depth;
110   s = (s + 2 * border + stride_align - 1) & ~(stride_align - 1);
111   stride_in_bytes = s * bit_depth / 8;
112 
113   /* Allocate the new image */
114   if (!img) {
115     img = (aom_image_t *)calloc(1, sizeof(aom_image_t));
116 
117     if (!img) goto fail;
118 
119     img->self_allocd = 1;
120   }
121 
122   img->img_data = img_data;
123 
124   if (!img_data) {
125     const uint64_t alloc_size =
126         (fmt & AOM_IMG_FMT_PLANAR)
127             ? (uint64_t)(h + 2 * border) * stride_in_bytes * bps / bit_depth
128             : (uint64_t)(h + 2 * border) * stride_in_bytes;
129 
130     if (alloc_size != (size_t)alloc_size) goto fail;
131 
132     if (alloc_cb) {
133       const size_t padded_alloc_size = (size_t)alloc_size + buf_align - 1;
134       img->img_data = (uint8_t *)alloc_cb(cb_priv, padded_alloc_size);
135       if (img->img_data) {
136         img->img_data = (uint8_t *)aom_align_addr(img->img_data, buf_align);
137       }
138       img->img_data_owner = 0;
139     } else {
140       img->img_data = (uint8_t *)aom_memalign(buf_align, (size_t)alloc_size);
141       img->img_data_owner = 1;
142     }
143     img->sz = (size_t)alloc_size;
144   }
145 
146   if (!img->img_data) goto fail;
147 
148   img->fmt = fmt;
149   img->bit_depth = bit_depth;
150   // aligned width and aligned height
151   img->w = w;
152   img->h = h;
153   img->x_chroma_shift = xcs;
154   img->y_chroma_shift = ycs;
155   img->bps = bps;
156 
157   /* Calculate strides */
158   img->stride[AOM_PLANE_Y] = stride_in_bytes;
159   img->stride[AOM_PLANE_U] = img->stride[AOM_PLANE_V] = stride_in_bytes >> xcs;
160 
161   if (fmt == AOM_IMG_FMT_NV12) {
162     // Each row is a row of U and a row of V interleaved, so the stride is twice
163     // as long.
164     img->stride[AOM_PLANE_U] *= 2;
165     img->stride[AOM_PLANE_V] = 0;
166   }
167 
168   /* Default viewport to entire image. (This aom_img_set_rect call always
169    * succeeds.) */
170   aom_img_set_rect(img, 0, 0, d_w, d_h, border);
171   return img;
172 
173 fail:
174   aom_img_free(img);
175   return NULL;
176 }
177 
aom_img_alloc(aom_image_t * img,aom_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int align)178 aom_image_t *aom_img_alloc(aom_image_t *img, aom_img_fmt_t fmt,
179                            unsigned int d_w, unsigned int d_h,
180                            unsigned int align) {
181   return img_alloc_helper(img, fmt, d_w, d_h, align, align, 1, 0, NULL, NULL,
182                           NULL);
183 }
184 
aom_img_alloc_with_cb(aom_image_t * img,aom_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int align,aom_alloc_img_data_cb_fn_t alloc_cb,void * cb_priv)185 aom_image_t *aom_img_alloc_with_cb(aom_image_t *img, aom_img_fmt_t fmt,
186                                    unsigned int d_w, unsigned int d_h,
187                                    unsigned int align,
188                                    aom_alloc_img_data_cb_fn_t alloc_cb,
189                                    void *cb_priv) {
190   return img_alloc_helper(img, fmt, d_w, d_h, align, align, 1, 0, NULL,
191                           alloc_cb, cb_priv);
192 }
193 
aom_img_wrap(aom_image_t * img,aom_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int stride_align,unsigned char * img_data)194 aom_image_t *aom_img_wrap(aom_image_t *img, aom_img_fmt_t fmt, unsigned int d_w,
195                           unsigned int d_h, unsigned int stride_align,
196                           unsigned char *img_data) {
197   /* Set buf_align = 1. It is ignored by img_alloc_helper because img_data is
198    * not NULL. */
199   return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, 1, 0, img_data,
200                           NULL, NULL);
201 }
202 
aom_img_alloc_with_border(aom_image_t * img,aom_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int align,unsigned int size_align,unsigned int border)203 aom_image_t *aom_img_alloc_with_border(aom_image_t *img, aom_img_fmt_t fmt,
204                                        unsigned int d_w, unsigned int d_h,
205                                        unsigned int align,
206                                        unsigned int size_align,
207                                        unsigned int border) {
208   return img_alloc_helper(img, fmt, d_w, d_h, align, align, size_align, border,
209                           NULL, NULL, NULL);
210 }
211 
aom_img_set_rect(aom_image_t * img,unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int border)212 int aom_img_set_rect(aom_image_t *img, unsigned int x, unsigned int y,
213                      unsigned int w, unsigned int h, unsigned int border) {
214   if (x <= UINT_MAX - w && x + w <= img->w && y <= UINT_MAX - h &&
215       y + h <= img->h) {
216     img->d_w = w;
217     img->d_h = h;
218 
219     x += border;
220     y += border;
221 
222     /* Calculate plane pointers */
223     if (!(img->fmt & AOM_IMG_FMT_PLANAR)) {
224       img->planes[AOM_PLANE_PACKED] =
225           img->img_data + x * img->bps / 8 + y * img->stride[AOM_PLANE_PACKED];
226     } else {
227       const int bytes_per_sample =
228           (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
229       unsigned char *data = img->img_data;
230 
231       img->planes[AOM_PLANE_Y] =
232           data + x * bytes_per_sample + y * img->stride[AOM_PLANE_Y];
233       data += (img->h + 2 * border) * img->stride[AOM_PLANE_Y];
234 
235       unsigned int uv_border_h = border >> img->y_chroma_shift;
236       unsigned int uv_x = x >> img->x_chroma_shift;
237       unsigned int uv_y = y >> img->y_chroma_shift;
238       if (img->fmt == AOM_IMG_FMT_NV12) {
239         img->planes[AOM_PLANE_U] = data + uv_x * bytes_per_sample * 2 +
240                                    uv_y * img->stride[AOM_PLANE_U];
241         img->planes[AOM_PLANE_V] = NULL;
242       } else if (!(img->fmt & AOM_IMG_FMT_UV_FLIP)) {
243         img->planes[AOM_PLANE_U] =
244             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_U];
245         data += ((img->h >> img->y_chroma_shift) + 2 * uv_border_h) *
246                 img->stride[AOM_PLANE_U];
247         img->planes[AOM_PLANE_V] =
248             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_V];
249       } else {
250         img->planes[AOM_PLANE_V] =
251             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_V];
252         data += ((img->h >> img->y_chroma_shift) + 2 * uv_border_h) *
253                 img->stride[AOM_PLANE_V];
254         img->planes[AOM_PLANE_U] =
255             data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_U];
256       }
257     }
258     return 0;
259   }
260   return -1;
261 }
262 
aom_img_flip(aom_image_t * img)263 void aom_img_flip(aom_image_t *img) {
264   /* Note: In the calculation pointer adjustment calculation, we want the
265    * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
266    * standard indicates that if the adjustment parameter is unsigned, the
267    * stride parameter will be promoted to unsigned, causing errors when
268    * the lhs is a larger type than the rhs.
269    */
270   img->planes[AOM_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[AOM_PLANE_Y];
271   img->stride[AOM_PLANE_Y] = -img->stride[AOM_PLANE_Y];
272 
273   img->planes[AOM_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
274                               img->stride[AOM_PLANE_U];
275   img->stride[AOM_PLANE_U] = -img->stride[AOM_PLANE_U];
276 
277   img->planes[AOM_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
278                               img->stride[AOM_PLANE_V];
279   img->stride[AOM_PLANE_V] = -img->stride[AOM_PLANE_V];
280 }
281 
aom_img_free(aom_image_t * img)282 void aom_img_free(aom_image_t *img) {
283   if (img) {
284     aom_img_remove_metadata(img);
285     if (img->img_data && img->img_data_owner) aom_free(img->img_data);
286 
287     if (img->self_allocd) free(img);
288   }
289 }
290 
aom_img_plane_width(const aom_image_t * img,int plane)291 int aom_img_plane_width(const aom_image_t *img, int plane) {
292   if (plane > 0 && img->x_chroma_shift > 0)
293     return (img->d_w + 1) >> img->x_chroma_shift;
294   else
295     return img->d_w;
296 }
297 
aom_img_plane_height(const aom_image_t * img,int plane)298 int aom_img_plane_height(const aom_image_t *img, int plane) {
299   if (plane > 0 && img->y_chroma_shift > 0)
300     return (img->d_h + 1) >> img->y_chroma_shift;
301   else
302     return img->d_h;
303 }
304 
aom_img_metadata_alloc(uint32_t type,const uint8_t * data,size_t sz,aom_metadata_insert_flags_t insert_flag)305 aom_metadata_t *aom_img_metadata_alloc(
306     uint32_t type, const uint8_t *data, size_t sz,
307     aom_metadata_insert_flags_t insert_flag) {
308   if (!data || sz == 0) return NULL;
309   aom_metadata_t *metadata = (aom_metadata_t *)malloc(sizeof(aom_metadata_t));
310   if (!metadata) return NULL;
311   metadata->type = type;
312   metadata->payload = (uint8_t *)malloc(sz);
313   if (!metadata->payload) {
314     free(metadata);
315     return NULL;
316   }
317   memcpy(metadata->payload, data, sz);
318   metadata->sz = sz;
319   metadata->insert_flag = insert_flag;
320   return metadata;
321 }
322 
aom_img_metadata_free(aom_metadata_t * metadata)323 void aom_img_metadata_free(aom_metadata_t *metadata) {
324   if (metadata) {
325     if (metadata->payload) free(metadata->payload);
326     free(metadata);
327   }
328 }
329 
aom_img_metadata_array_alloc(size_t sz)330 aom_metadata_array_t *aom_img_metadata_array_alloc(size_t sz) {
331   aom_metadata_array_t *arr =
332       (aom_metadata_array_t *)calloc(1, sizeof(aom_metadata_array_t));
333   if (!arr) return NULL;
334   if (sz > 0) {
335     arr->metadata_array =
336         (aom_metadata_t **)calloc(sz, sizeof(aom_metadata_t *));
337     if (!arr->metadata_array) {
338       aom_img_metadata_array_free(arr);
339       return NULL;
340     }
341     arr->sz = sz;
342   }
343   return arr;
344 }
345 
aom_img_metadata_array_free(aom_metadata_array_t * arr)346 void aom_img_metadata_array_free(aom_metadata_array_t *arr) {
347   if (arr) {
348     if (arr->metadata_array) {
349       for (size_t i = 0; i < arr->sz; i++) {
350         aom_img_metadata_free(arr->metadata_array[i]);
351       }
352       free(arr->metadata_array);
353     }
354     free(arr);
355   }
356 }
357 
aom_img_add_metadata(aom_image_t * img,uint32_t type,const uint8_t * data,size_t sz,aom_metadata_insert_flags_t insert_flag)358 int aom_img_add_metadata(aom_image_t *img, uint32_t type, const uint8_t *data,
359                          size_t sz, aom_metadata_insert_flags_t insert_flag) {
360   if (!img) return -1;
361   if (!img->metadata) {
362     img->metadata = aom_img_metadata_array_alloc(0);
363     if (!img->metadata) return -1;
364   }
365   aom_metadata_t *metadata =
366       aom_img_metadata_alloc(type, data, sz, insert_flag);
367   if (!metadata) return -1;
368   aom_metadata_t **metadata_array =
369       (aom_metadata_t **)realloc(img->metadata->metadata_array,
370                                  (img->metadata->sz + 1) * sizeof(metadata));
371   if (!metadata_array) {
372     aom_img_metadata_free(metadata);
373     return -1;
374   }
375   img->metadata->metadata_array = metadata_array;
376   img->metadata->metadata_array[img->metadata->sz] = metadata;
377   img->metadata->sz++;
378   return 0;
379 }
380 
aom_img_remove_metadata(aom_image_t * img)381 void aom_img_remove_metadata(aom_image_t *img) {
382   if (img && img->metadata) {
383     aom_img_metadata_array_free(img->metadata);
384     img->metadata = NULL;
385   }
386 }
387 
aom_img_get_metadata(const aom_image_t * img,size_t index)388 const aom_metadata_t *aom_img_get_metadata(const aom_image_t *img,
389                                            size_t index) {
390   if (!img) return NULL;
391   const aom_metadata_array_t *array = img->metadata;
392   if (array && index < array->sz) {
393     return array->metadata_array[index];
394   }
395   return NULL;
396 }
397 
aom_img_num_metadata(const aom_image_t * img)398 size_t aom_img_num_metadata(const aom_image_t *img) {
399   if (!img || !img->metadata) return 0;
400   return img->metadata->sz;
401 }
402