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
42QT_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
53static 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
62static 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(*lineY0++, rv, guv, bu);
84 *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
85 *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu);
86 *rgb1++ = qYUVToARGB32(*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
99void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output)
100{
101 FETCH_INFO_TRIPLANAR(frame)
102 planarYUV420_to_ARGB32(plane1, plane1Stride,
103 plane2, plane2Stride,
104 plane3, plane3Stride,
105 1,
106 reinterpret_cast<quint32*>(output),
107 width, height);
108}
109
110void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
111{
112 FETCH_INFO_TRIPLANAR(frame)
113 planarYUV420_to_ARGB32(plane1, plane1Stride,
114 plane3, plane3Stride,
115 plane2, plane2Stride,
116 1,
117 reinterpret_cast<quint32*>(output),
118 width, height);
119}
120
121void 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
146void 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
170void 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(y0, rv, guv, bu);
189 *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
190 }
191
192 src += stride;
193 }
194}
195
196void 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(y0, rv, guv, bu);
215 *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
216 }
217
218 src += stride;
219 }
220}
221
222void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
223{
224 FETCH_INFO_BIPLANAR(frame)
225 planarYUV420_to_ARGB32(plane1, plane1Stride,
226 plane2, plane2Stride,
227 plane2 + 1, plane2Stride,
228 2,
229 reinterpret_cast<quint32*>(output),
230 width, height);
231}
232
233void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output)
234{
235 FETCH_INFO_BIPLANAR(frame)
236 planarYUV420_to_ARGB32(plane1, plane1Stride,
237 plane2 + 1, plane2Stride,
238 plane2, plane2Stride,
239 2,
240 reinterpret_cast<quint32*>(output),
241 width, height);
242}
243
244void 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++);
257 *argb++ = qConvertBGRA32ToARGB32(*bgra++);
258 *argb++ = qConvertBGRA32ToARGB32(*bgra++);
259 *argb++ = qConvertBGRA32ToARGB32(*bgra++);
260 }
261
262 // leftovers
263 for (; x < width; ++x)
264 *argb++ = qConvertBGRA32ToARGB32(*bgra++);
265
266 src += stride;
267 }
268}
269
270void 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
302void 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++);
315 *argb++ = qConvertBGR565ToARGB32(*bgr++);
316 *argb++ = qConvertBGR565ToARGB32(*bgr++);
317 *argb++ = qConvertBGR565ToARGB32(*bgr++);
318 }
319
320 // leftovers
321 for (; x < width; ++x)
322 *argb++ = qConvertBGR565ToARGB32(*bgr++);
323
324 src += stride;
325 }
326}
327
328void 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++);
341 *argb++ = qConvertBGR555ToARGB32(*bgr++);
342 *argb++ = qConvertBGR555ToARGB32(*bgr++);
343 *argb++ = qConvertBGR555ToARGB32(*bgr++);
344 }
345
346 // leftovers
347 for (; x < width; ++x)
348 *argb++ = qConvertBGR555ToARGB32(*bgr++);
349
350 src += stride;
351 }
352}
353
354QT_END_NAMESPACE
355