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