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