• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <limits.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "vpx/vpx_image.h"
16 #include "vpx/vpx_integer.h"
17 #include "vpx_mem/vpx_mem.h"
18 
img_alloc_helper(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int buf_align,unsigned int stride_align,unsigned char * img_data)19 static vpx_image_t *img_alloc_helper(vpx_image_t *img, vpx_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   unsigned int align;
27 
28   if (img != NULL) memset(img, 0, sizeof(vpx_image_t));
29 
30   /* Treat align==0 like align==1 */
31   if (!buf_align) buf_align = 1;
32 
33   /* Validate alignment (must be power of 2) */
34   if (buf_align & (buf_align - 1)) goto fail;
35 
36   /* Treat align==0 like align==1 */
37   if (!stride_align) stride_align = 1;
38 
39   /* Validate alignment (must be power of 2) */
40   if (stride_align & (stride_align - 1)) goto fail;
41 
42   /* Get sample size for this format */
43   switch (fmt) {
44     case VPX_IMG_FMT_I420:
45     case VPX_IMG_FMT_YV12:
46     case VPX_IMG_FMT_NV12: bps = 12; break;
47     case VPX_IMG_FMT_I422:
48     case VPX_IMG_FMT_I440: bps = 16; break;
49     case VPX_IMG_FMT_I444: bps = 24; break;
50     case VPX_IMG_FMT_I42016: bps = 24; break;
51     case VPX_IMG_FMT_I42216:
52     case VPX_IMG_FMT_I44016: bps = 32; break;
53     case VPX_IMG_FMT_I44416: bps = 48; break;
54     default: bps = 16; break;
55   }
56 
57   /* Get chroma shift values for this format */
58   // For VPX_IMG_FMT_NV12, xcs needs to be 0 such that UV data is all read at
59   // one time.
60   switch (fmt) {
61     case VPX_IMG_FMT_I420:
62     case VPX_IMG_FMT_YV12:
63     case VPX_IMG_FMT_I422:
64     case VPX_IMG_FMT_I42016:
65     case VPX_IMG_FMT_I42216: xcs = 1; break;
66     default: xcs = 0; break;
67   }
68 
69   switch (fmt) {
70     case VPX_IMG_FMT_I420:
71     case VPX_IMG_FMT_NV12:
72     case VPX_IMG_FMT_I440:
73     case VPX_IMG_FMT_YV12:
74     case VPX_IMG_FMT_I42016:
75     case VPX_IMG_FMT_I44016: ycs = 1; break;
76     default: ycs = 0; break;
77   }
78 
79   /* Calculate storage sizes. If the buffer was allocated externally, the width
80    * and height shouldn't be adjusted. */
81   w = d_w;
82   h = d_h;
83   s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
84   s = (s + stride_align - 1) & ~(stride_align - 1);
85   stride_in_bytes = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;
86 
87   /* Allocate the new image */
88   if (!img) {
89     img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t));
90 
91     if (!img) goto fail;
92 
93     img->self_allocd = 1;
94   }
95 
96   img->img_data = img_data;
97 
98   if (!img_data) {
99     uint64_t alloc_size;
100     /* Calculate storage sizes given the chroma subsampling */
101     align = (1 << xcs) - 1;
102     w = (d_w + align) & ~align;
103     align = (1 << ycs) - 1;
104     h = (d_h + align) & ~align;
105 
106     s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
107     s = (s + stride_align - 1) & ~(stride_align - 1);
108     stride_in_bytes = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;
109     alloc_size = (fmt & VPX_IMG_FMT_PLANAR) ? (uint64_t)h * s * bps / 8
110                                             : (uint64_t)h * s;
111 
112     if (alloc_size != (size_t)alloc_size) goto fail;
113 
114     img->img_data = (uint8_t *)vpx_memalign(buf_align, (size_t)alloc_size);
115     img->img_data_owner = 1;
116   }
117 
118   if (!img->img_data) goto fail;
119 
120   img->fmt = fmt;
121   img->bit_depth = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
122   img->w = w;
123   img->h = h;
124   img->x_chroma_shift = xcs;
125   img->y_chroma_shift = ycs;
126   img->bps = bps;
127 
128   /* Calculate strides */
129   img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = stride_in_bytes;
130   img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = stride_in_bytes >> xcs;
131 
132   /* Default viewport to entire image */
133   if (!vpx_img_set_rect(img, 0, 0, d_w, d_h)) return img;
134 
135 fail:
136   vpx_img_free(img);
137   return NULL;
138 }
139 
vpx_img_alloc(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int align)140 vpx_image_t *vpx_img_alloc(vpx_image_t *img, vpx_img_fmt_t fmt,
141                            unsigned int d_w, unsigned int d_h,
142                            unsigned int align) {
143   return img_alloc_helper(img, fmt, d_w, d_h, align, align, NULL);
144 }
145 
vpx_img_wrap(vpx_image_t * img,vpx_img_fmt_t fmt,unsigned int d_w,unsigned int d_h,unsigned int stride_align,unsigned char * img_data)146 vpx_image_t *vpx_img_wrap(vpx_image_t *img, vpx_img_fmt_t fmt, unsigned int d_w,
147                           unsigned int d_h, unsigned int stride_align,
148                           unsigned char *img_data) {
149   /* By setting buf_align = 1, we don't change buffer alignment in this
150    * function. */
151   return img_alloc_helper(img, fmt, d_w, d_h, 1, stride_align, img_data);
152 }
153 
vpx_img_set_rect(vpx_image_t * img,unsigned int x,unsigned int y,unsigned int w,unsigned int h)154 int vpx_img_set_rect(vpx_image_t *img, unsigned int x, unsigned int y,
155                      unsigned int w, unsigned int h) {
156   if (x <= UINT_MAX - w && x + w <= img->w && y <= UINT_MAX - h &&
157       y + h <= img->h) {
158     img->d_w = w;
159     img->d_h = h;
160 
161     /* Calculate plane pointers */
162     if (!(img->fmt & VPX_IMG_FMT_PLANAR)) {
163       img->planes[VPX_PLANE_PACKED] =
164           img->img_data + x * img->bps / 8 + y * img->stride[VPX_PLANE_PACKED];
165     } else {
166       const int bytes_per_sample =
167           (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
168       unsigned char *data = img->img_data;
169 
170       if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) {
171         img->planes[VPX_PLANE_ALPHA] =
172             data + x * bytes_per_sample + y * img->stride[VPX_PLANE_ALPHA];
173         data += img->h * img->stride[VPX_PLANE_ALPHA];
174       }
175 
176       img->planes[VPX_PLANE_Y] =
177           data + x * bytes_per_sample + y * img->stride[VPX_PLANE_Y];
178       data += img->h * img->stride[VPX_PLANE_Y];
179 
180       if (img->fmt == VPX_IMG_FMT_NV12) {
181         img->planes[VPX_PLANE_U] =
182             data + (x >> img->x_chroma_shift) +
183             (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
184         img->planes[VPX_PLANE_V] = img->planes[VPX_PLANE_U] + 1;
185       } else if (!(img->fmt & VPX_IMG_FMT_UV_FLIP)) {
186         img->planes[VPX_PLANE_U] =
187             data + (x >> img->x_chroma_shift) * bytes_per_sample +
188             (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
189         data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
190         img->planes[VPX_PLANE_V] =
191             data + (x >> img->x_chroma_shift) * bytes_per_sample +
192             (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
193       } else {
194         img->planes[VPX_PLANE_V] =
195             data + (x >> img->x_chroma_shift) * bytes_per_sample +
196             (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
197         data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
198         img->planes[VPX_PLANE_U] =
199             data + (x >> img->x_chroma_shift) * bytes_per_sample +
200             (y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
201       }
202     }
203     return 0;
204   }
205   return -1;
206 }
207 
vpx_img_flip(vpx_image_t * img)208 void vpx_img_flip(vpx_image_t *img) {
209   /* Note: In the calculation pointer adjustment calculation, we want the
210    * rhs to be promoted to a signed type. Section 6.3.1.8 of the ISO C99
211    * standard indicates that if the adjustment parameter is unsigned, the
212    * stride parameter will be promoted to unsigned, causing errors when
213    * the lhs is a larger type than the rhs.
214    */
215   img->planes[VPX_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[VPX_PLANE_Y];
216   img->stride[VPX_PLANE_Y] = -img->stride[VPX_PLANE_Y];
217 
218   img->planes[VPX_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
219                               img->stride[VPX_PLANE_U];
220   img->stride[VPX_PLANE_U] = -img->stride[VPX_PLANE_U];
221 
222   img->planes[VPX_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1) *
223                               img->stride[VPX_PLANE_V];
224   img->stride[VPX_PLANE_V] = -img->stride[VPX_PLANE_V];
225 
226   img->planes[VPX_PLANE_ALPHA] +=
227       (signed)(img->d_h - 1) * img->stride[VPX_PLANE_ALPHA];
228   img->stride[VPX_PLANE_ALPHA] = -img->stride[VPX_PLANE_ALPHA];
229 }
230 
vpx_img_free(vpx_image_t * img)231 void vpx_img_free(vpx_image_t *img) {
232   if (img) {
233     if (img->img_data && img->img_data_owner) vpx_free(img->img_data);
234 
235     if (img->self_allocd) free(img);
236   }
237 }
238