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_mem/aom_mem.h"
18
align_image_dimension(unsigned int d,unsigned int subsampling,unsigned int size_align)19 static INLINE unsigned int align_image_dimension(unsigned int d,
20 unsigned int subsampling,
21 unsigned int size_align) {
22 unsigned int align;
23
24 align = (1 << subsampling) - 1;
25 align = (size_align - 1 > align) ? (size_align - 1) : align;
26 return ((d + align) & ~align);
27 }
28
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 char * img_data,unsigned int border)29 static aom_image_t *img_alloc_helper(
30 aom_image_t *img, aom_img_fmt_t fmt, unsigned int d_w, unsigned int d_h,
31 unsigned int buf_align, unsigned int stride_align, unsigned int size_align,
32 unsigned char *img_data, unsigned int border) {
33 unsigned int h, w, s, xcs, ycs, bps;
34 unsigned int stride_in_bytes;
35
36 /* Treat align==0 like align==1 */
37 if (!buf_align) buf_align = 1;
38
39 /* Validate alignment (must be power of 2) */
40 if (buf_align & (buf_align - 1)) goto fail;
41
42 /* Treat align==0 like align==1 */
43 if (!stride_align) stride_align = 1;
44
45 /* Validate alignment (must be power of 2) */
46 if (stride_align & (stride_align - 1)) goto fail;
47
48 /* Treat align==0 like align==1 */
49 if (!size_align) size_align = 1;
50
51 /* Validate alignment (must be power of 2) */
52 if (size_align & (size_align - 1)) goto fail;
53
54 /* Get sample size for this format */
55 switch (fmt) {
56 case AOM_IMG_FMT_I420:
57 case AOM_IMG_FMT_YV12:
58 case AOM_IMG_FMT_AOMI420:
59 case AOM_IMG_FMT_AOMYV12: bps = 12; break;
60 case AOM_IMG_FMT_I422:
61 case AOM_IMG_FMT_I444: bps = 24; break;
62 case AOM_IMG_FMT_YV1216:
63 case AOM_IMG_FMT_I42016: bps = 24; break;
64 case AOM_IMG_FMT_I42216:
65 case AOM_IMG_FMT_I44416: bps = 48; break;
66 default: bps = 16; break;
67 }
68
69 /* Get chroma shift values for this format */
70 switch (fmt) {
71 case AOM_IMG_FMT_I420:
72 case AOM_IMG_FMT_YV12:
73 case AOM_IMG_FMT_AOMI420:
74 case AOM_IMG_FMT_AOMYV12:
75 case AOM_IMG_FMT_I422:
76 case AOM_IMG_FMT_I42016:
77 case AOM_IMG_FMT_YV1216:
78 case AOM_IMG_FMT_I42216: xcs = 1; break;
79 default: xcs = 0; break;
80 }
81
82 switch (fmt) {
83 case AOM_IMG_FMT_I420:
84 case AOM_IMG_FMT_YV12:
85 case AOM_IMG_FMT_AOMI420:
86 case AOM_IMG_FMT_AOMYV12:
87 case AOM_IMG_FMT_YV1216:
88 case AOM_IMG_FMT_I42016: ycs = 1; break;
89 default: ycs = 0; break;
90 }
91
92 /* Calculate storage sizes given the chroma subsampling */
93 w = align_image_dimension(d_w, xcs, size_align);
94 h = align_image_dimension(d_h, ycs, size_align);
95
96 s = (fmt & AOM_IMG_FMT_PLANAR) ? w : bps * w / 8;
97 s = (s + 2 * border + stride_align - 1) & ~(stride_align - 1);
98 stride_in_bytes = (fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;
99
100 /* Allocate the new image */
101 if (!img) {
102 img = (aom_image_t *)calloc(1, sizeof(aom_image_t));
103
104 if (!img) goto fail;
105
106 img->self_allocd = 1;
107 } else {
108 memset(img, 0, sizeof(aom_image_t));
109 }
110
111 img->img_data = img_data;
112
113 if (!img_data) {
114 const uint64_t alloc_size =
115 (fmt & AOM_IMG_FMT_PLANAR)
116 ? (uint64_t)(h + 2 * border) * stride_in_bytes * bps / 8
117 : (uint64_t)(h + 2 * border) * stride_in_bytes;
118
119 if (alloc_size != (size_t)alloc_size) goto fail;
120
121 img->img_data = (uint8_t *)aom_memalign(buf_align, (size_t)alloc_size);
122 img->img_data_owner = 1;
123 img->sz = (size_t)alloc_size;
124 }
125
126 if (!img->img_data) goto fail;
127
128 img->fmt = fmt;
129 img->bit_depth = (fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
130 // aligned width and aligned height
131 img->w = w;
132 img->h = h;
133 img->x_chroma_shift = xcs;
134 img->y_chroma_shift = ycs;
135 img->bps = bps;
136
137 /* Calculate strides */
138 img->stride[AOM_PLANE_Y] = stride_in_bytes;
139 img->stride[AOM_PLANE_U] = img->stride[AOM_PLANE_V] = stride_in_bytes >> xcs;
140
141 /* Default viewport to entire image */
142 if (!aom_img_set_rect(img, 0, 0, d_w, d_h, border)) return img;
143
144 fail:
145 aom_img_free(img);
146 return NULL;
147 }
148
aom_img_alloc(aom_image_t * img,aom_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int align)149 aom_image_t *aom_img_alloc(aom_image_t *img, aom_img_fmt_t fmt,
150 unsigned int d_w, unsigned int d_h,
151 unsigned int align) {
152 return img_alloc_helper(img, fmt, d_w, d_h, align, align, 1, NULL, 0);
153 }
154
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)155 aom_image_t *aom_img_wrap(aom_image_t *img, aom_img_fmt_t fmt, unsigned int d_w,
156 unsigned int d_h, unsigned int stride_align,
157 unsigned char *img_data) {
158 /* By setting buf_align = 1, we don't change buffer alignment in this
159 * function. */
160 return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, 1, img_data, 0);
161 }
162
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)163 aom_image_t *aom_img_alloc_with_border(aom_image_t *img, aom_img_fmt_t fmt,
164 unsigned int d_w, unsigned int d_h,
165 unsigned int align,
166 unsigned int size_align,
167 unsigned int border) {
168 return img_alloc_helper(img, fmt, d_w, d_h, align, align, size_align, NULL,
169 border);
170 }
171
aom_img_set_rect(aom_image_t * img,unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int border)172 int aom_img_set_rect(aom_image_t *img, unsigned int x, unsigned int y,
173 unsigned int w, unsigned int h, unsigned int border) {
174 unsigned char *data;
175
176 if (x + w <= img->w && y + h <= img->h) {
177 img->d_w = w;
178 img->d_h = h;
179
180 x += border;
181 y += border;
182
183 /* Calculate plane pointers */
184 if (!(img->fmt & AOM_IMG_FMT_PLANAR)) {
185 img->planes[AOM_PLANE_PACKED] =
186 img->img_data + x * img->bps / 8 + y * img->stride[AOM_PLANE_PACKED];
187 } else {
188 const int bytes_per_sample =
189 (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
190 data = img->img_data;
191
192 img->planes[AOM_PLANE_Y] =
193 data + x * bytes_per_sample + y * img->stride[AOM_PLANE_Y];
194 data += (img->h + 2 * border) * img->stride[AOM_PLANE_Y];
195
196 unsigned int uv_border_h = border >> img->y_chroma_shift;
197 unsigned int uv_x = x >> img->x_chroma_shift;
198 unsigned int uv_y = y >> img->y_chroma_shift;
199 if (!(img->fmt & AOM_IMG_FMT_UV_FLIP)) {
200 img->planes[AOM_PLANE_U] =
201 data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_U];
202 data += ((img->h >> img->y_chroma_shift) + 2 * uv_border_h) *
203 img->stride[AOM_PLANE_U];
204 img->planes[AOM_PLANE_V] =
205 data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_V];
206 } else {
207 img->planes[AOM_PLANE_V] =
208 data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_V];
209 data += ((img->h >> img->y_chroma_shift) + 2 * uv_border_h) *
210 img->stride[AOM_PLANE_V];
211 img->planes[AOM_PLANE_U] =
212 data + uv_x * bytes_per_sample + uv_y * img->stride[AOM_PLANE_U];
213 }
214 }
215 return 0;
216 }
217 return -1;
218 }
219
aom_img_flip(aom_image_t * img)220 void aom_img_flip(aom_image_t *img) {
221 /* Note: In the calculation pointer adjustment calculation, we want the
222 * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
223 * standard indicates that if the adjustment parameter is unsigned, the
224 * stride parameter will be promoted to unsigned, causing errors when
225 * the lhs is a larger type than the rhs.
226 */
227 img->planes[AOM_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[AOM_PLANE_Y];
228 img->stride[AOM_PLANE_Y] = -img->stride[AOM_PLANE_Y];
229
230 img->planes[AOM_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
231 img->stride[AOM_PLANE_U];
232 img->stride[AOM_PLANE_U] = -img->stride[AOM_PLANE_U];
233
234 img->planes[AOM_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
235 img->stride[AOM_PLANE_V];
236 img->stride[AOM_PLANE_V] = -img->stride[AOM_PLANE_V];
237 }
238
aom_img_free(aom_image_t * img)239 void aom_img_free(aom_image_t *img) {
240 if (img) {
241 if (img->img_data && img->img_data_owner) aom_free(img->img_data);
242
243 if (img->self_allocd) free(img);
244 }
245 }
246
aom_img_plane_width(const aom_image_t * img,int plane)247 int aom_img_plane_width(const aom_image_t *img, int plane) {
248 if (plane > 0 && img->x_chroma_shift > 0)
249 return (img->d_w + 1) >> img->x_chroma_shift;
250 else
251 return img->d_w;
252 }
253
aom_img_plane_height(const aom_image_t * img,int plane)254 int aom_img_plane_height(const aom_image_t *img, int plane) {
255 if (plane > 0 && img->y_chroma_shift > 0)
256 return (img->d_h + 1) >> img->y_chroma_shift;
257 else
258 return img->d_h;
259 }
260