1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qvideoframeconversionhelper_p.h" |
41 | |
42 | QT_BEGIN_NAMESPACE |
43 | |
44 | #define CLAMP(n) (n > 255 ? 255 : (n < 0 ? 0 : n)) |
45 | |
46 | #define EXPAND_UV(u, v) \ |
47 | int uu = u - 128; \ |
48 | int vv = v - 128; \ |
49 | int rv = 409 * vv + 128; \ |
50 | int guv = 100 * uu + 208 * vv + 128; \ |
51 | int bu = 516 * uu + 128; \ |
52 | |
53 | static inline quint32 qYUVToARGB32(int y, int rv, int guv, int bu, int a = 0xff) |
54 | { |
55 | int yy = (y - 16) * 298; |
56 | return (a << 24) |
57 | | CLAMP((yy + rv) >> 8) << 16 |
58 | | CLAMP((yy - guv) >> 8) << 8 |
59 | | CLAMP((yy + bu) >> 8); |
60 | } |
61 | |
62 | static inline void planarYUV420_to_ARGB32(const uchar *y, int yStride, |
63 | const uchar *u, int uStride, |
64 | const uchar *v, int vStride, |
65 | int uvPixelStride, |
66 | quint32 *rgb, |
67 | int width, int height) |
68 | { |
69 | quint32 *rgb0 = rgb; |
70 | quint32 *rgb1 = rgb + width; |
71 | |
72 | for (int j = 0; j < height; j += 2) { |
73 | const uchar *lineY0 = y; |
74 | const uchar *lineY1 = y + yStride; |
75 | const uchar *lineU = u; |
76 | const uchar *lineV = v; |
77 | |
78 | for (int i = 0; i < width; i += 2) { |
79 | EXPAND_UV(*lineU, *lineV); |
80 | lineU += uvPixelStride; |
81 | lineV += uvPixelStride; |
82 | |
83 | *rgb0++ = qYUVToARGB32(y: *lineY0++, rv, guv, bu); |
84 | *rgb0++ = qYUVToARGB32(y: *lineY0++, rv, guv, bu); |
85 | *rgb1++ = qYUVToARGB32(y: *lineY1++, rv, guv, bu); |
86 | *rgb1++ = qYUVToARGB32(y: *lineY1++, rv, guv, bu); |
87 | } |
88 | |
89 | y += yStride << 1; // stride * 2 |
90 | u += uStride; |
91 | v += vStride; |
92 | rgb0 += width; |
93 | rgb1 += width; |
94 | } |
95 | } |
96 | |
97 | |
98 | |
99 | void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output) |
100 | { |
101 | FETCH_INFO_TRIPLANAR(frame) |
102 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
103 | u: plane2, uStride: plane2Stride, |
104 | v: plane3, vStride: plane3Stride, |
105 | uvPixelStride: 1, |
106 | rgb: reinterpret_cast<quint32*>(output), |
107 | width, height); |
108 | } |
109 | |
110 | void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output) |
111 | { |
112 | FETCH_INFO_TRIPLANAR(frame) |
113 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
114 | u: plane3, uStride: plane3Stride, |
115 | v: plane2, vStride: plane2Stride, |
116 | uvPixelStride: 1, |
117 | rgb: reinterpret_cast<quint32*>(output), |
118 | width, height); |
119 | } |
120 | |
121 | void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) |
122 | { |
123 | FETCH_INFO_PACKED(frame) |
124 | MERGE_LOOPS(width, height, stride, 4) |
125 | |
126 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
127 | |
128 | for (int i = 0; i < height; ++i) { |
129 | const uchar *lineSrc = src; |
130 | |
131 | for (int j = 0; j < width; ++j) { |
132 | int a = *lineSrc++; |
133 | int y = *lineSrc++; |
134 | int u = *lineSrc++; |
135 | int v = *lineSrc++; |
136 | |
137 | EXPAND_UV(u, v); |
138 | |
139 | *rgb++ = qYUVToARGB32(y, rv, guv, bu, a); |
140 | } |
141 | |
142 | src += stride; |
143 | } |
144 | } |
145 | |
146 | void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) |
147 | { |
148 | FETCH_INFO_PACKED(frame) |
149 | MERGE_LOOPS(width, height, stride, 3) |
150 | |
151 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
152 | |
153 | for (int i = 0; i < height; ++i) { |
154 | const uchar *lineSrc = src; |
155 | |
156 | for (int j = 0; j < width; ++j) { |
157 | int y = *lineSrc++; |
158 | int u = *lineSrc++; |
159 | int v = *lineSrc++; |
160 | |
161 | EXPAND_UV(u, v); |
162 | |
163 | *rgb++ = qYUVToARGB32(y, rv, guv, bu); |
164 | } |
165 | |
166 | src += stride; |
167 | } |
168 | } |
169 | |
170 | void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output) |
171 | { |
172 | FETCH_INFO_PACKED(frame) |
173 | MERGE_LOOPS(width, height, stride, 2) |
174 | |
175 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
176 | |
177 | for (int i = 0; i < height; ++i) { |
178 | const uchar *lineSrc = src; |
179 | |
180 | for (int j = 0; j < width; j += 2) { |
181 | int u = *lineSrc++; |
182 | int y0 = *lineSrc++; |
183 | int v = *lineSrc++; |
184 | int y1 = *lineSrc++; |
185 | |
186 | EXPAND_UV(u, v); |
187 | |
188 | *rgb++ = qYUVToARGB32(y: y0, rv, guv, bu); |
189 | *rgb++ = qYUVToARGB32(y: y1, rv, guv, bu); |
190 | } |
191 | |
192 | src += stride; |
193 | } |
194 | } |
195 | |
196 | void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output) |
197 | { |
198 | FETCH_INFO_PACKED(frame) |
199 | MERGE_LOOPS(width, height, stride, 2) |
200 | |
201 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
202 | |
203 | for (int i = 0; i < height; ++i) { |
204 | const uchar *lineSrc = src; |
205 | |
206 | for (int j = 0; j < width; j += 2) { |
207 | int y0 = *lineSrc++; |
208 | int u = *lineSrc++; |
209 | int y1 = *lineSrc++; |
210 | int v = *lineSrc++; |
211 | |
212 | EXPAND_UV(u, v); |
213 | |
214 | *rgb++ = qYUVToARGB32(y: y0, rv, guv, bu); |
215 | *rgb++ = qYUVToARGB32(y: y1, rv, guv, bu); |
216 | } |
217 | |
218 | src += stride; |
219 | } |
220 | } |
221 | |
222 | void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output) |
223 | { |
224 | FETCH_INFO_BIPLANAR(frame) |
225 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
226 | u: plane2, uStride: plane2Stride, |
227 | v: plane2 + 1, vStride: plane2Stride, |
228 | uvPixelStride: 2, |
229 | rgb: reinterpret_cast<quint32*>(output), |
230 | width, height); |
231 | } |
232 | |
233 | void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output) |
234 | { |
235 | FETCH_INFO_BIPLANAR(frame) |
236 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
237 | u: plane2 + 1, uStride: plane2Stride, |
238 | v: plane2, vStride: plane2Stride, |
239 | uvPixelStride: 2, |
240 | rgb: reinterpret_cast<quint32*>(output), |
241 | width, height); |
242 | } |
243 | |
244 | void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *output) |
245 | { |
246 | FETCH_INFO_PACKED(frame) |
247 | MERGE_LOOPS(width, height, stride, 4) |
248 | |
249 | quint32 *argb = reinterpret_cast<quint32*>(output); |
250 | |
251 | for (int y = 0; y < height; ++y) { |
252 | const quint32 *bgra = reinterpret_cast<const quint32*>(src); |
253 | |
254 | int x = 0; |
255 | for (; x < width - 3; x += 4) { |
256 | *argb++ = qConvertBGRA32ToARGB32(bgra: *bgra++); |
257 | *argb++ = qConvertBGRA32ToARGB32(bgra: *bgra++); |
258 | *argb++ = qConvertBGRA32ToARGB32(bgra: *bgra++); |
259 | *argb++ = qConvertBGRA32ToARGB32(bgra: *bgra++); |
260 | } |
261 | |
262 | // leftovers |
263 | for (; x < width; ++x) |
264 | *argb++ = qConvertBGRA32ToARGB32(bgra: *bgra++); |
265 | |
266 | src += stride; |
267 | } |
268 | } |
269 | |
270 | void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame &frame, uchar *output) |
271 | { |
272 | FETCH_INFO_PACKED(frame) |
273 | MERGE_LOOPS(width, height, stride, 3) |
274 | |
275 | quint32 *argb = reinterpret_cast<quint32*>(output); |
276 | |
277 | for (int y = 0; y < height; ++y) { |
278 | const uchar *bgr = src; |
279 | |
280 | int x = 0; |
281 | for (; x < width - 3; x += 4) { |
282 | *argb++ = qConvertBGR24ToARGB32(bgr); |
283 | bgr += 3; |
284 | *argb++ = qConvertBGR24ToARGB32(bgr); |
285 | bgr += 3; |
286 | *argb++ = qConvertBGR24ToARGB32(bgr); |
287 | bgr += 3; |
288 | *argb++ = qConvertBGR24ToARGB32(bgr); |
289 | bgr += 3; |
290 | } |
291 | |
292 | // leftovers |
293 | for (; x < width; ++x) { |
294 | *argb++ = qConvertBGR24ToARGB32(bgr); |
295 | bgr += 3; |
296 | } |
297 | |
298 | src += stride; |
299 | } |
300 | } |
301 | |
302 | void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *output) |
303 | { |
304 | FETCH_INFO_PACKED(frame) |
305 | MERGE_LOOPS(width, height, stride, 2) |
306 | |
307 | quint32 *argb = reinterpret_cast<quint32*>(output); |
308 | |
309 | for (int y = 0; y < height; ++y) { |
310 | const quint16 *bgr = reinterpret_cast<const quint16*>(src); |
311 | |
312 | int x = 0; |
313 | for (; x < width - 3; x += 4) { |
314 | *argb++ = qConvertBGR565ToARGB32(bgr: *bgr++); |
315 | *argb++ = qConvertBGR565ToARGB32(bgr: *bgr++); |
316 | *argb++ = qConvertBGR565ToARGB32(bgr: *bgr++); |
317 | *argb++ = qConvertBGR565ToARGB32(bgr: *bgr++); |
318 | } |
319 | |
320 | // leftovers |
321 | for (; x < width; ++x) |
322 | *argb++ = qConvertBGR565ToARGB32(bgr: *bgr++); |
323 | |
324 | src += stride; |
325 | } |
326 | } |
327 | |
328 | void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *output) |
329 | { |
330 | FETCH_INFO_PACKED(frame) |
331 | MERGE_LOOPS(width, height, stride, 2) |
332 | |
333 | quint32 *argb = reinterpret_cast<quint32*>(output); |
334 | |
335 | for (int y = 0; y < height; ++y) { |
336 | const quint16 *bgr = reinterpret_cast<const quint16*>(src); |
337 | |
338 | int x = 0; |
339 | for (; x < width - 3; x += 4) { |
340 | *argb++ = qConvertBGR555ToARGB32(bgr: *bgr++); |
341 | *argb++ = qConvertBGR555ToARGB32(bgr: *bgr++); |
342 | *argb++ = qConvertBGR555ToARGB32(bgr: *bgr++); |
343 | *argb++ = qConvertBGR555ToARGB32(bgr: *bgr++); |
344 | } |
345 | |
346 | // leftovers |
347 | for (; x < width; ++x) |
348 | *argb++ = qConvertBGR555ToARGB32(bgr: *bgr++); |
349 | |
350 | src += stride; |
351 | } |
352 | } |
353 | |
354 | QT_END_NAMESPACE |
355 | |