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
9QT_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
20static 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
29static 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
65static 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
97static 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
108static 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
120static 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
131static 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
156static 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
181static 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
207static 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
233static 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
244static 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
255static 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
269static 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
282static 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
296static 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
310template<typename Pixel>
311static 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
344template<typename Pixel>
345static 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
378static 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
418static 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
430template <typename Y>
431static 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
465template<typename Pixel>
466static 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
473static 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
505static PixelsCopyFunc qPixelsCopyFunc = qt_copy_pixels_with_mask<uint32_t>;
506
507static std::once_flag InitFuncsAsmFlag;
508
509static 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
574VideoFrameConvertFunc qConverterForFormat(QVideoFrameFormat::PixelFormat format)
575{
576 std::call_once(once&: InitFuncsAsmFlag, f: &qInitFuncsAsm);
577
578 VideoFrameConvertFunc convert = qConvertFuncs[format];
579 return convert;
580}
581
582void 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
599void 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
606uint32_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
634QT_END_NAMESPACE
635

source code of qtmultimedia/src/multimedia/video/qvideoframeconversionhelper.cpp