• 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/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