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