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