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