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 <stdlib.h>
12
13 #include "libyuv/convert.h"
14
15 #include "libyuv/video_common.h"
16
17 #ifdef __cplusplus
18 namespace libyuv {
19 extern "C" {
20 #endif
21
22 // Convert camera sample to I420 with cropping, rotation and vertical flip.
23 // src_width is used for source stride computation
24 // src_height is used to compute location of planes, and indicate inversion
25 // sample_size is measured in bytes and is the size of the frame.
26 // With MJPEG it is the compressed size of the frame.
27 LIBYUV_API
ConvertToI420(const uint8 * sample,size_t sample_size,uint8 * y,int y_stride,uint8 * u,int u_stride,uint8 * v,int v_stride,int crop_x,int crop_y,int src_width,int src_height,int crop_width,int crop_height,enum RotationMode rotation,uint32 fourcc)28 int ConvertToI420(const uint8* sample,
29 size_t sample_size,
30 uint8* y,
31 int y_stride,
32 uint8* u,
33 int u_stride,
34 uint8* v,
35 int v_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 const int abs_src_height = (src_height < 0) ? -src_height : src_height;
49 // TODO(nisse): Why allow crop_height < 0?
50 const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
51 int r = 0;
52 LIBYUV_BOOL need_buf =
53 (rotation && format != FOURCC_I420 && format != FOURCC_NV12 &&
54 format != FOURCC_NV21 && format != FOURCC_YV12) ||
55 y == sample;
56 uint8* tmp_y = y;
57 uint8* tmp_u = u;
58 uint8* tmp_v = v;
59 int tmp_y_stride = y_stride;
60 int tmp_u_stride = u_stride;
61 int tmp_v_stride = v_stride;
62 uint8* rotate_buffer = NULL;
63 const int inv_crop_height =
64 (src_height < 0) ? -abs_crop_height : abs_crop_height;
65
66 if (!y || !u || !v || !sample || src_width <= 0 || crop_width <= 0 ||
67 src_height == 0 || crop_height == 0) {
68 return -1;
69 }
70
71 // One pass rotation is available for some formats. For the rest, convert
72 // to I420 (with optional vertical flipping) into a temporary I420 buffer,
73 // and then rotate the I420 to the final destination buffer.
74 // For in-place conversion, if destination y is same as source sample,
75 // also enable temporary buffer.
76 if (need_buf) {
77 int y_size = crop_width * abs_crop_height;
78 int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
79 rotate_buffer = (uint8*)malloc(y_size + uv_size * 2); /* NOLINT */
80 if (!rotate_buffer) {
81 return 1; // Out of memory runtime error.
82 }
83 y = rotate_buffer;
84 u = y + y_size;
85 v = u + uv_size;
86 y_stride = crop_width;
87 u_stride = v_stride = ((crop_width + 1) / 2);
88 }
89
90 switch (format) {
91 // Single plane formats
92 case FOURCC_YUY2:
93 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
94 r = YUY2ToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
95 v_stride, crop_width, inv_crop_height);
96 break;
97 case FOURCC_UYVY:
98 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
99 r = UYVYToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
100 v_stride, crop_width, inv_crop_height);
101 break;
102 case FOURCC_RGBP:
103 src = sample + (src_width * crop_y + crop_x) * 2;
104 r = RGB565ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
105 v_stride, crop_width, inv_crop_height);
106 break;
107 case FOURCC_RGBO:
108 src = sample + (src_width * crop_y + crop_x) * 2;
109 r = ARGB1555ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
110 v_stride, crop_width, inv_crop_height);
111 break;
112 case FOURCC_R444:
113 src = sample + (src_width * crop_y + crop_x) * 2;
114 r = ARGB4444ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
115 v_stride, crop_width, inv_crop_height);
116 break;
117 case FOURCC_24BG:
118 src = sample + (src_width * crop_y + crop_x) * 3;
119 r = RGB24ToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
120 crop_width, inv_crop_height);
121 break;
122 case FOURCC_RAW:
123 src = sample + (src_width * crop_y + crop_x) * 3;
124 r = RAWToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
125 crop_width, inv_crop_height);
126 break;
127 case FOURCC_ARGB:
128 src = sample + (src_width * crop_y + crop_x) * 4;
129 r = ARGBToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
130 crop_width, inv_crop_height);
131 break;
132 case FOURCC_BGRA:
133 src = sample + (src_width * crop_y + crop_x) * 4;
134 r = BGRAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
135 crop_width, inv_crop_height);
136 break;
137 case FOURCC_ABGR:
138 src = sample + (src_width * crop_y + crop_x) * 4;
139 r = ABGRToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
140 crop_width, inv_crop_height);
141 break;
142 case FOURCC_RGBA:
143 src = sample + (src_width * crop_y + crop_x) * 4;
144 r = RGBAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
145 crop_width, inv_crop_height);
146 break;
147 case FOURCC_I400:
148 src = sample + src_width * crop_y + crop_x;
149 r = I400ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride,
150 crop_width, inv_crop_height);
151 break;
152 // Biplanar formats
153 case FOURCC_NV12:
154 src = sample + (src_width * crop_y + crop_x);
155 src_uv = sample + (src_width * src_height) +
156 ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
157 r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y,
158 y_stride, u, u_stride, v, v_stride, crop_width,
159 inv_crop_height, rotation);
160 break;
161 case FOURCC_NV21:
162 src = sample + (src_width * crop_y + crop_x);
163 src_uv = sample + (src_width * src_height) +
164 ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
165 // Call NV12 but with u and v parameters swapped.
166 r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y,
167 y_stride, v, v_stride, u, u_stride, crop_width,
168 inv_crop_height, rotation);
169 break;
170 case FOURCC_M420:
171 src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
172 r = M420ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride,
173 crop_width, inv_crop_height);
174 break;
175 // Triplanar formats
176 case FOURCC_I420:
177 case FOURCC_YV12: {
178 const uint8* src_y = sample + (src_width * crop_y + crop_x);
179 const uint8* src_u;
180 const uint8* src_v;
181 int halfwidth = (src_width + 1) / 2;
182 int halfheight = (abs_src_height + 1) / 2;
183 if (format == FOURCC_YV12) {
184 src_v = sample + src_width * abs_src_height +
185 (halfwidth * crop_y + crop_x) / 2;
186 src_u = sample + src_width * abs_src_height +
187 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
188 } else {
189 src_u = sample + src_width * abs_src_height +
190 (halfwidth * crop_y + crop_x) / 2;
191 src_v = sample + src_width * abs_src_height +
192 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
193 }
194 r = I420Rotate(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y,
195 y_stride, u, u_stride, v, v_stride, crop_width,
196 inv_crop_height, rotation);
197 break;
198 }
199 case FOURCC_I422:
200 case FOURCC_YV16: {
201 const uint8* src_y = sample + src_width * crop_y + crop_x;
202 const uint8* src_u;
203 const uint8* src_v;
204 int halfwidth = (src_width + 1) / 2;
205 if (format == FOURCC_YV16) {
206 src_v = sample + src_width * abs_src_height + halfwidth * crop_y +
207 crop_x / 2;
208 src_u = sample + src_width * abs_src_height +
209 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
210 } else {
211 src_u = sample + src_width * abs_src_height + halfwidth * crop_y +
212 crop_x / 2;
213 src_v = sample + src_width * abs_src_height +
214 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
215 }
216 r = I422ToI420(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y,
217 y_stride, u, u_stride, v, v_stride, crop_width,
218 inv_crop_height);
219 break;
220 }
221 case FOURCC_I444:
222 case FOURCC_YV24: {
223 const uint8* src_y = sample + src_width * crop_y + crop_x;
224 const uint8* src_u;
225 const uint8* src_v;
226 if (format == FOURCC_YV24) {
227 src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
228 src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
229 } else {
230 src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
231 src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
232 }
233 r = I444ToI420(src_y, src_width, src_u, src_width, src_v, src_width, y,
234 y_stride, u, u_stride, v, v_stride, crop_width,
235 inv_crop_height);
236 break;
237 }
238 #ifdef HAVE_JPEG
239 case FOURCC_MJPG:
240 r = MJPGToI420(sample, sample_size, y, y_stride, u, u_stride, v, v_stride,
241 src_width, abs_src_height, crop_width, inv_crop_height);
242 break;
243 #endif
244 default:
245 r = -1; // unknown fourcc - return failure code.
246 }
247
248 if (need_buf) {
249 if (!r) {
250 r = I420Rotate(y, y_stride, u, u_stride, v, v_stride, tmp_y, tmp_y_stride,
251 tmp_u, tmp_u_stride, tmp_v, tmp_v_stride, crop_width,
252 abs_crop_height, rotation);
253 }
254 free(rotate_buffer);
255 }
256
257 return r;
258 }
259
260 #ifdef __cplusplus
261 } // extern "C"
262 } // namespace libyuv
263 #endif
264