• 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,
31                   int y_stride,
32                   uint8* u,
33                   int u_stride,
34                   uint8* v,
35                   int v_stride,
36                   int crop_x,
37                   int crop_y,
38                   int src_width,
39                   int src_height,
40                   int crop_width,
41                   int crop_height,
42                   enum RotationMode rotation,
43                   uint32 fourcc) {
44   uint32 format = CanonicalFourCC(fourcc);
45   int aligned_src_width = (src_width + 1) & ~1;
46   const uint8* src;
47   const uint8* src_uv;
48   const int abs_src_height = (src_height < 0) ? -src_height : src_height;
49   // TODO(nisse): Why allow crop_height < 0?
50   const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
51   int r = 0;
52   LIBYUV_BOOL need_buf =
53       (rotation && format != FOURCC_I420 && format != FOURCC_NV12 &&
54        format != FOURCC_NV21 && format != FOURCC_YV12) ||
55       y == sample;
56   uint8* tmp_y = y;
57   uint8* tmp_u = u;
58   uint8* tmp_v = v;
59   int tmp_y_stride = y_stride;
60   int tmp_u_stride = u_stride;
61   int tmp_v_stride = v_stride;
62   uint8* rotate_buffer = NULL;
63   const int inv_crop_height =
64       (src_height < 0) ? -abs_crop_height : abs_crop_height;
65 
66   if (!y || !u || !v || !sample || src_width <= 0 || crop_width <= 0 ||
67       src_height == 0 || crop_height == 0) {
68     return -1;
69   }
70 
71   // One pass rotation is available for some formats. For the rest, convert
72   // to I420 (with optional vertical flipping) into a temporary I420 buffer,
73   // and then rotate the I420 to the final destination buffer.
74   // For in-place conversion, if destination y is same as source sample,
75   // also enable temporary buffer.
76   if (need_buf) {
77     int y_size = crop_width * abs_crop_height;
78     int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
79     rotate_buffer = (uint8*)malloc(y_size + uv_size * 2); /* NOLINT */
80     if (!rotate_buffer) {
81       return 1;  // Out of memory runtime error.
82     }
83     y = rotate_buffer;
84     u = y + y_size;
85     v = u + uv_size;
86     y_stride = crop_width;
87     u_stride = v_stride = ((crop_width + 1) / 2);
88   }
89 
90   switch (format) {
91     // Single plane formats
92     case FOURCC_YUY2:
93       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
94       r = YUY2ToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
95                      v_stride, crop_width, inv_crop_height);
96       break;
97     case FOURCC_UYVY:
98       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
99       r = UYVYToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
100                      v_stride, 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, y, y_stride, u, u_stride, v,
105                        v_stride, crop_width, inv_crop_height);
106       break;
107     case FOURCC_RGBO:
108       src = sample + (src_width * crop_y + crop_x) * 2;
109       r = ARGB1555ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
110                          v_stride, crop_width, inv_crop_height);
111       break;
112     case FOURCC_R444:
113       src = sample + (src_width * crop_y + crop_x) * 2;
114       r = ARGB4444ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
115                          v_stride, crop_width, inv_crop_height);
116       break;
117     case FOURCC_24BG:
118       src = sample + (src_width * crop_y + crop_x) * 3;
119       r = RGB24ToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
120                       crop_width, inv_crop_height);
121       break;
122     case FOURCC_RAW:
123       src = sample + (src_width * crop_y + crop_x) * 3;
124       r = RAWToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
125                     crop_width, inv_crop_height);
126       break;
127     case FOURCC_ARGB:
128       src = sample + (src_width * crop_y + crop_x) * 4;
129       r = ARGBToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
130                      crop_width, inv_crop_height);
131       break;
132     case FOURCC_BGRA:
133       src = sample + (src_width * crop_y + crop_x) * 4;
134       r = BGRAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
135                      crop_width, inv_crop_height);
136       break;
137     case FOURCC_ABGR:
138       src = sample + (src_width * crop_y + crop_x) * 4;
139       r = ABGRToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
140                      crop_width, inv_crop_height);
141       break;
142     case FOURCC_RGBA:
143       src = sample + (src_width * crop_y + crop_x) * 4;
144       r = RGBAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
145                      crop_width, inv_crop_height);
146       break;
147     case FOURCC_I400:
148       src = sample + src_width * crop_y + crop_x;
149       r = I400ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride,
150                      crop_width, inv_crop_height);
151       break;
152     // Biplanar formats
153     case FOURCC_NV12:
154       src = sample + (src_width * crop_y + crop_x);
155       src_uv = sample + (src_width * src_height) +
156                ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
157       r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y,
158                            y_stride, u, u_stride, v, v_stride, crop_width,
159                            inv_crop_height, rotation);
160       break;
161     case FOURCC_NV21:
162       src = sample + (src_width * crop_y + crop_x);
163       src_uv = sample + (src_width * src_height) +
164                ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
165       // Call NV12 but with u and v parameters swapped.
166       r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y,
167                            y_stride, v, v_stride, u, u_stride, crop_width,
168                            inv_crop_height, rotation);
169       break;
170     case FOURCC_M420:
171       src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
172       r = M420ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride,
173                      crop_width, inv_crop_height);
174       break;
175     // Triplanar formats
176     case FOURCC_I420:
177     case FOURCC_YV12: {
178       const uint8* src_y = sample + (src_width * crop_y + crop_x);
179       const uint8* src_u;
180       const uint8* src_v;
181       int halfwidth = (src_width + 1) / 2;
182       int halfheight = (abs_src_height + 1) / 2;
183       if (format == FOURCC_YV12) {
184         src_v = sample + src_width * abs_src_height +
185                 (halfwidth * crop_y + crop_x) / 2;
186         src_u = sample + src_width * abs_src_height +
187                 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
188       } else {
189         src_u = sample + src_width * abs_src_height +
190                 (halfwidth * crop_y + crop_x) / 2;
191         src_v = sample + src_width * abs_src_height +
192                 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
193       }
194       r = I420Rotate(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y,
195                      y_stride, u, u_stride, v, v_stride, crop_width,
196                      inv_crop_height, rotation);
197       break;
198     }
199     case FOURCC_I422:
200     case FOURCC_YV16: {
201       const uint8* src_y = sample + src_width * crop_y + crop_x;
202       const uint8* src_u;
203       const uint8* src_v;
204       int halfwidth = (src_width + 1) / 2;
205       if (format == FOURCC_YV16) {
206         src_v = sample + src_width * abs_src_height + halfwidth * crop_y +
207                 crop_x / 2;
208         src_u = sample + src_width * abs_src_height +
209                 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
210       } else {
211         src_u = sample + src_width * abs_src_height + halfwidth * crop_y +
212                 crop_x / 2;
213         src_v = sample + src_width * abs_src_height +
214                 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
215       }
216       r = I422ToI420(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y,
217                      y_stride, u, u_stride, v, v_stride, crop_width,
218                      inv_crop_height);
219       break;
220     }
221     case FOURCC_I444:
222     case FOURCC_YV24: {
223       const uint8* src_y = sample + src_width * crop_y + crop_x;
224       const uint8* src_u;
225       const uint8* src_v;
226       if (format == FOURCC_YV24) {
227         src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
228         src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
229       } else {
230         src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
231         src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
232       }
233       r = I444ToI420(src_y, src_width, src_u, src_width, src_v, src_width, y,
234                      y_stride, u, u_stride, v, v_stride, crop_width,
235                      inv_crop_height);
236       break;
237     }
238 #ifdef HAVE_JPEG
239     case FOURCC_MJPG:
240       r = MJPGToI420(sample, sample_size, y, y_stride, u, u_stride, v, v_stride,
241                      src_width, abs_src_height, crop_width, inv_crop_height);
242       break;
243 #endif
244     default:
245       r = -1;  // unknown fourcc - return failure code.
246   }
247 
248   if (need_buf) {
249     if (!r) {
250       r = I420Rotate(y, y_stride, u, u_stride, v, v_stride, tmp_y, tmp_y_stride,
251                      tmp_u, tmp_u_stride, tmp_v, tmp_v_stride, crop_width,
252                      abs_crop_height, rotation);
253     }
254     free(rotate_buffer);
255   }
256 
257   return r;
258 }
259 
260 #ifdef __cplusplus
261 }  // extern "C"
262 }  // namespace libyuv
263 #endif
264