• 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_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