• 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 #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
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)32 int ConvertToARGB(const uint8* sample,
33                   size_t sample_size,
34                   uint8* crop_argb,
35                   int argb_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   int abs_src_height = (src_height < 0) ? -src_height : src_height;
49   int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
50   int r = 0;
51 
52   // One pass rotation is available for some formats. For the rest, convert
53   // to ARGB (with optional vertical flipping) into a temporary ARGB buffer,
54   // and then rotate the ARGB to the final destination buffer.
55   // For in-place conversion, if destination crop_argb is same as source sample,
56   // also enable temporary buffer.
57   LIBYUV_BOOL need_buf =
58       (rotation && format != FOURCC_ARGB) || crop_argb == sample;
59   uint8* dest_argb = crop_argb;
60   int dest_argb_stride = argb_stride;
61   uint8* rotate_buffer = NULL;
62   int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
63 
64   if (crop_argb == NULL || sample == NULL || src_width <= 0 ||
65       crop_width <= 0 || src_height == 0 || crop_height == 0) {
66     return -1;
67   }
68   if (src_height < 0) {
69     inv_crop_height = -inv_crop_height;
70   }
71 
72   if (need_buf) {
73     int argb_size = crop_width * 4 * abs_crop_height;
74     rotate_buffer = (uint8*)malloc(argb_size); /* NOLINT */
75     if (!rotate_buffer) {
76       return 1;  // Out of memory runtime error.
77     }
78     crop_argb = rotate_buffer;
79     argb_stride = crop_width * 4;
80   }
81 
82   switch (format) {
83     // Single plane formats
84     case FOURCC_YUY2:
85       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
86       r = YUY2ToARGB(src, aligned_src_width * 2, crop_argb, argb_stride,
87                      crop_width, inv_crop_height);
88       break;
89     case FOURCC_UYVY:
90       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
91       r = UYVYToARGB(src, aligned_src_width * 2, crop_argb, argb_stride,
92                      crop_width, inv_crop_height);
93       break;
94     case FOURCC_24BG:
95       src = sample + (src_width * crop_y + crop_x) * 3;
96       r = RGB24ToARGB(src, src_width * 3, crop_argb, argb_stride, crop_width,
97                       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, crop_argb, argb_stride, crop_width,
102                     inv_crop_height);
103       break;
104     case FOURCC_ARGB:
105       if (!need_buf && !rotation) {
106         src = sample + (src_width * crop_y + crop_x) * 4;
107         r = ARGBToARGB(src, src_width * 4, crop_argb, argb_stride, crop_width,
108                        inv_crop_height);
109       }
110       break;
111     case FOURCC_BGRA:
112       src = sample + (src_width * crop_y + crop_x) * 4;
113       r = BGRAToARGB(src, src_width * 4, crop_argb, argb_stride, crop_width,
114                      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, crop_argb, argb_stride, crop_width,
119                      inv_crop_height);
120       break;
121     case FOURCC_RGBA:
122       src = sample + (src_width * crop_y + crop_x) * 4;
123       r = RGBAToARGB(src, src_width * 4, crop_argb, argb_stride, crop_width,
124                      inv_crop_height);
125       break;
126     case FOURCC_RGBP:
127       src = sample + (src_width * crop_y + crop_x) * 2;
128       r = RGB565ToARGB(src, src_width * 2, crop_argb, argb_stride, crop_width,
129                        inv_crop_height);
130       break;
131     case FOURCC_RGBO:
132       src = sample + (src_width * crop_y + crop_x) * 2;
133       r = ARGB1555ToARGB(src, src_width * 2, crop_argb, argb_stride, crop_width,
134                          inv_crop_height);
135       break;
136     case FOURCC_R444:
137       src = sample + (src_width * crop_y + crop_x) * 2;
138       r = ARGB4444ToARGB(src, src_width * 2, crop_argb, argb_stride, crop_width,
139                          inv_crop_height);
140       break;
141     case FOURCC_I400:
142       src = sample + src_width * crop_y + crop_x;
143       r = I400ToARGB(src, src_width, crop_argb, argb_stride, crop_width,
144                      inv_crop_height);
145       break;
146 
147     // Biplanar formats
148     case FOURCC_NV12:
149       src = sample + (src_width * crop_y + crop_x);
150       src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
151       r = NV12ToARGB(src, src_width, src_uv, aligned_src_width, crop_argb,
152                      argb_stride, crop_width, inv_crop_height);
153       break;
154     case FOURCC_NV21:
155       src = sample + (src_width * crop_y + crop_x);
156       src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
157       // Call NV12 but with u and v parameters swapped.
158       r = NV21ToARGB(src, src_width, src_uv, aligned_src_width, crop_argb,
159                      argb_stride, crop_width, inv_crop_height);
160       break;
161     case FOURCC_M420:
162       src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
163       r = M420ToARGB(src, src_width, crop_argb, argb_stride, crop_width,
164                      inv_crop_height);
165       break;
166     // Triplanar formats
167     case FOURCC_I420:
168     case FOURCC_YV12: {
169       const uint8* src_y = sample + (src_width * crop_y + crop_x);
170       const uint8* src_u;
171       const uint8* src_v;
172       int halfwidth = (src_width + 1) / 2;
173       int halfheight = (abs_src_height + 1) / 2;
174       if (format == FOURCC_YV12) {
175         src_v = sample + src_width * abs_src_height +
176                 (halfwidth * crop_y + crop_x) / 2;
177         src_u = sample + src_width * abs_src_height +
178                 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
179       } else {
180         src_u = sample + src_width * abs_src_height +
181                 (halfwidth * crop_y + crop_x) / 2;
182         src_v = sample + src_width * abs_src_height +
183                 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
184       }
185       r = I420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
186                      crop_argb, argb_stride, crop_width, inv_crop_height);
187       break;
188     }
189 
190     case FOURCC_J420: {
191       const uint8* src_y = sample + (src_width * crop_y + crop_x);
192       const uint8* src_u;
193       const uint8* src_v;
194       int halfwidth = (src_width + 1) / 2;
195       int halfheight = (abs_src_height + 1) / 2;
196       src_u = sample + src_width * abs_src_height +
197               (halfwidth * crop_y + crop_x) / 2;
198       src_v = sample + src_width * abs_src_height +
199               halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
200       r = J420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
201                      crop_argb, argb_stride, crop_width, inv_crop_height);
202       break;
203     }
204 
205     case FOURCC_I422:
206     case FOURCC_YV16: {
207       const uint8* src_y = sample + src_width * crop_y + crop_x;
208       const uint8* src_u;
209       const uint8* src_v;
210       int halfwidth = (src_width + 1) / 2;
211       if (format == FOURCC_YV16) {
212         src_v = sample + src_width * abs_src_height + halfwidth * crop_y +
213                 crop_x / 2;
214         src_u = sample + src_width * abs_src_height +
215                 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
216       } else {
217         src_u = sample + src_width * abs_src_height + halfwidth * crop_y +
218                 crop_x / 2;
219         src_v = sample + src_width * abs_src_height +
220                 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
221       }
222       r = I422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
223                      crop_argb, argb_stride, crop_width, inv_crop_height);
224       break;
225     }
226     case FOURCC_I444:
227     case FOURCC_YV24: {
228       const uint8* src_y = sample + src_width * crop_y + crop_x;
229       const uint8* src_u;
230       const uint8* src_v;
231       if (format == FOURCC_YV24) {
232         src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
233         src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
234       } else {
235         src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
236         src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
237       }
238       r = I444ToARGB(src_y, src_width, src_u, src_width, src_v, src_width,
239                      crop_argb, argb_stride, crop_width, inv_crop_height);
240       break;
241     }
242 #ifdef HAVE_JPEG
243     case FOURCC_MJPG:
244       r = MJPGToARGB(sample, sample_size, crop_argb, argb_stride, src_width,
245                      abs_src_height, crop_width, inv_crop_height);
246       break;
247 #endif
248     default:
249       r = -1;  // unknown fourcc - return failure code.
250   }
251 
252   if (need_buf) {
253     if (!r) {
254       r = ARGBRotate(crop_argb, argb_stride, dest_argb, dest_argb_stride,
255                      crop_width, abs_crop_height, rotation);
256     }
257     free(rotate_buffer);
258   } else if (rotation) {
259     src = sample + (src_width * crop_y + crop_x) * 4;
260     r = ARGBRotate(src, src_width * 4, crop_argb, argb_stride, crop_width,
261                    inv_crop_height, rotation);
262   }
263 
264   return r;
265 }
266 
267 #ifdef __cplusplus
268 }  // extern "C"
269 }  // namespace libyuv
270 #endif
271