• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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