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