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