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:GPL-EXCEPT$ |
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 General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | //TESTED_COMPONENT=src/multimedia |
30 | |
31 | #include <private/qpaintervideosurface_p.h> |
32 | #include <QtTest/QtTest> |
33 | |
34 | #include <QtWidgets/qapplication.h> |
35 | #include <qvideosurfaceformat.h> |
36 | |
37 | #if QT_CONFIG(opengl) |
38 | #include <QOpenGLContext> |
39 | #include <QOpenGLFunctions> |
40 | #include <QOpenGLWidget> |
41 | #endif |
42 | |
43 | QT_USE_NAMESPACE |
44 | class tst_QPainterVideoSurface : public QObject |
45 | { |
46 | Q_OBJECT |
47 | private slots: |
48 | void cleanup() {} |
49 | void cleanupTestCase() {} |
50 | |
51 | void colors(); |
52 | |
53 | void supportedFormat_data(); |
54 | void supportedFormat(); |
55 | |
56 | void present_data(); |
57 | void present(); |
58 | void presentOpaqueFrame(); |
59 | |
60 | #if QT_CONFIG(opengl) |
61 | |
62 | void shaderType(); |
63 | |
64 | void shaderTypeStarted_data(); |
65 | void shaderTypeStarted(); |
66 | |
67 | void shaderSupportedFormat_data(); |
68 | void shaderSupportedFormat(); |
69 | |
70 | void shaderPresent_data(); |
71 | void shaderPresent(); |
72 | void shaderPresentOpaqueFrame_data(); |
73 | void shaderPresentOpaqueFrame(); |
74 | void shaderPresentGLFrame_data(); |
75 | void shaderPresentGLFrame(); |
76 | #endif |
77 | private: |
78 | bool m_libGL = QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL; |
79 | }; |
80 | |
81 | Q_DECLARE_METATYPE(const uchar *) |
82 | |
83 | #if QT_CONFIG(opengl) |
84 | Q_DECLARE_METATYPE(QPainterVideoSurface::ShaderType); |
85 | |
86 | class QtTestGLVideoBuffer : public QAbstractVideoBuffer |
87 | { |
88 | public: |
89 | QtTestGLVideoBuffer() |
90 | : QAbstractVideoBuffer(GLTextureHandle) |
91 | , m_textureId(0) |
92 | { |
93 | QOpenGLContext::currentContext()->functions()->glGenTextures(n: 1, textures: &m_textureId); |
94 | } |
95 | |
96 | ~QtTestGLVideoBuffer() |
97 | { |
98 | QOpenGLContext::currentContext()->functions()->glDeleteTextures(n: 1, textures: &m_textureId); |
99 | } |
100 | |
101 | GLuint textureId() const { return m_textureId; } |
102 | |
103 | QVariant handle() const { return m_textureId; } |
104 | |
105 | uchar *map(MapMode, int *, int *) { return 0; } |
106 | void unmap() {} |
107 | MapMode mapMode() const { return NotMapped; } |
108 | |
109 | private: |
110 | GLuint m_textureId; |
111 | }; |
112 | |
113 | #endif |
114 | |
115 | class QtTestOpaqueVideoBuffer : public QAbstractVideoBuffer |
116 | { |
117 | public: |
118 | QtTestOpaqueVideoBuffer() |
119 | : QAbstractVideoBuffer(UserHandle) |
120 | {} |
121 | |
122 | uchar *map(MapMode, int *, int *) { return 0; } |
123 | void unmap() {} |
124 | MapMode mapMode() const { return NotMapped; } |
125 | }; |
126 | |
127 | void tst_QPainterVideoSurface::colors() |
128 | { |
129 | QPainterVideoSurface surface; |
130 | |
131 | QCOMPARE(surface.brightness(), 0); |
132 | QCOMPARE(surface.contrast(), 0); |
133 | QCOMPARE(surface.hue(), 0); |
134 | QCOMPARE(surface.saturation(), 0); |
135 | |
136 | surface.setBrightness(56); |
137 | QCOMPARE(surface.brightness(), 56); |
138 | |
139 | surface.setContrast(43); |
140 | QCOMPARE(surface.contrast(), 43); |
141 | |
142 | surface.setHue(-84); |
143 | QCOMPARE(surface.hue(), -84); |
144 | |
145 | surface.setSaturation(100); |
146 | QCOMPARE(surface.saturation(), 100); |
147 | } |
148 | |
149 | static const uchar rgb32ImageData[] = |
150 | { |
151 | 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, |
152 | 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00 |
153 | }; |
154 | |
155 | static const uchar argb32ImageData[] = |
156 | { |
157 | 0x00, 0xff, 0x00, 0x00, 0xcc, 0x00, 0xff, 0xcc, |
158 | 0x77, 0x00, 0x00, 0x77, 0x00, 0xff, 0xff, 0x00 |
159 | }; |
160 | |
161 | static const uchar rgb24ImageData[] = |
162 | { |
163 | 0x00, 0xff, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, |
164 | 0xcc, 0x00, 0xcc, 0x77, 0xff, 0x77, 0x00, 0x00 |
165 | }; |
166 | |
167 | static const uchar rgb565ImageData[] = |
168 | { |
169 | 0xff, 0xff, 0xff, 0xff, |
170 | 0x00, 0x00, 0x00, 0x00 |
171 | }; |
172 | |
173 | static const uchar yuvPlanarImageData[] = |
174 | { |
175 | 0x00, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, |
176 | 0x00, 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0f, 0x00, |
177 | 0x00, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0x00, |
178 | 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, |
179 | 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, |
180 | 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0x0f, |
181 | 0x00, 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0f, 0x00, |
182 | 0x00, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, |
183 | 0x00, 0x0f, 0x0f, 0x00, |
184 | 0x0f, 0x00, 0x00, 0x0f, |
185 | 0x0f, 0x00, 0x00, 0x0f, |
186 | 0x00, 0x0f, 0x0f, 0x00, |
187 | 0x00, 0x0f, 0x0f, 0x00, |
188 | 0x0f, 0x00, 0x00, 0x0f, |
189 | 0x0f, 0x00, 0x00, 0x0f, |
190 | 0x00, 0x0f, 0x0f, 0x00, |
191 | }; |
192 | |
193 | void tst_QPainterVideoSurface::supportedFormat_data() |
194 | { |
195 | QTest::addColumn<QAbstractVideoBuffer::HandleType>(name: "handleType" ); |
196 | QTest::addColumn<QVideoFrame::PixelFormat>(name: "pixelFormat" ); |
197 | QTest::addColumn<QSize>(name: "frameSize" ); |
198 | QTest::addColumn<bool>(name: "supportedPixelFormat" ); |
199 | QTest::addColumn<bool>(name: "supportedFormat" ); |
200 | |
201 | QTest::newRow(dataTag: "rgb32 640x480" ) |
202 | << QAbstractVideoBuffer::NoHandle |
203 | << QVideoFrame::Format_RGB32 |
204 | << QSize(640, 480) |
205 | << true |
206 | << true; |
207 | QTest::newRow(dataTag: "rgb32 -640x480" ) |
208 | << QAbstractVideoBuffer::NoHandle |
209 | << QVideoFrame::Format_RGB32 |
210 | << QSize(-640, 480) |
211 | << true |
212 | << false; |
213 | QTest::newRow(dataTag: "rgb24 1024x768" ) |
214 | << QAbstractVideoBuffer::NoHandle |
215 | << QVideoFrame::Format_RGB24 |
216 | << QSize(1024, 768) |
217 | #if !defined(QT_OPENGL_ES) |
218 | << m_libGL |
219 | << m_libGL; |
220 | #else |
221 | << false |
222 | << false; |
223 | #endif |
224 | QTest::newRow(dataTag: "rgb24 -1024x-768" ) |
225 | << QAbstractVideoBuffer::NoHandle |
226 | << QVideoFrame::Format_RGB24 |
227 | << QSize(-1024, -768) |
228 | #if !defined(QT_OPENGL_ES) |
229 | << m_libGL |
230 | #else |
231 | << false |
232 | #endif |
233 | << false; |
234 | QTest::newRow(dataTag: "rgb565 0x0" ) |
235 | << QAbstractVideoBuffer::NoHandle |
236 | << QVideoFrame::Format_RGB565 |
237 | << QSize(0, 0) |
238 | << true |
239 | << false; |
240 | QTest::newRow(dataTag: "YUV420P 640x480" ) |
241 | << QAbstractVideoBuffer::NoHandle |
242 | << QVideoFrame::Format_YUV420P |
243 | << QSize(640, 480) |
244 | << false |
245 | << false; |
246 | QTest::newRow(dataTag: "YUV420P 640x-480" ) |
247 | << QAbstractVideoBuffer::NoHandle |
248 | << QVideoFrame::Format_YUV420P |
249 | << QSize(640, -480) |
250 | << false |
251 | << false; |
252 | QTest::newRow(dataTag: "Y8 640x480" ) |
253 | << QAbstractVideoBuffer::NoHandle |
254 | << QVideoFrame::Format_Y8 |
255 | << QSize(640, 480) |
256 | << false |
257 | << false; |
258 | QTest::newRow(dataTag: "Texture: rgb32 640x480" ) |
259 | << QAbstractVideoBuffer::GLTextureHandle |
260 | << QVideoFrame::Format_RGB32 |
261 | << QSize(640, 480) |
262 | << false |
263 | << false; |
264 | QTest::newRow(dataTag: "Texture: rgb32 -640x480" ) |
265 | << QAbstractVideoBuffer::GLTextureHandle |
266 | << QVideoFrame::Format_RGB32 |
267 | << QSize(-640, 480) |
268 | << false |
269 | << false; |
270 | QTest::newRow(dataTag: "rgb565 32x32" ) |
271 | << QAbstractVideoBuffer::NoHandle |
272 | << QVideoFrame::Format_RGB565 |
273 | << QSize(32, 32) |
274 | << true |
275 | << true; |
276 | QTest::newRow(dataTag: "rgb565 0x0" ) |
277 | << QAbstractVideoBuffer::NoHandle |
278 | << QVideoFrame::Format_RGB565 |
279 | << QSize(0, 0) |
280 | << true |
281 | << false; |
282 | QTest::newRow(dataTag: "argb32 256x256" ) |
283 | << QAbstractVideoBuffer::NoHandle |
284 | << QVideoFrame::Format_ARGB32 |
285 | << QSize(256, 256) |
286 | << true |
287 | << true; |
288 | QTest::newRow(dataTag: "Texture: rgb24 1024x768" ) |
289 | << QAbstractVideoBuffer::GLTextureHandle |
290 | << QVideoFrame::Format_RGB24 |
291 | << QSize(1024, 768) |
292 | << false |
293 | << false; |
294 | QTest::newRow(dataTag: "Texture: rgb24 -1024x-768" ) |
295 | << QAbstractVideoBuffer::GLTextureHandle |
296 | << QVideoFrame::Format_RGB24 |
297 | << QSize(-1024, -768) |
298 | << false |
299 | << false; |
300 | QTest::newRow(dataTag: "Texture: YUV420P 640x480" ) |
301 | << QAbstractVideoBuffer::GLTextureHandle |
302 | << QVideoFrame::Format_YUV420P |
303 | << QSize(640, 480) |
304 | << false |
305 | << false; |
306 | QTest::newRow(dataTag: "Texture: YUV420P 640x-480" ) |
307 | << QAbstractVideoBuffer::GLTextureHandle |
308 | << QVideoFrame::Format_YUV420P |
309 | << QSize(640, -480) |
310 | << false |
311 | << false; |
312 | QTest::newRow(dataTag: "User Buffer: rgb32 256x256" ) |
313 | << QAbstractVideoBuffer::UserHandle |
314 | << QVideoFrame::Format_RGB32 |
315 | << QSize(256, 256) |
316 | << false |
317 | << false; |
318 | #if !defined(Q_OS_MAC) |
319 | QTest::newRow(dataTag: "Pixmap: rgb32 640x480" ) |
320 | << QAbstractVideoBuffer::QPixmapHandle |
321 | << QVideoFrame::Format_RGB32 |
322 | << QSize(640, 480) |
323 | << true |
324 | << true; |
325 | QTest::newRow(dataTag: "Pixmap: YUV420P 640x480" ) |
326 | << QAbstractVideoBuffer::QPixmapHandle |
327 | << QVideoFrame::Format_YUV420P |
328 | << QSize(640, 480) |
329 | << false |
330 | << true; |
331 | #endif |
332 | } |
333 | |
334 | void tst_QPainterVideoSurface::supportedFormat() |
335 | { |
336 | QFETCH(QAbstractVideoBuffer::HandleType, handleType); |
337 | QFETCH(QVideoFrame::PixelFormat, pixelFormat); |
338 | QFETCH(QSize, frameSize); |
339 | QFETCH(bool, supportedPixelFormat); |
340 | QFETCH(bool, supportedFormat); |
341 | |
342 | QPainterVideoSurface surface; |
343 | |
344 | const QList<QVideoFrame::PixelFormat> pixelFormats = surface.supportedPixelFormats(handleType); |
345 | |
346 | QCOMPARE(pixelFormats.contains(pixelFormat), supportedPixelFormat); |
347 | |
348 | QVideoSurfaceFormat format(frameSize, pixelFormat, handleType); |
349 | |
350 | QCOMPARE(surface.isFormatSupported(format), supportedFormat); |
351 | QCOMPARE(surface.start(format), supportedFormat); |
352 | } |
353 | |
354 | void tst_QPainterVideoSurface::present_data() |
355 | { |
356 | QTest::addColumn<QVideoFrame::PixelFormat>(name: "pixelFormatA" ); |
357 | QTest::addColumn<QSize>(name: "frameSizeA" ); |
358 | QTest::addColumn<const uchar *>(name: "frameDataA" ); |
359 | QTest::addColumn<int>(name: "bytesA" ); |
360 | QTest::addColumn<int>(name: "bytesPerLineA" ); |
361 | QTest::addColumn<QVideoFrame::PixelFormat>(name: "pixelFormatB" ); |
362 | QTest::addColumn<QSize>(name: "frameSizeB" ); |
363 | QTest::addColumn<const uchar *>(name: "frameDataB" ); |
364 | QTest::addColumn<int>(name: "bytesB" ); |
365 | QTest::addColumn<int>(name: "bytesPerLineB" ); |
366 | |
367 | QTest::newRow(dataTag: "rgb32 -> argb32" ) |
368 | << QVideoFrame::Format_RGB32 |
369 | << QSize(2, 2) |
370 | << static_cast<const uchar *>(rgb32ImageData) |
371 | << int(sizeof(rgb32ImageData)) |
372 | << 8 |
373 | << QVideoFrame::Format_ARGB32 |
374 | << QSize(2, 2) |
375 | << static_cast<const uchar *>(argb32ImageData) |
376 | << int(sizeof(argb32ImageData)) |
377 | << 8; |
378 | |
379 | #if !defined(QT_OPENGL_ES) |
380 | if (m_libGL) |
381 | QTest::newRow(dataTag: "rgb32 -> rgb24" ) |
382 | << QVideoFrame::Format_RGB32 |
383 | << QSize(2, 2) |
384 | << static_cast<const uchar *>(rgb32ImageData) |
385 | << int(sizeof(rgb32ImageData)) |
386 | << 8 |
387 | << QVideoFrame::Format_RGB24 |
388 | << QSize(2, 2) |
389 | << static_cast<const uchar *>(rgb24ImageData) |
390 | << int(sizeof(rgb24ImageData)) |
391 | << 8; |
392 | #endif |
393 | |
394 | QTest::newRow(dataTag: "rgb32 -> rgb565" ) |
395 | << QVideoFrame::Format_RGB32 |
396 | << QSize(2, 2) |
397 | << static_cast<const uchar *>(rgb32ImageData) |
398 | << int(sizeof(rgb32ImageData)) |
399 | << 8 |
400 | << QVideoFrame::Format_RGB565 |
401 | << QSize(2, 2) |
402 | << static_cast<const uchar *>(rgb565ImageData) |
403 | << int(sizeof(rgb565ImageData)) |
404 | << 4; |
405 | |
406 | #if !defined(QT_OPENGL_ES) |
407 | if (m_libGL) |
408 | QTest::newRow(dataTag: "rgb24 -> rgb565" ) |
409 | << QVideoFrame::Format_RGB24 |
410 | << QSize(2, 2) |
411 | << static_cast<const uchar *>(rgb24ImageData) |
412 | << int(sizeof(rgb24ImageData)) |
413 | << 8 |
414 | << QVideoFrame::Format_RGB565 |
415 | << QSize(2, 2) |
416 | << static_cast<const uchar *>(rgb565ImageData) |
417 | << int(sizeof(rgb565ImageData)) |
418 | << 4; |
419 | #endif |
420 | } |
421 | |
422 | void tst_QPainterVideoSurface::present() |
423 | { |
424 | QFETCH(QVideoFrame::PixelFormat, pixelFormatA); |
425 | QFETCH(QSize, frameSizeA); |
426 | QFETCH(const uchar *, frameDataA); |
427 | QFETCH(int, bytesA); |
428 | QFETCH(int, bytesPerLineA); |
429 | QFETCH(QVideoFrame::PixelFormat, pixelFormatB); |
430 | QFETCH(QSize, frameSizeB); |
431 | QFETCH(const uchar *, frameDataB); |
432 | QFETCH(int, bytesB); |
433 | QFETCH(int, bytesPerLineB); |
434 | |
435 | QPainterVideoSurface surface; |
436 | |
437 | QImage image(320, 240, QImage::Format_RGB32); |
438 | |
439 | QSignalSpy frameSpy(&surface, SIGNAL(frameChanged())); |
440 | |
441 | const QList<QVideoFrame::PixelFormat> pixelFormats = surface.supportedPixelFormats(); |
442 | |
443 | { // Test painting before started. |
444 | QPainter painter(&image); |
445 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
446 | } |
447 | |
448 | QVideoSurfaceFormat formatA(frameSizeA, pixelFormatA); |
449 | |
450 | QVERIFY(surface.start(formatA)); |
451 | QCOMPARE(surface.isActive(), true); |
452 | QCOMPARE(surface.isReady(), true); |
453 | |
454 | { // Test painting before receiving a frame. |
455 | QPainter painter(&image); |
456 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
457 | } |
458 | QCOMPARE(surface.error(), QAbstractVideoSurface::NoError); |
459 | |
460 | QVideoFrame frameA(bytesA, frameSizeA, bytesPerLineA, pixelFormatA); |
461 | |
462 | frameA.map(mode: QAbstractVideoBuffer::WriteOnly); |
463 | memcpy(dest: frameA.bits(), src: frameDataA, n: frameA.mappedBytes()); |
464 | frameA.unmap(); |
465 | |
466 | QVERIFY(surface.present(frameA)); |
467 | QCOMPARE(surface.isReady(), false); |
468 | QCOMPARE(frameSpy.count(), 1); |
469 | |
470 | { |
471 | QPainter painter(&image); |
472 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
473 | } |
474 | QCOMPARE(surface.isActive(), true); |
475 | QCOMPARE(surface.isReady(), false); |
476 | |
477 | { // Test repainting before receiving another frame. |
478 | QPainter painter(&image); |
479 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
480 | } |
481 | QCOMPARE(surface.isActive(), true); |
482 | QCOMPARE(surface.isReady(), false); |
483 | |
484 | QVERIFY(surface.present(frameA)); |
485 | QCOMPARE(frameSpy.count(), 1); |
486 | |
487 | surface.setReady(true); |
488 | QCOMPARE(surface.isReady(), true); |
489 | QVERIFY(surface.present(frameA)); |
490 | QCOMPARE(frameSpy.count(), 2); |
491 | |
492 | // Try switching to a different format after starting. |
493 | QVideoSurfaceFormat formatB(frameSizeB, pixelFormatB); |
494 | |
495 | QVERIFY(surface.start(formatB)); |
496 | QCOMPARE(surface.isActive(), true); |
497 | QCOMPARE(surface.isReady(), true); |
498 | |
499 | QVideoFrame frameB(bytesB, frameSizeB, bytesPerLineB, pixelFormatB); |
500 | |
501 | frameB.map(mode: QAbstractVideoBuffer::WriteOnly); |
502 | memcpy(dest: frameB.bits(), src: frameDataB, n: frameB.mappedBytes()); |
503 | frameB.unmap(); |
504 | |
505 | QVERIFY(surface.present(frameB)); |
506 | QCOMPARE(surface.isReady(), false); |
507 | QCOMPARE(frameSpy.count(), 3); |
508 | |
509 | { |
510 | QPainter painter(&image); |
511 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
512 | } |
513 | QVERIFY(surface.isActive()); |
514 | |
515 | surface.stop(); |
516 | |
517 | QCOMPARE(surface.isActive(), false); |
518 | QCOMPARE(surface.isReady(), false); |
519 | |
520 | // Try presenting a frame while stopped. |
521 | QVERIFY(!surface.present(frameB)); |
522 | QCOMPARE(surface.isReady(), false); |
523 | QCOMPARE(surface.error(), QAbstractVideoSurface::StoppedError); |
524 | |
525 | // Try presenting a frame with a different format. |
526 | QVERIFY(surface.start(formatB)); |
527 | QVERIFY(!surface.present(frameA)); |
528 | QCOMPARE(surface.isActive(), false); |
529 | QCOMPARE(surface.isReady(), false); |
530 | QCOMPARE(surface.error(), QAbstractVideoSurface::IncorrectFormatError); |
531 | } |
532 | |
533 | void tst_QPainterVideoSurface::presentOpaqueFrame() |
534 | { |
535 | QPainterVideoSurface surface; |
536 | |
537 | QImage image(320, 240, QImage::Format_RGB32); |
538 | |
539 | QVideoSurfaceFormat format(QSize(64, 64), QVideoFrame::Format_RGB32); |
540 | |
541 | QVERIFY(surface.start(format)); |
542 | QCOMPARE(surface.isActive(), true); |
543 | QCOMPARE(surface.isReady(), true); |
544 | |
545 | QVideoFrame frame(new QtTestOpaqueVideoBuffer, QSize(64, 64), QVideoFrame::Format_RGB32); |
546 | |
547 | if (surface.present(frame)) { |
548 | QPainter painter(&image); |
549 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
550 | } |
551 | |
552 | QCOMPARE(surface.isActive(), false); |
553 | QCOMPARE(surface.isReady(), false); |
554 | QCOMPARE(surface.error(), QAbstractVideoSurface::IncorrectFormatError); |
555 | } |
556 | |
557 | #if QT_CONFIG(opengl) |
558 | |
559 | void tst_QPainterVideoSurface::shaderType() |
560 | { |
561 | QPainterVideoSurface surface; |
562 | QOpenGLWidget widget; |
563 | widget.show(); |
564 | |
565 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
566 | |
567 | if (!widget.context() || !widget.context()->isValid()) |
568 | QSKIP("Platform does not support OpenGLContext" ); |
569 | |
570 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
571 | QCOMPARE(surface.supportedShaderTypes(), QPainterVideoSurface::NoShaders); |
572 | |
573 | widget.makeCurrent(); |
574 | surface.updateGLContext(); |
575 | QCOMPARE(surface.glContext(), widget.context()); |
576 | |
577 | { |
578 | QSignalSpy spy(&surface, SIGNAL(supportedFormatsChanged())); |
579 | |
580 | surface.setShaderType(QPainterVideoSurface::NoShaders); |
581 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
582 | QCOMPARE(spy.count(), 0); |
583 | } |
584 | |
585 | #if !defined(QT_OPENGL_ES) |
586 | if (surface.supportedShaderTypes() & QPainterVideoSurface::FragmentProgramShader) { |
587 | QSignalSpy spy(&surface, SIGNAL(supportedFormatsChanged())); |
588 | |
589 | surface.setShaderType(QPainterVideoSurface::FragmentProgramShader); |
590 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::FragmentProgramShader); |
591 | QCOMPARE(spy.count(), 1); |
592 | |
593 | surface.setShaderType(QPainterVideoSurface::FragmentProgramShader); |
594 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::FragmentProgramShader); |
595 | QCOMPARE(spy.count(), 1); |
596 | } |
597 | #endif |
598 | |
599 | if (surface.supportedShaderTypes() & QPainterVideoSurface::GlslShader) { |
600 | QSignalSpy spy(&surface, SIGNAL(supportedFormatsChanged())); |
601 | |
602 | surface.setShaderType(QPainterVideoSurface::GlslShader); |
603 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::GlslShader); |
604 | QCOMPARE(spy.count(), 1); |
605 | |
606 | surface.setShaderType(QPainterVideoSurface::GlslShader); |
607 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::GlslShader); |
608 | QCOMPARE(spy.count(), 1); |
609 | } |
610 | |
611 | { |
612 | QSignalSpy spy(&surface, SIGNAL(supportedFormatsChanged())); |
613 | |
614 | widget.makeCurrent(); |
615 | surface.updateGLContext(); |
616 | QCOMPARE(surface.glContext(), widget.context()); |
617 | QCOMPARE(spy.count(), 0); |
618 | } |
619 | |
620 | widget.doneCurrent(); |
621 | surface.updateGLContext(); |
622 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
623 | QCOMPARE(surface.supportedShaderTypes(), QPainterVideoSurface::NoShaders); |
624 | |
625 | { |
626 | QSignalSpy spy(&surface, SIGNAL(supportedFormatsChanged())); |
627 | |
628 | surface.setShaderType(QPainterVideoSurface::NoShaders); |
629 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
630 | QCOMPARE(spy.count(), 0); |
631 | |
632 | #if !defined(QT_OPENGL_ES) |
633 | surface.setShaderType(QPainterVideoSurface::FragmentProgramShader); |
634 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
635 | QCOMPARE(spy.count(), 0); |
636 | #endif |
637 | |
638 | surface.setShaderType(QPainterVideoSurface::GlslShader); |
639 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
640 | QCOMPARE(spy.count(), 0); |
641 | } |
642 | } |
643 | |
644 | void tst_QPainterVideoSurface::shaderTypeStarted_data() |
645 | { |
646 | QTest::addColumn<QPainterVideoSurface::ShaderType>(name: "shaderType" ); |
647 | |
648 | #if !defined(QT_OPENGL_ES) |
649 | QTest::newRow(dataTag: "ARBfp" ) |
650 | << QPainterVideoSurface::FragmentProgramShader; |
651 | #endif |
652 | QTest::newRow(dataTag: "GLSL" ) |
653 | << QPainterVideoSurface::GlslShader; |
654 | } |
655 | |
656 | void tst_QPainterVideoSurface::shaderTypeStarted() |
657 | { |
658 | QFETCH(QPainterVideoSurface::ShaderType, shaderType); |
659 | |
660 | QOpenGLWidget widget; |
661 | widget.show(); |
662 | |
663 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
664 | |
665 | if (!widget.context() || !widget.context()->isValid()) |
666 | QSKIP("Platform does not support OpenGLContext" ); |
667 | |
668 | QPainterVideoSurface surface; |
669 | |
670 | widget.makeCurrent(); |
671 | surface.updateGLContext(); |
672 | |
673 | if (!(surface.supportedShaderTypes() & shaderType)) |
674 | QSKIP("Shader type unsupported on this platform" ); |
675 | |
676 | surface.setShaderType(shaderType); |
677 | QCOMPARE(surface.shaderType(), shaderType); |
678 | |
679 | QVERIFY(surface.start(QVideoSurfaceFormat(QSize(640, 480), QVideoFrame::Format_RGB32))); |
680 | { |
681 | QSignalSpy spy(&surface, SIGNAL(activeChanged(bool))); |
682 | |
683 | surface.setShaderType(QPainterVideoSurface::NoShaders); |
684 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
685 | QCOMPARE(surface.isActive(), false); |
686 | QCOMPARE(spy.count(), 1); |
687 | QCOMPARE(spy.last().value(0).toBool(), false); |
688 | } |
689 | |
690 | QVERIFY(surface.start(QVideoSurfaceFormat(QSize(640, 480), QVideoFrame::Format_RGB32))); |
691 | { |
692 | QSignalSpy spy(&surface, SIGNAL(activeChanged(bool))); |
693 | |
694 | surface.setShaderType(QPainterVideoSurface::NoShaders); |
695 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
696 | QCOMPARE(surface.isActive(), true); |
697 | QCOMPARE(spy.count(), 0); |
698 | |
699 | surface.setShaderType(shaderType); |
700 | QCOMPARE(surface.shaderType(), shaderType); |
701 | QCOMPARE(surface.isActive(), false); |
702 | QCOMPARE(spy.count(), 1); |
703 | QCOMPARE(spy.last().value(0).toBool(), false); |
704 | } |
705 | |
706 | QVERIFY(surface.start(QVideoSurfaceFormat(QSize(640, 480), QVideoFrame::Format_RGB32))); |
707 | { |
708 | QSignalSpy spy(&surface, SIGNAL(activeChanged(bool))); |
709 | |
710 | surface.setShaderType(shaderType); |
711 | QCOMPARE(surface.shaderType(), shaderType); |
712 | QCOMPARE(surface.isActive(), true); |
713 | QCOMPARE(spy.count(), 0); |
714 | |
715 | widget.doneCurrent(); |
716 | surface.updateGLContext(); |
717 | QCOMPARE(surface.shaderType(), QPainterVideoSurface::NoShaders); |
718 | QCOMPARE(surface.isActive(), false); |
719 | QCOMPARE(spy.count(), 1); |
720 | QCOMPARE(spy.last().value(0).toBool(), false); |
721 | } |
722 | } |
723 | |
724 | void tst_QPainterVideoSurface::shaderSupportedFormat_data() |
725 | { |
726 | QTest::addColumn<QPainterVideoSurface::ShaderType>(name: "shaderType" ); |
727 | QTest::addColumn<QAbstractVideoBuffer::HandleType>(name: "handleType" ); |
728 | QTest::addColumn<QVideoFrame::PixelFormat>(name: "pixelFormat" ); |
729 | QTest::addColumn<QSize>(name: "frameSize" ); |
730 | QTest::addColumn<bool>(name: "supportedPixelFormat" ); |
731 | QTest::addColumn<bool>(name: "supportedFormat" ); |
732 | |
733 | const QPair<QPainterVideoSurface::ShaderType, QByteArray> types[] = { |
734 | #if !defined(QT_OPENGL_ES) |
735 | qMakePair(x: QPainterVideoSurface::FragmentProgramShader, y: QByteArray("ARBfp: " )), |
736 | #endif |
737 | qMakePair(x: QPainterVideoSurface::GlslShader, y: QByteArray("GLSL: " )), |
738 | }; |
739 | |
740 | for (const auto &type : types) { |
741 | QTest::newRow(dataTag: (type.second + "rgb32 640x480" ).constData()) |
742 | << type.first |
743 | << QAbstractVideoBuffer::NoHandle |
744 | << QVideoFrame::Format_RGB32 |
745 | << QSize(640, 480) |
746 | << true |
747 | << true; |
748 | QTest::newRow(dataTag: (type.second + "rgb32 -640x480" ).constData()) |
749 | << type.first |
750 | << QAbstractVideoBuffer::NoHandle |
751 | << QVideoFrame::Format_RGB32 |
752 | << QSize(-640, 480) |
753 | << true |
754 | << false; |
755 | QTest::newRow(dataTag: (type.second + "rgb565 32x32" ).constData()) |
756 | << type.first |
757 | << QAbstractVideoBuffer::NoHandle |
758 | << QVideoFrame::Format_RGB565 |
759 | << QSize(32, 32) |
760 | << true |
761 | << true; |
762 | QTest::newRow(dataTag: (type.second + "rgb565 0x0" ).constData()) |
763 | << type.first |
764 | << QAbstractVideoBuffer::NoHandle |
765 | << QVideoFrame::Format_RGB565 |
766 | << QSize(0, 0) |
767 | << true |
768 | << false; |
769 | QTest::newRow(dataTag: (type.second + "argb32 256x256" ).constData()) |
770 | << type.first |
771 | << QAbstractVideoBuffer::NoHandle |
772 | << QVideoFrame::Format_ARGB32 |
773 | << QSize(256, 256) |
774 | << true |
775 | << true; |
776 | QTest::newRow(dataTag: (type.second + "rgb24 1024x768" ).constData()) |
777 | << type.first |
778 | << QAbstractVideoBuffer::NoHandle |
779 | << QVideoFrame::Format_RGB24 |
780 | << QSize(1024, 768) |
781 | #if !defined(QT_OPENGL_ES) |
782 | << m_libGL |
783 | << m_libGL; |
784 | #else |
785 | << false |
786 | << false; |
787 | #endif |
788 | QTest::newRow(dataTag: (type.second + "rgb24 -1024x-768" ).constData()) |
789 | << type.first |
790 | << QAbstractVideoBuffer::NoHandle |
791 | << QVideoFrame::Format_RGB24 |
792 | << QSize(-1024, -768) |
793 | #if !defined(QT_OPENGL_ES) |
794 | << m_libGL |
795 | #else |
796 | << false |
797 | #endif |
798 | << false; |
799 | #ifndef Q_OS_MAC |
800 | QTest::newRow(dataTag: (type.second + "YUV420P 640x480" ).constData()) |
801 | << type.first |
802 | << QAbstractVideoBuffer::NoHandle |
803 | << QVideoFrame::Format_YUV420P |
804 | << QSize(640, 480) |
805 | << true |
806 | << true; |
807 | QTest::newRow(dataTag: (type.second + "YUV420P 640x-480" ).constData()) |
808 | << type.first |
809 | << QAbstractVideoBuffer::NoHandle |
810 | << QVideoFrame::Format_YUV420P |
811 | << QSize(640, -480) |
812 | << true |
813 | << false; |
814 | #endif |
815 | QTest::newRow(dataTag: (type.second + "Y8 640x480" ).constData()) |
816 | << type.first |
817 | << QAbstractVideoBuffer::NoHandle |
818 | << QVideoFrame::Format_Y8 |
819 | << QSize(640, 480) |
820 | << false |
821 | << false; |
822 | QTest::newRow(dataTag: (type.second + "Texture: rgb32 640x480" ).constData()) |
823 | << type.first |
824 | << QAbstractVideoBuffer::GLTextureHandle |
825 | << QVideoFrame::Format_RGB32 |
826 | << QSize(640, 480) |
827 | << true |
828 | << true; |
829 | QTest::newRow(dataTag: (type.second + "Texture: rgb32 -640x480" ).constData()) |
830 | << type.first |
831 | << QAbstractVideoBuffer::GLTextureHandle |
832 | << QVideoFrame::Format_RGB32 |
833 | << QSize(-640, 480) |
834 | << true |
835 | << false; |
836 | #ifndef Q_OS_MAC |
837 | QTest::newRow(dataTag: (type.second + "Texture: rgb565 32x32" ).constData()) |
838 | << type.first |
839 | << QAbstractVideoBuffer::GLTextureHandle |
840 | << QVideoFrame::Format_RGB565 |
841 | << QSize(32, 32) |
842 | << false |
843 | << false; |
844 | QTest::newRow(dataTag: (type.second + "Texture: rgb565 0x0" ).constData()) |
845 | << type.first |
846 | << QAbstractVideoBuffer::GLTextureHandle |
847 | << QVideoFrame::Format_RGB565 |
848 | << QSize(0, 0) |
849 | << false |
850 | << false; |
851 | #endif |
852 | QTest::newRow(dataTag: (type.second + "Texture argb32 256x256" ).constData()) |
853 | << type.first |
854 | << QAbstractVideoBuffer::GLTextureHandle |
855 | << QVideoFrame::Format_ARGB32 |
856 | << QSize(256, 256) |
857 | << true |
858 | << true; |
859 | #ifndef Q_OS_MAC |
860 | QTest::newRow(dataTag: (type.second + "Texture: rgb24 1024x768" ).constData()) |
861 | << type.first |
862 | << QAbstractVideoBuffer::GLTextureHandle |
863 | << QVideoFrame::Format_RGB24 |
864 | << QSize(1024, 768) |
865 | << false |
866 | << false; |
867 | QTest::newRow(dataTag: (type.second + "Texture: rgb24 -1024x-768" ).constData()) |
868 | << type.first |
869 | << QAbstractVideoBuffer::GLTextureHandle |
870 | << QVideoFrame::Format_RGB24 |
871 | << QSize(-1024, -768) |
872 | << false |
873 | << false; |
874 | QTest::newRow(dataTag: (type.second + "Texture: YUV420P 640x480" ).constData()) |
875 | << type.first |
876 | << QAbstractVideoBuffer::GLTextureHandle |
877 | << QVideoFrame::Format_YUV420P |
878 | << QSize(640, 480) |
879 | << false |
880 | << false; |
881 | QTest::newRow(dataTag: (type.second + "Texture: YUV420P 640x-480" ).constData()) |
882 | << type.first |
883 | << QAbstractVideoBuffer::GLTextureHandle |
884 | << QVideoFrame::Format_YUV420P |
885 | << QSize(640, -480) |
886 | << false |
887 | << false; |
888 | #endif |
889 | QTest::newRow(dataTag: type.second + "User Buffer: rgb32 256x256" ) |
890 | << type.first |
891 | << QAbstractVideoBuffer::UserHandle |
892 | << QVideoFrame::Format_RGB32 |
893 | << QSize(256, 256) |
894 | << false |
895 | << false; |
896 | } |
897 | } |
898 | |
899 | void tst_QPainterVideoSurface::shaderSupportedFormat() |
900 | { |
901 | QFETCH(QPainterVideoSurface::ShaderType, shaderType); |
902 | QFETCH(QAbstractVideoBuffer::HandleType, handleType); |
903 | QFETCH(QVideoFrame::PixelFormat, pixelFormat); |
904 | QFETCH(QSize, frameSize); |
905 | QFETCH(bool, supportedPixelFormat); |
906 | QFETCH(bool, supportedFormat); |
907 | |
908 | QOpenGLWidget widget; |
909 | widget.show(); |
910 | |
911 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
912 | |
913 | if (!widget.context() || !widget.context()->isValid()) |
914 | QSKIP("Platform does not support GLContext" ); |
915 | |
916 | QPainterVideoSurface surface; |
917 | widget.makeCurrent(); |
918 | surface.updateGLContext(); |
919 | |
920 | |
921 | if (!(surface.supportedShaderTypes() & shaderType)) |
922 | QSKIP("Shader type not supported on this platform" ); |
923 | |
924 | surface.setShaderType(shaderType); |
925 | if (surface.shaderType() != shaderType) |
926 | QSKIP("Shader type couldn't be set" ); |
927 | |
928 | const QList<QVideoFrame::PixelFormat> pixelFormats = surface.supportedPixelFormats(handleType); |
929 | |
930 | QCOMPARE(pixelFormats.contains(pixelFormat), supportedPixelFormat); |
931 | |
932 | QVideoSurfaceFormat format(frameSize, pixelFormat, handleType); |
933 | |
934 | QCOMPARE(surface.isFormatSupported(format), supportedFormat); |
935 | QCOMPARE(surface.start(format), supportedFormat); |
936 | } |
937 | |
938 | void tst_QPainterVideoSurface::shaderPresent_data() |
939 | { |
940 | QTest::addColumn<QPainterVideoSurface::ShaderType>(name: "shaderType" ); |
941 | QTest::addColumn<QVideoFrame::PixelFormat>(name: "pixelFormatA" ); |
942 | QTest::addColumn<QSize>(name: "frameSizeA" ); |
943 | QTest::addColumn<const uchar *>(name: "frameDataA" ); |
944 | QTest::addColumn<int>(name: "bytesA" ); |
945 | QTest::addColumn<int>(name: "bytesPerLineA" ); |
946 | QTest::addColumn<QVideoFrame::PixelFormat>(name: "pixelFormatB" ); |
947 | QTest::addColumn<QSize>(name: "frameSizeB" ); |
948 | QTest::addColumn<const uchar *>(name: "frameDataB" ); |
949 | QTest::addColumn<int>(name: "bytesB" ); |
950 | QTest::addColumn<int>(name: "bytesPerLineB" ); |
951 | |
952 | const QPair<QPainterVideoSurface::ShaderType, QByteArray> types[] = { |
953 | #if !defined(QT_OPENGL_ES) |
954 | qMakePair(x: QPainterVideoSurface::FragmentProgramShader, y: QByteArray("ARBfp: " )), |
955 | #endif |
956 | qMakePair(x: QPainterVideoSurface::GlslShader, y: QByteArray("GLSL: " )), |
957 | }; |
958 | |
959 | for (const auto &type : types) { |
960 | QTest::newRow(dataTag: (type.second + "rgb32 -> argb32" ).constData()) |
961 | << type.first |
962 | << QVideoFrame::Format_RGB32 |
963 | << QSize(2, 2) |
964 | << static_cast<const uchar *>(rgb32ImageData) |
965 | << int(sizeof(rgb32ImageData)) |
966 | << 8 |
967 | << QVideoFrame::Format_ARGB32 |
968 | << QSize(2, 2) |
969 | << static_cast<const uchar *>(argb32ImageData) |
970 | << int(sizeof(argb32ImageData)) |
971 | << 8; |
972 | |
973 | QTest::newRow(dataTag: (type.second + "rgb32 -> rgb565" ).constData()) |
974 | << type.first |
975 | << QVideoFrame::Format_RGB32 |
976 | << QSize(2, 2) |
977 | << static_cast<const uchar *>(rgb32ImageData) |
978 | << int(sizeof(rgb32ImageData)) |
979 | << 8 |
980 | << QVideoFrame::Format_RGB565 |
981 | << QSize(2, 2) |
982 | << static_cast<const uchar *>(rgb565ImageData) |
983 | << int(sizeof(rgb565ImageData)) |
984 | << 4; |
985 | #ifndef Q_OS_MAC |
986 | QTest::newRow(dataTag: (type.second + "rgb32 -> yuv420p" ).constData()) |
987 | << type.first |
988 | << QVideoFrame::Format_RGB32 |
989 | << QSize(2, 2) |
990 | << static_cast<const uchar *>(rgb32ImageData) |
991 | << int(sizeof(rgb32ImageData)) |
992 | << 8 |
993 | << QVideoFrame::Format_YUV420P |
994 | << QSize(8, 8) |
995 | << static_cast<const uchar *>(yuvPlanarImageData) |
996 | << int(sizeof(yuvPlanarImageData)) |
997 | << 8; |
998 | |
999 | QTest::newRow(dataTag: (type.second + "yv12 -> rgb32" ).constData()) |
1000 | << type.first |
1001 | << QVideoFrame::Format_YV12 |
1002 | << QSize(8, 8) |
1003 | << static_cast<const uchar *>(yuvPlanarImageData) |
1004 | << int(sizeof(yuvPlanarImageData)) |
1005 | << 8 |
1006 | << QVideoFrame::Format_RGB32 |
1007 | << QSize(2, 2) |
1008 | << static_cast<const uchar *>(rgb32ImageData) |
1009 | << int(sizeof(rgb32ImageData)) |
1010 | << 8; |
1011 | #endif |
1012 | } |
1013 | } |
1014 | |
1015 | void tst_QPainterVideoSurface::shaderPresent() |
1016 | { |
1017 | QFETCH(QPainterVideoSurface::ShaderType, shaderType); |
1018 | QFETCH(QVideoFrame::PixelFormat, pixelFormatA); |
1019 | QFETCH(QSize, frameSizeA); |
1020 | QFETCH(const uchar *, frameDataA); |
1021 | QFETCH(int, bytesA); |
1022 | QFETCH(int, bytesPerLineA); |
1023 | QFETCH(QVideoFrame::PixelFormat, pixelFormatB); |
1024 | QFETCH(QSize, frameSizeB); |
1025 | QFETCH(const uchar *, frameDataB); |
1026 | QFETCH(int, bytesB); |
1027 | QFETCH(int, bytesPerLineB); |
1028 | |
1029 | QOpenGLWidget widget; |
1030 | widget.show(); |
1031 | |
1032 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
1033 | |
1034 | if (!widget.context() || !widget.context()->isValid()) |
1035 | QSKIP("Platform does not support GLContext" ); |
1036 | |
1037 | QPainterVideoSurface surface; |
1038 | widget.makeCurrent(); |
1039 | surface.updateGLContext(); |
1040 | |
1041 | if (!(surface.supportedShaderTypes() & shaderType)) |
1042 | QSKIP("Shader type unsupported on this platform" ); |
1043 | |
1044 | surface.setShaderType(shaderType); |
1045 | if (surface.shaderType() != shaderType) |
1046 | QSKIP("Shader type couldn't be set" ); |
1047 | |
1048 | QSignalSpy frameSpy(&surface, SIGNAL(frameChanged())); |
1049 | |
1050 | { // Test painting before starting the surface. |
1051 | QPainter painter(&widget); |
1052 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1053 | } |
1054 | QCOMPARE(surface.error(), QAbstractVideoSurface::NoError); |
1055 | |
1056 | QVideoSurfaceFormat formatA(frameSizeA, pixelFormatA); |
1057 | |
1058 | QVERIFY(surface.start(formatA)); |
1059 | QCOMPARE(surface.isActive(), true); |
1060 | QCOMPARE(surface.isReady(), true); |
1061 | |
1062 | // Test painting before receiving a frame. |
1063 | { |
1064 | QPainter painter(&widget); |
1065 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1066 | } |
1067 | QCOMPARE(surface.isActive(), true); |
1068 | QCOMPARE(surface.isReady(), true); |
1069 | |
1070 | QVideoFrame frameA(bytesA, frameSizeA, bytesPerLineA, pixelFormatA); |
1071 | |
1072 | frameA.map(mode: QAbstractVideoBuffer::WriteOnly); |
1073 | memcpy(dest: frameA.bits(), src: frameDataA, n: frameA.mappedBytes()); |
1074 | frameA.unmap(); |
1075 | |
1076 | QVERIFY(surface.present(frameA)); |
1077 | QCOMPARE(surface.isReady(), false); |
1078 | QCOMPARE(frameSpy.count(), 1); |
1079 | |
1080 | { |
1081 | QPainter painter(&widget); |
1082 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1083 | } |
1084 | QCOMPARE(surface.isActive(), true); |
1085 | QCOMPARE(surface.isReady(), false); |
1086 | |
1087 | { // Test repainting before receiving another frame. |
1088 | QPainter painter(&widget); |
1089 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1090 | } |
1091 | QCOMPARE(surface.isActive(), true); |
1092 | QCOMPARE(surface.isReady(), false); |
1093 | |
1094 | // If present() fails for any other reason the surface should immediately enter the stopped state |
1095 | // and an error() value will be set. |
1096 | QVERIFY(surface.present(frameA)); |
1097 | QCOMPARE(frameSpy.count(), 1); |
1098 | |
1099 | surface.setReady(true); |
1100 | QCOMPARE(surface.isReady(), true); |
1101 | QVERIFY(surface.present(frameA)); |
1102 | QCOMPARE(frameSpy.count(), 2); |
1103 | |
1104 | // Try switching to a different format after starting. |
1105 | QVideoSurfaceFormat formatB(frameSizeB, pixelFormatB); |
1106 | |
1107 | QVERIFY(surface.start(formatB)); |
1108 | QCOMPARE(surface.isActive(), true); |
1109 | QCOMPARE(surface.isReady(), true); |
1110 | |
1111 | QVideoFrame frameB(bytesB, frameSizeB, bytesPerLineB, pixelFormatB); |
1112 | |
1113 | frameB.map(mode: QAbstractVideoBuffer::WriteOnly); |
1114 | memcpy(dest: frameB.bits(), src: frameDataB, n: frameB.mappedBytes()); |
1115 | frameB.unmap(); |
1116 | |
1117 | QVERIFY(surface.present(frameB)); |
1118 | QCOMPARE(surface.isReady(), false); |
1119 | QCOMPARE(frameSpy.count(), 3); |
1120 | |
1121 | { |
1122 | QPainter painter(&widget); |
1123 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1124 | } |
1125 | QCOMPARE(surface.isActive(), true); |
1126 | |
1127 | surface.stop(); |
1128 | QCOMPARE(surface.isActive(), false); |
1129 | QCOMPARE(surface.isReady(), false); |
1130 | |
1131 | // Try presenting a frame while stopped. |
1132 | QVERIFY(!surface.present(frameB)); |
1133 | QCOMPARE(surface.isReady(), false); |
1134 | QCOMPARE(surface.error(), QAbstractVideoSurface::StoppedError); |
1135 | |
1136 | // Try stopping while already stopped. |
1137 | surface.stop(); |
1138 | QCOMPARE(surface.isActive(), false); |
1139 | QCOMPARE(surface.isReady(), false); |
1140 | |
1141 | // Try presenting a frame with a different format. |
1142 | QVERIFY(surface.start(formatB)); |
1143 | QVERIFY(!surface.present(frameA)); |
1144 | QCOMPARE(surface.isActive(), false); |
1145 | QCOMPARE(surface.isReady(), false); |
1146 | QCOMPARE(surface.error(), QAbstractVideoSurface::IncorrectFormatError); |
1147 | } |
1148 | |
1149 | void tst_QPainterVideoSurface::shaderPresentOpaqueFrame_data() |
1150 | { |
1151 | QTest::addColumn<QPainterVideoSurface::ShaderType>(name: "shaderType" ); |
1152 | |
1153 | #if !defined(QT_OPENGL_ES) |
1154 | QTest::newRow(dataTag: "ARBfp" ) |
1155 | << QPainterVideoSurface::FragmentProgramShader; |
1156 | #endif |
1157 | QTest::newRow(dataTag: "GLSL" ) |
1158 | << QPainterVideoSurface::GlslShader; |
1159 | } |
1160 | |
1161 | void tst_QPainterVideoSurface::shaderPresentOpaqueFrame() |
1162 | { |
1163 | QFETCH(QPainterVideoSurface::ShaderType, shaderType); |
1164 | |
1165 | QOpenGLWidget widget; |
1166 | widget.show(); |
1167 | |
1168 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
1169 | |
1170 | if (!widget.context() || !widget.context()->isValid()) |
1171 | QSKIP("Platform does not support GLContext" ); |
1172 | |
1173 | QPainterVideoSurface surface; |
1174 | widget.makeCurrent(); |
1175 | surface.updateGLContext(); |
1176 | |
1177 | if (!(surface.supportedShaderTypes() & shaderType)) |
1178 | QSKIP("Shader type unsupported on this platform" ); |
1179 | |
1180 | surface.setShaderType(shaderType); |
1181 | if (surface.shaderType() != shaderType) |
1182 | QSKIP("Shader type couldn't be set" ); |
1183 | |
1184 | QVideoSurfaceFormat format(QSize(64, 64), QVideoFrame::Format_RGB32); |
1185 | |
1186 | QVERIFY(surface.start(format)); |
1187 | QCOMPARE(surface.isActive(), true); |
1188 | QCOMPARE(surface.isReady(), true); |
1189 | |
1190 | QVideoFrame frame(new QtTestOpaqueVideoBuffer, QSize(64, 64), QVideoFrame::Format_RGB32); |
1191 | |
1192 | if (surface.present(frame)) { |
1193 | QPainter painter(&widget); |
1194 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1195 | } |
1196 | |
1197 | QCOMPARE(surface.isActive(), false); |
1198 | QCOMPARE(surface.isReady(), false); |
1199 | QCOMPARE(surface.error(), QAbstractVideoSurface::IncorrectFormatError); |
1200 | } |
1201 | |
1202 | void tst_QPainterVideoSurface::shaderPresentGLFrame_data() |
1203 | { |
1204 | QTest::addColumn<QPainterVideoSurface::ShaderType>(name: "shaderType" ); |
1205 | |
1206 | #if !defined(QT_OPENGL_ES) |
1207 | QTest::newRow(dataTag: "ARBfp" ) |
1208 | << QPainterVideoSurface::FragmentProgramShader; |
1209 | #endif |
1210 | QTest::newRow(dataTag: "GLSL" ) |
1211 | << QPainterVideoSurface::GlslShader; |
1212 | } |
1213 | |
1214 | void tst_QPainterVideoSurface::shaderPresentGLFrame() |
1215 | { |
1216 | QFETCH(QPainterVideoSurface::ShaderType, shaderType); |
1217 | |
1218 | QOpenGLWidget widget; |
1219 | widget.show(); |
1220 | |
1221 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
1222 | |
1223 | if (!widget.context() || !widget.context()->isValid()) |
1224 | QSKIP("Platform does not support GLContext" ); |
1225 | |
1226 | QPainterVideoSurface surface; |
1227 | widget.makeCurrent(); |
1228 | surface.updateGLContext(); |
1229 | |
1230 | if (!(surface.supportedShaderTypes() & shaderType)) |
1231 | QSKIP("Shader type unsupported on this platform" ); |
1232 | |
1233 | surface.setShaderType(shaderType); |
1234 | if (surface.shaderType() != shaderType) |
1235 | QSKIP("Shader type couldn't be set" ); |
1236 | |
1237 | QVideoSurfaceFormat format( |
1238 | QSize(2, 2), QVideoFrame::Format_RGB32, QAbstractVideoBuffer::GLTextureHandle); |
1239 | |
1240 | QVERIFY(surface.start(format)); |
1241 | QCOMPARE(surface.isActive(), true); |
1242 | QCOMPARE(surface.isReady(), true); |
1243 | |
1244 | QtTestGLVideoBuffer *buffer = new QtTestGLVideoBuffer; |
1245 | |
1246 | QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); |
1247 | f->glBindTexture(GL_TEXTURE_2D, texture: buffer->textureId()); |
1248 | f->glTexImage2D(GL_TEXTURE_2D, level: 0, GL_RGB, width: 2, height: 2, border: 0, GL_RGB, GL_UNSIGNED_BYTE, pixels: rgb32ImageData); |
1249 | f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
1250 | f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
1251 | f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); |
1252 | f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); |
1253 | |
1254 | QVideoFrame frame(buffer, QSize(2, 2), QVideoFrame::Format_RGB32); |
1255 | |
1256 | QVERIFY(surface.present(frame)); |
1257 | |
1258 | { |
1259 | QPainter painter(&widget); |
1260 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1261 | } |
1262 | |
1263 | QCOMPARE(surface.isActive(), true); |
1264 | QCOMPARE(surface.isReady(), false); |
1265 | |
1266 | { |
1267 | QPainter painter(&widget); |
1268 | surface.paint(painter: &painter, target: QRect(0, 0, 320, 240)); |
1269 | } |
1270 | |
1271 | QCOMPARE(surface.isActive(), true); |
1272 | QCOMPARE(surface.isReady(), false); |
1273 | } |
1274 | |
1275 | #endif |
1276 | |
1277 | QTEST_MAIN(tst_QPainterVideoSurface) |
1278 | |
1279 | #include "tst_qpaintervideosurface.moc" |
1280 | |