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, 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 }
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 }
298
299 return r;
300 }
301
302 #ifdef __cplusplus
303 } // extern "C"
304 } // namespace libyuv
305 #endif
306