1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qvideoframeconversionhelper_p.h" |
5 | #include "qrgb.h" |
6 | |
7 | #include <mutex> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | #define CLAMP(n) (n > 255 ? 255 : (n < 0 ? 0 : n)) |
12 | |
13 | #define EXPAND_UV(u, v) \ |
14 | int uu = u - 128; \ |
15 | int vv = v - 128; \ |
16 | int rv = 409 * vv + 128; \ |
17 | int guv = 100 * uu + 208 * vv + 128; \ |
18 | int bu = 516 * uu + 128; \ |
19 | |
20 | static inline quint32 qYUVToARGB32(int y, int rv, int guv, int bu, int a = 0xff) |
21 | { |
22 | int yy = (y - 16) * 298; |
23 | return (a << 24) |
24 | | CLAMP((yy + rv) >> 8) << 16 |
25 | | CLAMP((yy - guv) >> 8) << 8 |
26 | | CLAMP((yy + bu) >> 8); |
27 | } |
28 | |
29 | static inline void planarYUV420_to_ARGB32(const uchar *y, int yStride, |
30 | const uchar *u, int uStride, |
31 | const uchar *v, int vStride, |
32 | int uvPixelStride, |
33 | quint32 *rgb, |
34 | int width, int height) |
35 | { |
36 | height &= ~1; |
37 | quint32 *rgb0 = rgb; |
38 | quint32 *rgb1 = rgb + width; |
39 | |
40 | for (int j = 0; j < height; j += 2) { |
41 | const uchar *lineY0 = y; |
42 | const uchar *lineY1 = y + yStride; |
43 | const uchar *lineU = u; |
44 | const uchar *lineV = v; |
45 | |
46 | for (int i = 0; i < width; i += 2) { |
47 | EXPAND_UV(*lineU, *lineV); |
48 | lineU += uvPixelStride; |
49 | lineV += uvPixelStride; |
50 | |
51 | *rgb0++ = qYUVToARGB32(y: *lineY0++, rv, guv, bu); |
52 | *rgb0++ = qYUVToARGB32(y: *lineY0++, rv, guv, bu); |
53 | *rgb1++ = qYUVToARGB32(y: *lineY1++, rv, guv, bu); |
54 | *rgb1++ = qYUVToARGB32(y: *lineY1++, rv, guv, bu); |
55 | } |
56 | |
57 | y += yStride << 1; // stride * 2 |
58 | u += uStride; |
59 | v += vStride; |
60 | rgb0 += width; |
61 | rgb1 += width; |
62 | } |
63 | } |
64 | |
65 | static inline void planarYUV422_to_ARGB32(const uchar *y, int yStride, |
66 | const uchar *u, int uStride, |
67 | const uchar *v, int vStride, |
68 | int uvPixelStride, |
69 | quint32 *rgb, |
70 | int width, int height) |
71 | { |
72 | quint32 *rgb0 = rgb; |
73 | |
74 | for (int j = 0; j < height; ++j) { |
75 | const uchar *lineY0 = y; |
76 | const uchar *lineU = u; |
77 | const uchar *lineV = v; |
78 | |
79 | for (int i = 0; i < width; i += 2) { |
80 | EXPAND_UV(*lineU, *lineV); |
81 | lineU += uvPixelStride; |
82 | lineV += uvPixelStride; |
83 | |
84 | *rgb0++ = qYUVToARGB32(y: *lineY0++, rv, guv, bu); |
85 | *rgb0++ = qYUVToARGB32(y: *lineY0++, rv, guv, bu); |
86 | } |
87 | |
88 | y += yStride; // stride * 2 |
89 | u += uStride; |
90 | v += vStride; |
91 | rgb0 += width; |
92 | } |
93 | } |
94 | |
95 | |
96 | |
97 | static void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output) |
98 | { |
99 | FETCH_INFO_TRIPLANAR(frame) |
100 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
101 | u: plane2, uStride: plane2Stride, |
102 | v: plane3, vStride: plane3Stride, |
103 | uvPixelStride: 1, |
104 | rgb: reinterpret_cast<quint32*>(output), |
105 | width, height); |
106 | } |
107 | |
108 | static void QT_FASTCALL qt_convert_YUV422P_to_ARGB32(const QVideoFrame &frame, uchar *output) |
109 | { |
110 | FETCH_INFO_TRIPLANAR(frame) |
111 | planarYUV422_to_ARGB32(y: plane1, yStride: plane1Stride, |
112 | u: plane2, uStride: plane2Stride, |
113 | v: plane3, vStride: plane3Stride, |
114 | uvPixelStride: 1, |
115 | rgb: reinterpret_cast<quint32*>(output), |
116 | width, height); |
117 | } |
118 | |
119 | |
120 | static void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output) |
121 | { |
122 | FETCH_INFO_TRIPLANAR(frame) |
123 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
124 | u: plane3, uStride: plane3Stride, |
125 | v: plane2, vStride: plane2Stride, |
126 | uvPixelStride: 1, |
127 | rgb: reinterpret_cast<quint32*>(output), |
128 | width, height); |
129 | } |
130 | |
131 | static void QT_FASTCALL qt_convert_AYUV_to_ARGB32(const QVideoFrame &frame, uchar *output) |
132 | { |
133 | FETCH_INFO_PACKED(frame) |
134 | MERGE_LOOPS(width, height, stride, 4) |
135 | |
136 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
137 | |
138 | for (int i = 0; i < height; ++i) { |
139 | const uchar *lineSrc = src; |
140 | |
141 | for (int j = 0; j < width; ++j) { |
142 | int a = *lineSrc++; |
143 | int y = *lineSrc++; |
144 | int u = *lineSrc++; |
145 | int v = *lineSrc++; |
146 | |
147 | EXPAND_UV(u, v); |
148 | |
149 | *rgb++ = qPremultiply(x: qYUVToARGB32(y, rv, guv, bu, a)); |
150 | } |
151 | |
152 | src += stride; |
153 | } |
154 | } |
155 | |
156 | static void QT_FASTCALL qt_convert_AYUV_Premultiplied_to_ARGB32(const QVideoFrame &frame, uchar *output) |
157 | { |
158 | FETCH_INFO_PACKED(frame) |
159 | MERGE_LOOPS(width, height, stride, 4) |
160 | |
161 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
162 | |
163 | for (int i = 0; i < height; ++i) { |
164 | const uchar *lineSrc = src; |
165 | |
166 | for (int j = 0; j < width; ++j) { |
167 | int a = *lineSrc++; |
168 | int y = *lineSrc++; |
169 | int u = *lineSrc++; |
170 | int v = *lineSrc++; |
171 | |
172 | EXPAND_UV(u, v); |
173 | |
174 | *rgb++ = qYUVToARGB32(y, rv, guv, bu, a); |
175 | } |
176 | |
177 | src += stride; |
178 | } |
179 | } |
180 | |
181 | static void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output) |
182 | { |
183 | FETCH_INFO_PACKED(frame) |
184 | MERGE_LOOPS(width, height, stride, 2) |
185 | |
186 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
187 | |
188 | for (int i = 0; i < height; ++i) { |
189 | const uchar *lineSrc = src; |
190 | |
191 | for (int j = 0; j < width; j += 2) { |
192 | int u = *lineSrc++; |
193 | int y0 = *lineSrc++; |
194 | int v = *lineSrc++; |
195 | int y1 = *lineSrc++; |
196 | |
197 | EXPAND_UV(u, v); |
198 | |
199 | *rgb++ = qYUVToARGB32(y: y0, rv, guv, bu); |
200 | *rgb++ = qYUVToARGB32(y: y1, rv, guv, bu); |
201 | } |
202 | |
203 | src += stride; |
204 | } |
205 | } |
206 | |
207 | static void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output) |
208 | { |
209 | FETCH_INFO_PACKED(frame) |
210 | MERGE_LOOPS(width, height, stride, 2) |
211 | |
212 | quint32 *rgb = reinterpret_cast<quint32*>(output); |
213 | |
214 | for (int i = 0; i < height; ++i) { |
215 | const uchar *lineSrc = src; |
216 | |
217 | for (int j = 0; j < width; j += 2) { |
218 | int y0 = *lineSrc++; |
219 | int u = *lineSrc++; |
220 | int y1 = *lineSrc++; |
221 | int v = *lineSrc++; |
222 | |
223 | EXPAND_UV(u, v); |
224 | |
225 | *rgb++ = qYUVToARGB32(y: y0, rv, guv, bu); |
226 | *rgb++ = qYUVToARGB32(y: y1, rv, guv, bu); |
227 | } |
228 | |
229 | src += stride; |
230 | } |
231 | } |
232 | |
233 | static void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output) |
234 | { |
235 | FETCH_INFO_BIPLANAR(frame) |
236 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
237 | u: plane2, uStride: plane2Stride, |
238 | v: plane2 + 1, vStride: plane2Stride, |
239 | uvPixelStride: 2, |
240 | rgb: reinterpret_cast<quint32*>(output), |
241 | width, height); |
242 | } |
243 | |
244 | static void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output) |
245 | { |
246 | FETCH_INFO_BIPLANAR(frame) |
247 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
248 | u: plane2 + 1, uStride: plane2Stride, |
249 | v: plane2, vStride: plane2Stride, |
250 | uvPixelStride: 2, |
251 | rgb: reinterpret_cast<quint32*>(output), |
252 | width, height); |
253 | } |
254 | |
255 | static void QT_FASTCALL qt_convert_IMC1_to_ARGB32(const QVideoFrame &frame, uchar *output) |
256 | { |
257 | FETCH_INFO_TRIPLANAR(frame) |
258 | Q_ASSERT(plane1Stride == plane2Stride); |
259 | Q_ASSERT(plane1Stride == plane3Stride); |
260 | |
261 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
262 | u: plane3, uStride: plane3Stride, |
263 | v: plane2, vStride: plane2Stride, |
264 | uvPixelStride: 1, |
265 | rgb: reinterpret_cast<quint32*>(output), |
266 | width, height); |
267 | } |
268 | |
269 | static void QT_FASTCALL qt_convert_IMC2_to_ARGB32(const QVideoFrame &frame, uchar *output) |
270 | { |
271 | FETCH_INFO_BIPLANAR(frame) |
272 | Q_ASSERT(plane1Stride == plane2Stride); |
273 | |
274 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
275 | u: plane2 + (plane1Stride >> 1), uStride: plane1Stride, |
276 | v: plane2, vStride: plane1Stride, |
277 | uvPixelStride: 1, |
278 | rgb: reinterpret_cast<quint32*>(output), |
279 | width, height); |
280 | } |
281 | |
282 | static void QT_FASTCALL qt_convert_IMC3_to_ARGB32(const QVideoFrame &frame, uchar *output) |
283 | { |
284 | FETCH_INFO_TRIPLANAR(frame) |
285 | Q_ASSERT(plane1Stride == plane2Stride); |
286 | Q_ASSERT(plane1Stride == plane3Stride); |
287 | |
288 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
289 | u: plane2, uStride: plane2Stride, |
290 | v: plane3, vStride: plane3Stride, |
291 | uvPixelStride: 1, |
292 | rgb: reinterpret_cast<quint32*>(output), |
293 | width, height); |
294 | } |
295 | |
296 | static void QT_FASTCALL qt_convert_IMC4_to_ARGB32(const QVideoFrame &frame, uchar *output) |
297 | { |
298 | FETCH_INFO_BIPLANAR(frame) |
299 | Q_ASSERT(plane1Stride == plane2Stride); |
300 | |
301 | planarYUV420_to_ARGB32(y: plane1, yStride: plane1Stride, |
302 | u: plane2, uStride: plane1Stride, |
303 | v: plane2 + (plane1Stride >> 1), vStride: plane1Stride, |
304 | uvPixelStride: 1, |
305 | rgb: reinterpret_cast<quint32*>(output), |
306 | width, height); |
307 | } |
308 | |
309 | |
310 | template<typename Pixel> |
311 | static void QT_FASTCALL qt_convert_to_ARGB32(const QVideoFrame &frame, uchar *output) |
312 | { |
313 | FETCH_INFO_PACKED(frame) |
314 | MERGE_LOOPS(width, height, stride, 4) |
315 | |
316 | quint32 *argb = reinterpret_cast<quint32*>(output); |
317 | |
318 | for (int y = 0; y < height; ++y) { |
319 | const Pixel *data = reinterpret_cast<const Pixel *>(src); |
320 | |
321 | int x = 0; |
322 | for (; x < width - 3; x += 4) { |
323 | // Copy 4 pixels onto the stack in one go. This significantly increases performance |
324 | // in the case where the mapped memory is uncached (because it's a framebuffer) |
325 | Pixel p[4]; |
326 | memcpy(p, data, 4*sizeof(Pixel)); |
327 | *argb++ = qPremultiply(p[0].convert()); |
328 | *argb++ = qPremultiply(p[1].convert()); |
329 | *argb++ = qPremultiply(p[2].convert()); |
330 | *argb++ = qPremultiply(p[3].convert()); |
331 | data += 4; |
332 | } |
333 | |
334 | // leftovers |
335 | for (; x < width; ++x) { |
336 | *argb++ = qPremultiply(data->convert()); |
337 | ++data; |
338 | } |
339 | |
340 | src += stride; |
341 | } |
342 | } |
343 | |
344 | template<typename Pixel> |
345 | static void QT_FASTCALL qt_convert_premultiplied_to_ARGB32(const QVideoFrame &frame, uchar *output) |
346 | { |
347 | FETCH_INFO_PACKED(frame) |
348 | MERGE_LOOPS(width, height, stride, 4) |
349 | |
350 | quint32 *argb = reinterpret_cast<quint32*>(output); |
351 | |
352 | for (int y = 0; y < height; ++y) { |
353 | const Pixel *data = reinterpret_cast<const Pixel *>(src); |
354 | |
355 | int x = 0; |
356 | for (; x < width - 3; x += 4) { |
357 | // Copy 4 pixels onto the stack in one go. This significantly increases performance |
358 | // in the case where the mapped memory is uncached (because it's a framebuffer) |
359 | Pixel p[4]; |
360 | memcpy(p, data, 4*sizeof(Pixel)); |
361 | *argb++ = p[0].convert(); |
362 | *argb++ = p[1].convert(); |
363 | *argb++ = p[2].convert(); |
364 | *argb++ = p[3].convert(); |
365 | data += 4; |
366 | } |
367 | |
368 | // leftovers |
369 | for (; x < width; ++x) { |
370 | *argb++ = data->convert(); |
371 | ++data; |
372 | } |
373 | |
374 | src += stride; |
375 | } |
376 | } |
377 | |
378 | static inline void planarYUV420_16bit_to_ARGB32(const uchar *y, int yStride, |
379 | const uchar *u, int uStride, |
380 | const uchar *v, int vStride, |
381 | int uvPixelStride, |
382 | quint32 *rgb, |
383 | int width, int height) |
384 | { |
385 | height &= ~1; |
386 | quint32 *rgb0 = rgb; |
387 | quint32 *rgb1 = rgb + width; |
388 | |
389 | for (int j = 0; j < height; j += 2) { |
390 | const uchar *lineY0 = y; |
391 | const uchar *lineY1 = y + yStride; |
392 | const uchar *lineU = u; |
393 | const uchar *lineV = v; |
394 | |
395 | for (int i = 0; i < width; i += 2) { |
396 | EXPAND_UV(*lineU, *lineV); |
397 | lineU += uvPixelStride; |
398 | lineV += uvPixelStride; |
399 | |
400 | *rgb0++ = qYUVToARGB32(y: *lineY0, rv, guv, bu); |
401 | lineY0 += 2; |
402 | *rgb0++ = qYUVToARGB32(y: *lineY0, rv, guv, bu); |
403 | lineY0 += 2; |
404 | *rgb1++ = qYUVToARGB32(y: *lineY1, rv, guv, bu); |
405 | lineY1 += 2; |
406 | *rgb1++ = qYUVToARGB32(y: *lineY1, rv, guv, bu); |
407 | lineY1 += 2; |
408 | } |
409 | |
410 | y += yStride << 1; // stride * 2 |
411 | u += uStride; |
412 | v += vStride; |
413 | rgb0 += width; |
414 | rgb1 += width; |
415 | } |
416 | } |
417 | |
418 | static void QT_FASTCALL qt_convert_P016_to_ARGB32(const QVideoFrame &frame, uchar *output) |
419 | { |
420 | FETCH_INFO_BIPLANAR(frame) |
421 | planarYUV420_16bit_to_ARGB32(y: plane1 + 1, yStride: plane1Stride, |
422 | u: plane2 + 1, uStride: plane2Stride, |
423 | v: plane2 + 3, vStride: plane2Stride, |
424 | uvPixelStride: 4, |
425 | rgb: reinterpret_cast<quint32*>(output), |
426 | width, height); |
427 | |
428 | } |
429 | |
430 | template <typename Y> |
431 | static void QT_FASTCALL qt_convert_Y_to_ARGB32(const QVideoFrame &frame, uchar *output) |
432 | { |
433 | FETCH_INFO_PACKED(frame) |
434 | MERGE_LOOPS(width, height, stride, (int)sizeof(Y)) |
435 | quint32 *argb = reinterpret_cast<quint32*>(output); |
436 | |
437 | using Pixel = YPixel<Y>; |
438 | |
439 | for (int y = 0; y < height; ++y) { |
440 | const Pixel *pixel = reinterpret_cast<const Pixel *>(src); |
441 | |
442 | int x = 0; |
443 | for (; x < width - 3; x += 4) { |
444 | *argb++ = pixel->convert(); |
445 | ++pixel; |
446 | *argb++ = pixel->convert(); |
447 | ++pixel; |
448 | *argb++ = pixel->convert(); |
449 | ++pixel; |
450 | *argb++ = pixel->convert(); |
451 | ++pixel; |
452 | } |
453 | |
454 | // leftovers |
455 | for (; x < width; ++x) { |
456 | *argb++ = pixel->convert(); |
457 | ++pixel; |
458 | } |
459 | |
460 | src += stride; |
461 | } |
462 | MERGE_LOOPS(width, height, stride, 1) |
463 | } |
464 | |
465 | template<typename Pixel> |
466 | static void QT_FASTCALL qt_copy_pixels_with_mask(Pixel *dst, const Pixel *src, size_t size, |
467 | Pixel mask) |
468 | { |
469 | for (size_t x = 0; x < size; ++x) |
470 | dst[x] = src[x] | mask; |
471 | } |
472 | |
473 | static VideoFrameConvertFunc qConvertFuncs[QVideoFrameFormat::NPixelFormats] = { |
474 | /* Format_Invalid */ nullptr, // Not needed |
475 | /* Format_ARGB8888 */ qt_convert_to_ARGB32<ARGB8888>, |
476 | /* Format_ARGB8888_Premultiplied */ qt_convert_premultiplied_to_ARGB32<ARGB8888>, |
477 | /* Format_XRGB8888 */ qt_convert_premultiplied_to_ARGB32<XRGB8888>, |
478 | /* Format_BGRA8888 */ qt_convert_to_ARGB32<BGRA8888>, |
479 | /* Format_BGRA8888_Premultiplied */ qt_convert_premultiplied_to_ARGB32<BGRA8888>, |
480 | /* Format_BGRX8888 */ qt_convert_premultiplied_to_ARGB32<BGRX8888>, |
481 | /* Format_ABGR8888 */ qt_convert_to_ARGB32<ABGR8888>, |
482 | /* Format_XBGR8888 */ qt_convert_premultiplied_to_ARGB32<XBGR8888>, |
483 | /* Format_RGBA8888 */ qt_convert_to_ARGB32<RGBA8888>, |
484 | /* Format_RGBX8888 */ qt_convert_premultiplied_to_ARGB32<RGBX8888>, |
485 | /* Format_AYUV */ qt_convert_AYUV_to_ARGB32, |
486 | /* Format_AYUV_Premultiplied */ qt_convert_AYUV_Premultiplied_to_ARGB32, |
487 | /* Format_YUV420P */ qt_convert_YUV420P_to_ARGB32, |
488 | /* Format_YUV422P */ qt_convert_YUV422P_to_ARGB32, |
489 | /* Format_YV12 */ qt_convert_YV12_to_ARGB32, |
490 | /* Format_UYVY */ qt_convert_UYVY_to_ARGB32, |
491 | /* Format_YUYV */ qt_convert_YUYV_to_ARGB32, |
492 | /* Format_NV12 */ qt_convert_NV12_to_ARGB32, |
493 | /* Format_NV21 */ qt_convert_NV21_to_ARGB32, |
494 | /* Format_IMC1 */ qt_convert_IMC1_to_ARGB32, |
495 | /* Format_IMC2 */ qt_convert_IMC2_to_ARGB32, |
496 | /* Format_IMC3 */ qt_convert_IMC3_to_ARGB32, |
497 | /* Format_IMC4 */ qt_convert_IMC4_to_ARGB32, |
498 | /* Format_Y8 */ qt_convert_Y_to_ARGB32<uchar>, |
499 | /* Format_Y16 */ qt_convert_Y_to_ARGB32<ushort>, |
500 | /* Format_P010 */ qt_convert_P016_to_ARGB32, |
501 | /* Format_P016 */ qt_convert_P016_to_ARGB32, |
502 | /* Format_Jpeg */ nullptr, // Not needed |
503 | }; |
504 | |
505 | static PixelsCopyFunc qPixelsCopyFunc = qt_copy_pixels_with_mask<uint32_t>; |
506 | |
507 | static std::once_flag InitFuncsAsmFlag; |
508 | |
509 | static void qInitFuncsAsm() |
510 | { |
511 | #ifdef QT_COMPILER_SUPPORTS_SSE2 |
512 | extern void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output); |
513 | extern void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output); |
514 | extern void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output); |
515 | extern void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output); |
516 | extern void QT_FASTCALL qt_copy_pixels_with_mask_sse2(uint32_t * dst, const uint32_t *src, size_t size, uint32_t mask); |
517 | |
518 | if (qCpuHasFeature(SSE2)){ |
519 | qConvertFuncs[QVideoFrameFormat::Format_ARGB8888] = qt_convert_ARGB8888_to_ARGB32_sse2; |
520 | qConvertFuncs[QVideoFrameFormat::Format_ARGB8888_Premultiplied] = qt_convert_ARGB8888_to_ARGB32_sse2; |
521 | qConvertFuncs[QVideoFrameFormat::Format_XRGB8888] = qt_convert_ARGB8888_to_ARGB32_sse2; |
522 | qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_sse2; |
523 | qConvertFuncs[QVideoFrameFormat::Format_BGRA8888_Premultiplied] = qt_convert_BGRA8888_to_ARGB32_sse2; |
524 | qConvertFuncs[QVideoFrameFormat::Format_BGRX8888] = qt_convert_BGRA8888_to_ARGB32_sse2; |
525 | qConvertFuncs[QVideoFrameFormat::Format_ABGR8888] = qt_convert_ABGR8888_to_ARGB32_sse2; |
526 | qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_ABGR8888_to_ARGB32_sse2; |
527 | qConvertFuncs[QVideoFrameFormat::Format_RGBA8888] = qt_convert_RGBA8888_to_ARGB32_sse2; |
528 | qConvertFuncs[QVideoFrameFormat::Format_RGBX8888] = qt_convert_RGBA8888_to_ARGB32_sse2; |
529 | |
530 | qPixelsCopyFunc = qt_copy_pixels_with_mask_sse2; |
531 | } |
532 | #endif |
533 | #ifdef QT_COMPILER_SUPPORTS_SSSE3 |
534 | extern void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output); |
535 | extern void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output); |
536 | extern void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output); |
537 | extern void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output); |
538 | if (qCpuHasFeature(SSSE3)){ |
539 | qConvertFuncs[QVideoFrameFormat::Format_ARGB8888] = qt_convert_ARGB8888_to_ARGB32_ssse3; |
540 | qConvertFuncs[QVideoFrameFormat::Format_ARGB8888_Premultiplied] = qt_convert_ARGB8888_to_ARGB32_ssse3; |
541 | qConvertFuncs[QVideoFrameFormat::Format_XRGB8888] = qt_convert_ARGB8888_to_ARGB32_ssse3; |
542 | qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_ssse3; |
543 | qConvertFuncs[QVideoFrameFormat::Format_BGRA8888_Premultiplied] = qt_convert_BGRA8888_to_ARGB32_ssse3; |
544 | qConvertFuncs[QVideoFrameFormat::Format_BGRX8888] = qt_convert_BGRA8888_to_ARGB32_ssse3; |
545 | qConvertFuncs[QVideoFrameFormat::Format_ABGR8888] = qt_convert_ABGR8888_to_ARGB32_ssse3; |
546 | qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_ABGR8888_to_ARGB32_ssse3; |
547 | qConvertFuncs[QVideoFrameFormat::Format_RGBA8888] = qt_convert_RGBA8888_to_ARGB32_ssse3; |
548 | qConvertFuncs[QVideoFrameFormat::Format_RGBX8888] = qt_convert_RGBA8888_to_ARGB32_ssse3; |
549 | } |
550 | #endif |
551 | #ifdef QT_COMPILER_SUPPORTS_AVX2 |
552 | extern void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output); |
553 | extern void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output); |
554 | extern void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output); |
555 | extern void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output); |
556 | extern void QT_FASTCALL qt_copy_pixels_with_mask_avx2(uint32_t * dst, const uint32_t *src, size_t size, uint32_t mask); |
557 | if (qCpuHasFeature(AVX2)){ |
558 | qConvertFuncs[QVideoFrameFormat::Format_ARGB8888] = qt_convert_ARGB8888_to_ARGB32_avx2; |
559 | qConvertFuncs[QVideoFrameFormat::Format_ARGB8888_Premultiplied] = qt_convert_ARGB8888_to_ARGB32_avx2; |
560 | qConvertFuncs[QVideoFrameFormat::Format_XRGB8888] = qt_convert_ARGB8888_to_ARGB32_avx2; |
561 | qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_avx2; |
562 | qConvertFuncs[QVideoFrameFormat::Format_BGRA8888_Premultiplied] = qt_convert_BGRA8888_to_ARGB32_avx2; |
563 | qConvertFuncs[QVideoFrameFormat::Format_BGRX8888] = qt_convert_BGRA8888_to_ARGB32_avx2; |
564 | qConvertFuncs[QVideoFrameFormat::Format_ABGR8888] = qt_convert_ABGR8888_to_ARGB32_avx2; |
565 | qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_ABGR8888_to_ARGB32_avx2; |
566 | qConvertFuncs[QVideoFrameFormat::Format_RGBA8888] = qt_convert_RGBA8888_to_ARGB32_avx2; |
567 | qConvertFuncs[QVideoFrameFormat::Format_RGBX8888] = qt_convert_RGBA8888_to_ARGB32_avx2; |
568 | |
569 | qPixelsCopyFunc = qt_copy_pixels_with_mask_avx2; |
570 | } |
571 | #endif |
572 | } |
573 | |
574 | VideoFrameConvertFunc qConverterForFormat(QVideoFrameFormat::PixelFormat format) |
575 | { |
576 | std::call_once(once&: InitFuncsAsmFlag, f: &qInitFuncsAsm); |
577 | |
578 | VideoFrameConvertFunc convert = qConvertFuncs[format]; |
579 | return convert; |
580 | } |
581 | |
582 | void Q_MULTIMEDIA_EXPORT qCopyPixelsWithAlphaMask(uint32_t *dst, |
583 | const uint32_t *src, |
584 | size_t pixCount, |
585 | QVideoFrameFormat::PixelFormat format, |
586 | bool srcAlphaVaries) |
587 | { |
588 | if (pixCount == 0) |
589 | return; |
590 | |
591 | const auto mask = qAlphaMask(format); |
592 | |
593 | if (srcAlphaVaries || (src[0] & mask) != mask) |
594 | qCopyPixelsWithMask(dst, src, size: pixCount, mask); |
595 | else |
596 | memcpy(dest: dst, src: src, n: pixCount * 4); |
597 | } |
598 | |
599 | void qCopyPixelsWithMask(uint32_t *dst, const uint32_t *src, size_t size, uint32_t mask) |
600 | { |
601 | std::call_once(once&: InitFuncsAsmFlag, f: &qInitFuncsAsm); |
602 | |
603 | qPixelsCopyFunc(dst, src, size, mask); |
604 | } |
605 | |
606 | uint32_t qAlphaMask(QVideoFrameFormat::PixelFormat format) |
607 | { |
608 | switch (format) { |
609 | case QVideoFrameFormat::Format_ARGB8888: |
610 | case QVideoFrameFormat::Format_ARGB8888_Premultiplied: |
611 | case QVideoFrameFormat::Format_XRGB8888: |
612 | case QVideoFrameFormat::Format_ABGR8888: |
613 | case QVideoFrameFormat::Format_XBGR8888: |
614 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
615 | return 0xff; |
616 | #else |
617 | return 0xff000000; |
618 | #endif |
619 | case QVideoFrameFormat::Format_BGRA8888: |
620 | case QVideoFrameFormat::Format_BGRA8888_Premultiplied: |
621 | case QVideoFrameFormat::Format_BGRX8888: |
622 | case QVideoFrameFormat::Format_RGBA8888: |
623 | case QVideoFrameFormat::Format_RGBX8888: |
624 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
625 | return 0xff000000; |
626 | #else |
627 | return 0xff; |
628 | #endif |
629 | default: |
630 | return 0; |
631 | } |
632 | } |
633 | |
634 | QT_END_NAMESPACE |
635 | |