|
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 |
|
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 |