1 /*
2 * Copyright 2011 The LibYuv 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
13 #include "libyuv/convert.h"
14
15 #include "libyuv/video_common.h"
16
17 #ifdef __cplusplus
18 namespace libyuv {
19 extern "C" {
20 #endif
21
22 // Convert camera sample to I420 with cropping, rotation and vertical flip.
23 // src_width is used for source stride computation
24 // src_height is used to compute location of planes, and indicate inversion
25 // sample_size is measured in bytes and is the size of the frame.
26 // With MJPEG it is the compressed size of the frame.
27 LIBYUV_API
ConvertToI420(const uint8 * sample,size_t sample_size,uint8 * y,int y_stride,uint8 * u,int u_stride,uint8 * v,int v_stride,int crop_x,int crop_y,int src_width,int src_height,int crop_width,int crop_height,enum RotationMode rotation,uint32 fourcc)28 int ConvertToI420(const uint8* sample,
29 size_t sample_size,
30 uint8* y, int y_stride,
31 uint8* u, int u_stride,
32 uint8* v, int v_stride,
33 int crop_x, int crop_y,
34 int src_width, int src_height,
35 int crop_width, int crop_height,
36 enum RotationMode rotation,
37 uint32 fourcc) {
38 uint32 format = CanonicalFourCC(fourcc);
39 int aligned_src_width = (src_width + 1) & ~1;
40 const uint8* src;
41 const uint8* src_uv;
42 const int abs_src_height = (src_height < 0) ? -src_height : src_height;
43 // TODO(nisse): Why allow crop_height < 0?
44 const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
45 int r = 0;
46 LIBYUV_BOOL need_buf = (rotation && format != FOURCC_I420 &&
47 format != FOURCC_NV12 && format != FOURCC_NV21 &&
48 format != FOURCC_YV12) || y == sample;
49 uint8* tmp_y = y;
50 uint8* tmp_u = u;
51 uint8* tmp_v = v;
52 int tmp_y_stride = y_stride;
53 int tmp_u_stride = u_stride;
54 int tmp_v_stride = v_stride;
55 uint8* rotate_buffer = NULL;
56 const int inv_crop_height =
57 (src_height < 0) ? -abs_crop_height : abs_crop_height;
58
59 if (!y || !u || !v || !sample ||
60 src_width <= 0 || crop_width <= 0 ||
61 src_height == 0 || crop_height == 0) {
62 return -1;
63 }
64
65 // One pass rotation is available for some formats. For the rest, convert
66 // to I420 (with optional vertical flipping) into a temporary I420 buffer,
67 // and then rotate the I420 to the final destination buffer.
68 // For in-place conversion, if destination y is same as source sample,
69 // also enable temporary buffer.
70 if (need_buf) {
71 int y_size = crop_width * abs_crop_height;
72 int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
73 rotate_buffer = (uint8*)malloc(y_size + uv_size * 2);
74 if (!rotate_buffer) {
75 return 1; // Out of memory runtime error.
76 }
77 y = rotate_buffer;
78 u = y + y_size;
79 v = u + uv_size;
80 y_stride = crop_width;
81 u_stride = v_stride = ((crop_width + 1) / 2);
82 }
83
84 switch (format) {
85 // Single plane formats
86 case FOURCC_YUY2:
87 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
88 r = YUY2ToI420(src, aligned_src_width * 2,
89 y, y_stride,
90 u, u_stride,
91 v, v_stride,
92 crop_width, inv_crop_height);
93 break;
94 case FOURCC_UYVY:
95 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
96 r = UYVYToI420(src, aligned_src_width * 2,
97 y, y_stride,
98 u, u_stride,
99 v, v_stride,
100 crop_width, inv_crop_height);
101 break;
102 case FOURCC_RGBP:
103 src = sample + (src_width * crop_y + crop_x) * 2;
104 r = RGB565ToI420(src, src_width * 2,
105 y, y_stride,
106 u, u_stride,
107 v, v_stride,
108 crop_width, inv_crop_height);
109 break;
110 case FOURCC_RGBO:
111 src = sample + (src_width * crop_y + crop_x) * 2;
112 r = ARGB1555ToI420(src, src_width * 2,
113 y, y_stride,
114 u, u_stride,
115 v, v_stride,
116 crop_width, inv_crop_height);
117 break;
118 case FOURCC_R444:
119 src = sample + (src_width * crop_y + crop_x) * 2;
120 r = ARGB4444ToI420(src, src_width * 2,
121 y, y_stride,
122 u, u_stride,
123 v, v_stride,
124 crop_width, inv_crop_height);
125 break;
126 case FOURCC_24BG:
127 src = sample + (src_width * crop_y + crop_x) * 3;
128 r = RGB24ToI420(src, src_width * 3,
129 y, y_stride,
130 u, u_stride,
131 v, v_stride,
132 crop_width, inv_crop_height);
133 break;
134 case FOURCC_RAW:
135 src = sample + (src_width * crop_y + crop_x) * 3;
136 r = RAWToI420(src, src_width * 3,
137 y, y_stride,
138 u, u_stride,
139 v, v_stride,
140 crop_width, inv_crop_height);
141 break;
142 case FOURCC_ARGB:
143 src = sample + (src_width * crop_y + crop_x) * 4;
144 r = ARGBToI420(src, src_width * 4,
145 y, y_stride,
146 u, u_stride,
147 v, v_stride,
148 crop_width, inv_crop_height);
149 break;
150 case FOURCC_BGRA:
151 src = sample + (src_width * crop_y + crop_x) * 4;
152 r = BGRAToI420(src, src_width * 4,
153 y, y_stride,
154 u, u_stride,
155 v, v_stride,
156 crop_width, inv_crop_height);
157 break;
158 case FOURCC_ABGR:
159 src = sample + (src_width * crop_y + crop_x) * 4;
160 r = ABGRToI420(src, src_width * 4,
161 y, y_stride,
162 u, u_stride,
163 v, v_stride,
164 crop_width, inv_crop_height);
165 break;
166 case FOURCC_RGBA:
167 src = sample + (src_width * crop_y + crop_x) * 4;
168 r = RGBAToI420(src, src_width * 4,
169 y, y_stride,
170 u, u_stride,
171 v, v_stride,
172 crop_width, inv_crop_height);
173 break;
174 case FOURCC_I400:
175 src = sample + src_width * crop_y + crop_x;
176 r = I400ToI420(src, src_width,
177 y, y_stride,
178 u, u_stride,
179 v, v_stride,
180 crop_width, inv_crop_height);
181 break;
182 // Biplanar formats
183 case FOURCC_NV12:
184 src = sample + (src_width * crop_y + crop_x);
185 src_uv = sample + (src_width * src_height) +
186 ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
187 r = NV12ToI420Rotate(src, src_width,
188 src_uv, aligned_src_width,
189 y, y_stride,
190 u, u_stride,
191 v, v_stride,
192 crop_width, inv_crop_height, rotation);
193 break;
194 case FOURCC_NV21:
195 src = sample + (src_width * crop_y + crop_x);
196 src_uv = sample + (src_width * src_height) +
197 ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
198 // Call NV12 but with u and v parameters swapped.
199 r = NV12ToI420Rotate(src, src_width,
200 src_uv, aligned_src_width,
201 y, y_stride,
202 v, v_stride,
203 u, u_stride,
204 crop_width, inv_crop_height, rotation);
205 break;
206 case FOURCC_M420:
207 src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
208 r = M420ToI420(src, src_width,
209 y, y_stride,
210 u, u_stride,
211 v, v_stride,
212 crop_width, inv_crop_height);
213 break;
214 // Triplanar formats
215 case FOURCC_I420:
216 case FOURCC_YV12: {
217 const uint8* src_y = sample + (src_width * crop_y + crop_x);
218 const uint8* src_u;
219 const uint8* src_v;
220 int halfwidth = (src_width + 1) / 2;
221 int halfheight = (abs_src_height + 1) / 2;
222 if (format == FOURCC_YV12) {
223 src_v = sample + src_width * abs_src_height +
224 (halfwidth * crop_y + crop_x) / 2;
225 src_u = sample + src_width * abs_src_height +
226 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
227 } else {
228 src_u = sample + src_width * abs_src_height +
229 (halfwidth * crop_y + crop_x) / 2;
230 src_v = sample + src_width * abs_src_height +
231 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
232 }
233 r = I420Rotate(src_y, src_width,
234 src_u, halfwidth,
235 src_v, halfwidth,
236 y, y_stride,
237 u, u_stride,
238 v, v_stride,
239 crop_width, inv_crop_height, rotation);
240 break;
241 }
242 case FOURCC_I422:
243 case FOURCC_YV16: {
244 const uint8* src_y = sample + src_width * crop_y + crop_x;
245 const uint8* src_u;
246 const uint8* src_v;
247 int halfwidth = (src_width + 1) / 2;
248 if (format == FOURCC_YV16) {
249 src_v = sample + src_width * abs_src_height +
250 halfwidth * crop_y + crop_x / 2;
251 src_u = sample + src_width * abs_src_height +
252 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
253 } else {
254 src_u = sample + src_width * abs_src_height +
255 halfwidth * crop_y + crop_x / 2;
256 src_v = sample + src_width * abs_src_height +
257 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
258 }
259 r = I422ToI420(src_y, src_width,
260 src_u, halfwidth,
261 src_v, halfwidth,
262 y, y_stride,
263 u, u_stride,
264 v, v_stride,
265 crop_width, inv_crop_height);
266 break;
267 }
268 case FOURCC_I444:
269 case FOURCC_YV24: {
270 const uint8* src_y = sample + src_width * crop_y + crop_x;
271 const uint8* src_u;
272 const uint8* src_v;
273 if (format == FOURCC_YV24) {
274 src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
275 src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
276 } else {
277 src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
278 src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
279 }
280 r = I444ToI420(src_y, src_width,
281 src_u, src_width,
282 src_v, src_width,
283 y, y_stride,
284 u, u_stride,
285 v, v_stride,
286 crop_width, inv_crop_height);
287 break;
288 }
289 case FOURCC_I411: {
290 int quarterwidth = (src_width + 3) / 4;
291 const uint8* src_y = sample + src_width * crop_y + crop_x;
292 const uint8* src_u = sample + src_width * abs_src_height +
293 quarterwidth * crop_y + crop_x / 4;
294 const uint8* src_v = sample + src_width * abs_src_height +
295 quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
296 r = I411ToI420(src_y, src_width,
297 src_u, quarterwidth,
298 src_v, quarterwidth,
299 y, y_stride,
300 u, u_stride,
301 v, v_stride,
302 crop_width, inv_crop_height);
303 break;
304 }
305 #ifdef HAVE_JPEG
306 case FOURCC_MJPG:
307 r = MJPGToI420(sample, sample_size,
308 y, y_stride,
309 u, u_stride,
310 v, v_stride,
311 src_width, abs_src_height, crop_width, inv_crop_height);
312 break;
313 #endif
314 default:
315 r = -1; // unknown fourcc - return failure code.
316 }
317
318 if (need_buf) {
319 if (!r) {
320 r = I420Rotate(y, y_stride,
321 u, u_stride,
322 v, v_stride,
323 tmp_y, tmp_y_stride,
324 tmp_u, tmp_u_stride,
325 tmp_v, tmp_v_stride,
326 crop_width, abs_crop_height, rotation);
327 }
328 free(rotate_buffer);
329 }
330
331 return r;
332 }
333
334 #ifdef __cplusplus
335 } // extern "C"
336 } // namespace libyuv
337 #endif
338