Line data Source code
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
28 0 : 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 0 : uint32 format = CanonicalFourCC(fourcc);
45 0 : int aligned_src_width = (src_width + 1) & ~1;
46 : const uint8* src;
47 : const uint8* src_uv;
48 0 : const int abs_src_height = (src_height < 0) ? -src_height : src_height;
49 : // TODO(nisse): Why allow crop_height < 0?
50 0 : const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
51 0 : int r = 0;
52 : LIBYUV_BOOL need_buf =
53 0 : (rotation && format != FOURCC_I420 && format != FOURCC_NV12 &&
54 0 : format != FOURCC_NV21 && format != FOURCC_YV12) ||
55 0 : y == sample;
56 0 : uint8* tmp_y = y;
57 0 : uint8* tmp_u = u;
58 0 : uint8* tmp_v = v;
59 0 : int tmp_y_stride = y_stride;
60 0 : int tmp_u_stride = u_stride;
61 0 : int tmp_v_stride = v_stride;
62 0 : uint8* rotate_buffer = NULL;
63 : const int inv_crop_height =
64 0 : (src_height < 0) ? -abs_crop_height : abs_crop_height;
65 :
66 0 : if (!y || !u || !v || !sample || src_width <= 0 || crop_width <= 0 ||
67 0 : src_height == 0 || crop_height == 0) {
68 0 : 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 0 : if (need_buf) {
77 0 : int y_size = crop_width * abs_crop_height;
78 0 : int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
79 0 : rotate_buffer = (uint8*)malloc(y_size + uv_size * 2); /* NOLINT */
80 0 : if (!rotate_buffer) {
81 0 : return 1; // Out of memory runtime error.
82 : }
83 0 : y = rotate_buffer;
84 0 : u = y + y_size;
85 0 : v = u + uv_size;
86 0 : y_stride = crop_width;
87 0 : u_stride = v_stride = ((crop_width + 1) / 2);
88 : }
89 :
90 0 : switch (format) {
91 : // Single plane formats
92 : case FOURCC_YUY2:
93 0 : src = sample + (aligned_src_width * crop_y + crop_x) * 2;
94 0 : r = YUY2ToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
95 0 : v_stride, crop_width, inv_crop_height);
96 0 : break;
97 : case FOURCC_UYVY:
98 0 : src = sample + (aligned_src_width * crop_y + crop_x) * 2;
99 0 : r = UYVYToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
100 0 : v_stride, crop_width, inv_crop_height);
101 0 : break;
102 : case FOURCC_RGBP:
103 0 : src = sample + (src_width * crop_y + crop_x) * 2;
104 0 : r = RGB565ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
105 0 : v_stride, crop_width, inv_crop_height);
106 0 : break;
107 : case FOURCC_RGBO:
108 0 : src = sample + (src_width * crop_y + crop_x) * 2;
109 0 : r = ARGB1555ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
110 0 : v_stride, crop_width, inv_crop_height);
111 0 : break;
112 : case FOURCC_R444:
113 0 : src = sample + (src_width * crop_y + crop_x) * 2;
114 0 : r = ARGB4444ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
115 0 : v_stride, crop_width, inv_crop_height);
116 0 : break;
117 : case FOURCC_24BG:
118 0 : src = sample + (src_width * crop_y + crop_x) * 3;
119 0 : r = RGB24ToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
120 0 : crop_width, inv_crop_height);
121 0 : break;
122 : case FOURCC_RAW:
123 0 : src = sample + (src_width * crop_y + crop_x) * 3;
124 0 : r = RAWToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
125 0 : crop_width, inv_crop_height);
126 0 : break;
127 : case FOURCC_ARGB:
128 0 : src = sample + (src_width * crop_y + crop_x) * 4;
129 0 : r = ARGBToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
130 0 : crop_width, inv_crop_height);
131 0 : break;
132 : case FOURCC_BGRA:
133 0 : src = sample + (src_width * crop_y + crop_x) * 4;
134 0 : r = BGRAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
135 0 : crop_width, inv_crop_height);
136 0 : break;
137 : case FOURCC_ABGR:
138 0 : src = sample + (src_width * crop_y + crop_x) * 4;
139 0 : r = ABGRToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
140 0 : crop_width, inv_crop_height);
141 0 : break;
142 : case FOURCC_RGBA:
143 0 : src = sample + (src_width * crop_y + crop_x) * 4;
144 0 : r = RGBAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
145 0 : crop_width, inv_crop_height);
146 0 : break;
147 : case FOURCC_I400:
148 0 : src = sample + src_width * crop_y + crop_x;
149 : r = I400ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride,
150 0 : crop_width, inv_crop_height);
151 0 : break;
152 : // Biplanar formats
153 : case FOURCC_NV12:
154 0 : src = sample + (src_width * crop_y + crop_x);
155 0 : src_uv = sample + (src_width * src_height) +
156 0 : ((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 0 : inv_crop_height, rotation);
160 0 : break;
161 : case FOURCC_NV21:
162 0 : src = sample + (src_width * crop_y + crop_x);
163 0 : src_uv = sample + (src_width * src_height) +
164 0 : ((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 0 : inv_crop_height, rotation);
169 0 : break;
170 : case FOURCC_M420:
171 0 : 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 0 : crop_width, inv_crop_height);
174 0 : break;
175 : // Triplanar formats
176 : case FOURCC_I420:
177 : case FOURCC_YV12: {
178 0 : const uint8* src_y = sample + (src_width * crop_y + crop_x);
179 : const uint8* src_u;
180 : const uint8* src_v;
181 0 : int halfwidth = (src_width + 1) / 2;
182 0 : int halfheight = (abs_src_height + 1) / 2;
183 0 : if (format == FOURCC_YV12) {
184 0 : src_v = sample + src_width * abs_src_height +
185 0 : (halfwidth * crop_y + crop_x) / 2;
186 0 : src_u = sample + src_width * abs_src_height +
187 0 : halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
188 : } else {
189 0 : src_u = sample + src_width * abs_src_height +
190 0 : (halfwidth * crop_y + crop_x) / 2;
191 0 : src_v = sample + src_width * abs_src_height +
192 0 : 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 0 : inv_crop_height, rotation);
197 0 : break;
198 : }
199 : case FOURCC_I422:
200 : case FOURCC_YV16: {
201 0 : const uint8* src_y = sample + src_width * crop_y + crop_x;
202 : const uint8* src_u;
203 : const uint8* src_v;
204 0 : int halfwidth = (src_width + 1) / 2;
205 0 : if (format == FOURCC_YV16) {
206 0 : src_v = sample + src_width * abs_src_height + halfwidth * crop_y +
207 0 : crop_x / 2;
208 0 : src_u = sample + src_width * abs_src_height +
209 0 : halfwidth * (abs_src_height + crop_y) + crop_x / 2;
210 : } else {
211 0 : src_u = sample + src_width * abs_src_height + halfwidth * crop_y +
212 0 : crop_x / 2;
213 0 : src_v = sample + src_width * abs_src_height +
214 0 : 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 0 : inv_crop_height);
219 0 : break;
220 : }
221 : case FOURCC_I444:
222 : case FOURCC_YV24: {
223 0 : const uint8* src_y = sample + src_width * crop_y + crop_x;
224 : const uint8* src_u;
225 : const uint8* src_v;
226 0 : if (format == FOURCC_YV24) {
227 0 : src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
228 0 : src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
229 : } else {
230 0 : src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
231 0 : 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 0 : inv_crop_height);
236 0 : 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 0 : src_width, abs_src_height, crop_width, inv_crop_height);
242 0 : break;
243 : #endif
244 : default:
245 0 : r = -1; // unknown fourcc - return failure code.
246 : }
247 :
248 0 : if (need_buf) {
249 0 : 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 0 : abs_crop_height, rotation);
253 : }
254 0 : free(rotate_buffer);
255 : }
256 :
257 0 : return r;
258 : }
259 :
260 : #ifdef __cplusplus
261 : } // extern "C"
262 : } // namespace libyuv
263 : #endif
|