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