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