summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt3
-rw-r--r--tests/auto/CMakeLists.txt7
-rw-r--r--tests/auto/cmake/CMakeLists.txt14
-rw-r--r--tests/auto/integration/CMakeLists.txt10
-rw-r--r--tests/auto/integration/backends/CMakeLists.txt9
-rw-r--r--tests/auto/integration/backends/tst_backends.cpp60
-rw-r--r--tests/auto/integration/multiapp/CMakeLists.txt21
-rw-r--r--tests/auto/integration/multiapp/double-drop.wavbin0 -> 20626 bytes
-rw-r--r--tests/auto/integration/multiapp/tst_multiapp.cpp161
-rw-r--r--tests/auto/integration/qaudiodecoderbackend/CMakeLists.txt17
-rw-r--r--tests/auto/integration/qaudiodecoderbackend/testdata/test-no-audio-track.mp4bin0 -> 1589 bytes
-rw-r--r--tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp566
-rw-r--r--tests/auto/integration/qaudiodevice/CMakeLists.txt5
-rw-r--r--tests/auto/integration/qaudiodevice/tst_qaudiodevice.cpp49
-rw-r--r--tests/auto/integration/qaudiosink/BLACKLIST12
-rw-r--r--tests/auto/integration/qaudiosink/CMakeLists.txt5
-rw-r--r--tests/auto/integration/qaudiosink/tst_qaudiosink.cpp587
-rw-r--r--tests/auto/integration/qaudiosource/CMakeLists.txt5
-rw-r--r--tests/auto/integration/qaudiosource/tst_qaudiosource.cpp238
-rw-r--r--tests/auto/integration/qcamerabackend/BLACKLIST1
-rw-r--r--tests/auto/integration/qcamerabackend/CMakeLists.txt10
-rw-r--r--tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp253
-rw-r--r--tests/auto/integration/qmediacapturesession/BLACKLIST1
-rw-r--r--tests/auto/integration/qmediacapturesession/CMakeLists.txt8
-rw-r--r--tests/auto/integration/qmediacapturesession/tst_qmediacapturesession.cpp638
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/CMakeLists.txt22
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.cpp88
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.h49
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/framegenerator.cpp148
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/framegenerator.h82
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/mediainfo.h96
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.cpp411
-rw-r--r--tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.h47
-rw-r--r--tests/auto/integration/qmediaplayerbackend/BLACKLIST1
-rw-r--r--tests/auto/integration/qmediaplayerbackend/CMakeLists.txt35
-rw-r--r--tests/auto/integration/qmediaplayerbackend/LazyLoad.qml52
-rw-r--r--tests/auto/integration/qmediaplayerbackend/fake.h29
-rw-r--r--tests/auto/integration/qmediaplayerbackend/fixture.h95
-rw-r--r--tests/auto/integration/qmediaplayerbackend/mediaplayerstate.h167
-rw-r--r--tests/auto/integration/qmediaplayerbackend/server.h48
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/15s.mkvbin0 -> 61283 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/3colors_with_sound_1s.mp4bin0 -> 37261 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_jpg_thumbnail.mp4bin0 -> 37930 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_png_thumbnail.mp4bin0 -> 37436 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/busAv1.webmbin0 -> 16108 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/color_matrix.mp4bin0 -> 21412 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_180_deg_clockwise.mp4bin0 -> 21412 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_270_deg_clockwise.mp4bin0 -> 21412 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_90_deg_clockwise.mp4bin0 -> 21412 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/duration_issues.webmbin0 -> 34940 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/h264_avc1_yuv420p10le_tv_bt2020.movbin0 -> 20164 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/multitrack-subtitle-start-at-zero.mkvbin0 -> 153449 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/multitrack.mkvbin0 -> 153452 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/nokia-tune.mp3bin62715 -> 33988 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4bin0 -> 1589 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/par_2_3.mp4bin0 -> 1656 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/par_3_2.mp4bin0 -> 1652 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/subtitletest.mkvbin0 -> 17398 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp4128
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/CMakeLists.txt30
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/README.md35
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.avibin0 -> 11284 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mkvbin0 -> 3019 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mp4bin0 -> 3280 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mpegbin0 -> 34816 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.wmvbin0 -> 29587 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/containers/unsupported/container.webpbin0 -> 2676 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/flipable.gifbin0 -> 131710 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr0.mp4bin0 -> 12335 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr24.mp4bin0 -> 12335 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray.mp4bin0 -> 6289 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray10le.mp4bin0 -> 6326 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv12.mp4bin0 -> 7734 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv16.mp4bin0 -> 8646 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv21.mp4bin0 -> 7734 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_rgb24.mp4bin0 -> 12335 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p.mp4bin0 -> 7747 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10.mp4bin0 -> 7699 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10le.mp4bin0 -> 7699 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p.mp4bin0 -> 8646 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10.mp4bin0 -> 8675 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10le.mp4bin0 -> 8675 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p.mp4bin0 -> 7575 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p10.mp4bin0 -> 7549 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj420p.mp4bin0 -> 8081 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj422p.mp4bin0 -> 9059 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj444p.mp4bin0 -> 7939 bytes
-rw-r--r--tests/auto/integration/qmediaplayerformatsupport/tst_qmediaplayerformatsupport.cpp124
-rw-r--r--tests/auto/integration/qml/CMakeLists.txt5
-rw-r--r--tests/auto/integration/qml/soundeffect/tst_soundeffect.qml29
-rw-r--r--tests/auto/integration/qml/tst_qml.cpp29
-rw-r--r--tests/auto/integration/qquickvideooutput/CMakeLists.txt5
-rw-r--r--tests/auto/integration/qquickvideooutput/tst_qquickvideooutput.cpp61
-rw-r--r--tests/auto/integration/qquickvideooutput_window/CMakeLists.txt5
-rw-r--r--tests/auto/integration/qquickvideooutput_window/tst_qquickvideooutput_window.cpp31
-rw-r--r--tests/auto/integration/qscreencapturebackend/BLACKLIST11
-rw-r--r--tests/auto/integration/qscreencapturebackend/CMakeLists.txt17
-rw-r--r--tests/auto/integration/qscreencapturebackend/tst_qscreencapturebackend.cpp505
-rw-r--r--tests/auto/integration/qsoundeffect/CMakeLists.txt36
-rw-r--r--tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp91
-rw-r--r--tests/auto/integration/qvideoframebackend/CMakeLists.txt26
-rw-r--r--tests/auto/integration/qvideoframebackend/testdata/colors.mp4bin0 -> 26042 bytes
-rw-r--r--tests/auto/integration/qvideoframebackend/testdata/one_red_frame.mp4bin0 -> 1589 bytes
-rw-r--r--tests/auto/integration/qvideoframebackend/tst_qvideoframebackend.cpp264
-rw-r--r--tests/auto/integration/qwindowcapturebackend/BLACKLIST13
-rw-r--r--tests/auto/integration/qwindowcapturebackend/CMakeLists.txt20
-rw-r--r--tests/auto/integration/qwindowcapturebackend/fixture.cpp234
-rw-r--r--tests/auto/integration/qwindowcapturebackend/fixture.h147
-rw-r--r--tests/auto/integration/qwindowcapturebackend/grabber.cpp62
-rw-r--r--tests/auto/integration/qwindowcapturebackend/grabber.h43
-rw-r--r--tests/auto/integration/qwindowcapturebackend/tst_qwindowcapturebackend.cpp278
-rw-r--r--tests/auto/integration/qwindowcapturebackend/widget.cpp125
-rw-r--r--tests/auto/integration/qwindowcapturebackend/widget.h43
-rw-r--r--tests/auto/integration/shared/mediabackendutils.h69
-rw-r--r--tests/auto/integration/shared/mediafileselector.h200
-rw-r--r--tests/auto/integration/shared/testvideosink.h69
-rwxr-xr-xtests/auto/runautotests.py29
-rw-r--r--tests/auto/shared/qscopedenvironmentvariable.h29
-rw-r--r--tests/auto/unit/CMakeLists.txt3
-rw-r--r--tests/auto/unit/mockbackend/CMakeLists.txt47
-rw-r--r--tests/auto/unit/mockbackend/mock.json3
-rw-r--r--tests/auto/unit/mockbackend/qmockaudiodecoder.cpp139
-rw-r--r--tests/auto/unit/mockbackend/qmockaudiodecoder.h178
-rw-r--r--tests/auto/unit/mockbackend/qmockaudiooutput.h40
-rw-r--r--tests/auto/unit/mockbackend/qmockcamera.cpp158
-rw-r--r--tests/auto/unit/mockbackend/qmockcamera.h205
-rw-r--r--tests/auto/unit/mockbackend/qmockimagecapture.cpp39
-rw-r--r--tests/auto/unit/mockbackend/qmockimagecapture.h29
-rw-r--r--tests/auto/unit/mockbackend/qmockintegration.cpp182
-rw-r--r--tests/auto/unit/mockbackend/qmockintegration.h103
-rw-r--r--tests/auto/unit/mockbackend/qmockintegration_p.h113
-rw-r--r--tests/auto/unit/mockbackend/qmockmediacapturesession.h43
-rw-r--r--tests/auto/unit/mockbackend/qmockmediadevices.cpp91
-rw-r--r--tests/auto/unit/mockbackend/qmockmediadevices.h45
-rw-r--r--tests/auto/unit/mockbackend/qmockmediadevices_p.h83
-rw-r--r--tests/auto/unit/mockbackend/qmockmediaencoder.h49
-rw-r--r--tests/auto/unit/mockbackend/qmockmediaplayer.h62
-rw-r--r--tests/auto/unit/mockbackend/qmocksurfacecapture.h88
-rw-r--r--tests/auto/unit/mockbackend/qmockvideobuffer.h38
-rw-r--r--tests/auto/unit/mockbackend/qmockvideosink.h42
-rw-r--r--tests/auto/unit/multimedia/CMakeLists.txt22
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt15
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp309
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h49
-rw-r--r--tests/auto/unit/multimedia/qabstractvideobuffer/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp76
-rw-r--r--tests/auto/unit/multimedia/qaudiobuffer/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qaudiobuffer/tst_qaudiobuffer.cpp29
-rw-r--r--tests/auto/unit/multimedia/qaudiodecoder/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimedia/qaudiodecoder/tst_qaudiodecoder.cpp95
-rw-r--r--tests/auto/unit/multimedia/qaudioformat/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qaudioformat/tst_qaudioformat.cpp31
-rw-r--r--tests/auto/unit/multimedia/qaudionamespace/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qaudionamespace/tst_qaudionamespace.cpp33
-rw-r--r--tests/auto/unit/multimedia/qaudiorecorder/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimedia/qaudiorecorder/tst_qaudiorecorder.cpp39
-rw-r--r--tests/auto/unit/multimedia/qaudiostatemachine/CMakeLists.txt11
-rw-r--r--tests/auto/unit/multimedia/qaudiostatemachine/tst_qaudiostatemachine.cpp661
-rw-r--r--tests/auto/unit/multimedia/qcamera/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp169
-rw-r--r--tests/auto/unit/multimedia/qcameradevice/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp97
-rw-r--r--tests/auto/unit/multimedia/qerrorinfo/CMakeLists.txt10
-rw-r--r--tests/auto/unit/multimedia/qerrorinfo/tst_qerrorinfo.cpp117
-rw-r--r--tests/auto/unit/multimedia/qimagecapture/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimedia/qimagecapture/tst_qimagecapture.cpp86
-rw-r--r--tests/auto/unit/multimedia/qmaybe/CMakeLists.txt9
-rw-r--r--tests/auto/unit/multimedia/qmaybe/tst_qmaybe.cpp124
-rw-r--r--tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt18
-rw-r--r--tests/auto/unit/multimedia/qmediacapture_gstreamer/tst_qmediacapture_gstreamer.cpp212
-rw-r--r--tests/auto/unit/multimedia/qmediadevices/CMakeLists.txt13
-rw-r--r--tests/auto/unit/multimedia/qmediadevices/tst_qmediadevices.cpp58
-rw-r--r--tests/auto/unit/multimedia/qmediaformat/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qmediaformat/tst_qmediaformat.cpp29
-rw-r--r--tests/auto/unit/multimedia/qmediametadata/CMakeLists.txt13
-rw-r--r--tests/auto/unit/multimedia/qmediametadata/tst_qmediametadata.cpp96
-rw-r--r--tests/auto/unit/multimedia/qmediaplayer/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimedia/qmediaplayer/tst_qmediaplayer.cpp216
-rw-r--r--tests/auto/unit/multimedia/qmediaplayer_gstreamer/CMakeLists.txt32
-rw-r--r--tests/auto/unit/multimedia/qmediaplayer_gstreamer/testdata/color_matrix.mp4bin0 -> 21412 bytes
-rw-r--r--tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp153
-rw-r--r--tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.h46
-rw-r--r--tests/auto/unit/multimedia/qmediaplaylist/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qmediaplaylist/tst_qmediaplaylist.cpp31
-rw-r--r--tests/auto/unit/multimedia/qmediarecorder/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimedia/qmediarecorder/tst_qmediarecorder.cpp138
-rw-r--r--tests/auto/unit/multimedia/qmediatimerange/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qmediatimerange/tst_qmediatimerange.cpp45
-rw-r--r--tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt9
-rw-r--r--tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp184
-rw-r--r--tests/auto/unit/multimedia/qsamplecache/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qsamplecache/tst_qsamplecache.cpp31
-rw-r--r--tests/auto/unit/multimedia/qscreencapture/CMakeLists.txt18
-rw-r--r--tests/auto/unit/multimedia/qscreencapture/tst_qscreencapture.cpp64
-rw-r--r--tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt10
-rw-r--r--tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp256
-rw-r--r--tests/auto/unit/multimedia/qvideoframe/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp771
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/CMakeLists.txt18
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpgbin0 -> 12786 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video.pngbin0 -> 40978 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full.pngbin0 -> 40854 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video.pngbin0 -> 40904 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full.pngbin0 -> 40945 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video.pngbin0 -> 40959 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full.pngbin0 -> 40934 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video.pngbin0 -> 40934 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full.pngbin0 -> 40912 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video.pngbin0 -> 41004 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full.pngbin0 -> 40870 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video.pngbin0 -> 40924 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full.pngbin0 -> 40966 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video.pngbin0 -> 40975 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video.pngbin0 -> 40978 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full.pngbin0 -> 40854 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video.pngbin0 -> 40904 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full.pngbin0 -> 40945 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video.pngbin0 -> 40959 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full.pngbin0 -> 40912 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video.pngbin0 -> 40987 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full.pngbin0 -> 40877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video.pngbin0 -> 40918 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full.pngbin0 -> 40967 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video.pngbin0 -> 40961 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video.pngbin0 -> 40978 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full.pngbin0 -> 40854 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video.pngbin0 -> 40904 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full.pngbin0 -> 40945 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video.pngbin0 -> 40959 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video.pngbin0 -> 40978 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full.pngbin0 -> 40854 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video.pngbin0 -> 40904 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full.pngbin0 -> 40945 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video.pngbin0 -> 40959 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full.pngbin0 -> 40927 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full_cpu.pngbin0 -> 35927 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video.pngbin0 -> 40927 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video_cpu.pngbin0 -> 35927 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full.pngbin0 -> 40923 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full_cpu.pngbin0 -> 35936 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video.pngbin0 -> 40964 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video_cpu.pngbin0 -> 35927 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full.pngbin0 -> 40897 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full_cpu.pngbin0 -> 35887 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video.pngbin0 -> 40914 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video_cpu.pngbin0 -> 35881 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full.pngbin0 -> 40936 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full_cpu.pngbin0 -> 35887 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video.pngbin0 -> 40991 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video_cpu.pngbin0 -> 35933 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full.pngbin0 -> 40913 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full_cpu.pngbin0 -> 35941 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video.pngbin0 -> 40913 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video_cpu.pngbin0 -> 35941 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full.pngbin0 -> 40969 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full_cpu.pngbin0 -> 35925 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video.pngbin0 -> 40951 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video_cpu.pngbin0 -> 35968 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full.pngbin0 -> 40860 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full_cpu.pngbin0 -> 35857 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video.pngbin0 -> 40946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video_cpu.pngbin0 -> 35908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full.pngbin0 -> 40942 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full_cpu.pngbin0 -> 35857 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video.pngbin0 -> 40966 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video_cpu.pngbin0 -> 35945 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video_cpu.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full.pngbin0 -> 39859 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full_cpu.pngbin0 -> 36094 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video.pngbin0 -> 39859 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video_cpu.pngbin0 -> 36094 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full.pngbin0 -> 39864 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full_cpu.pngbin0 -> 36087 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video.pngbin0 -> 39919 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video_cpu.pngbin0 -> 36215 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full.pngbin0 -> 39789 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full_cpu.pngbin0 -> 36021 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video.pngbin0 -> 39890 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video_cpu.pngbin0 -> 36258 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full.pngbin0 -> 39879 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full_cpu.pngbin0 -> 36021 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video.pngbin0 -> 39951 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video_cpu.pngbin0 -> 36189 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video.pngbin0 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video_cpu.pngbin0 -> 36154 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full.pngbin0 -> 25240 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full_cpu.pngbin0 -> 23434 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video.pngbin0 -> 25240 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video_cpu.pngbin0 -> 23434 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full.pngbin0 -> 25544 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full_cpu.pngbin0 -> 23596 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video.pngbin0 -> 24030 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video_cpu.pngbin0 -> 22241 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full.pngbin0 -> 25557 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full_cpu.pngbin0 -> 23545 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video.pngbin0 -> 23884 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video_cpu.pngbin0 -> 22208 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full.pngbin0 -> 25557 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full_cpu.pngbin0 -> 23545 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video.pngbin0 -> 24021 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video_cpu.pngbin0 -> 22392 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full.pngbin0 -> 25364 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full_cpu.pngbin0 -> 23481 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video.pngbin0 -> 25364 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video_cpu.pngbin0 -> 23481 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full.pngbin0 -> 25430 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full_cpu.pngbin0 -> 23425 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video.pngbin0 -> 23981 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video_cpu.pngbin0 -> 22350 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full.pngbin0 -> 25497 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full_cpu.pngbin0 -> 23568 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video.pngbin0 -> 23904 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video_cpu.pngbin0 -> 22203 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full.pngbin0 -> 25497 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full_cpu.pngbin0 -> 23568 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video.pngbin0 -> 23979 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video_cpu.pngbin0 -> 22331 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_full.pngbin0 -> 40919 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_video.pngbin0 -> 40919 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_full.pngbin0 -> 40952 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_video.pngbin0 -> 40967 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_full.pngbin0 -> 40881 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_video.pngbin0 -> 40962 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_full.pngbin0 -> 40954 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_video.pngbin0 -> 40987 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video.pngbin0 -> 40978 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full.pngbin0 -> 40854 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video.pngbin0 -> 40904 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full.pngbin0 -> 40945 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video.pngbin0 -> 40959 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full.pngbin0 -> 41163 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full_cpu.pngbin0 -> 36094 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video.pngbin0 -> 41163 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video_cpu.pngbin0 -> 36094 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full.pngbin0 -> 41160 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full_cpu.pngbin0 -> 36087 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video.pngbin0 -> 41199 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video_cpu.pngbin0 -> 36215 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full.pngbin0 -> 41000 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full_cpu.pngbin0 -> 36021 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video.pngbin0 -> 41177 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video_cpu.pngbin0 -> 36258 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full.pngbin0 -> 41183 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full_cpu.pngbin0 -> 36021 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video.pngbin0 -> 41209 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video_cpu.pngbin0 -> 36189 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full.pngbin0 -> 39859 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full_cpu.pngbin0 -> 36094 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video.pngbin0 -> 39859 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video_cpu.pngbin0 -> 36094 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full.pngbin0 -> 39864 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full_cpu.pngbin0 -> 36087 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video.pngbin0 -> 39919 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video_cpu.pngbin0 -> 36215 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full.pngbin0 -> 39789 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full_cpu.pngbin0 -> 36021 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video.pngbin0 -> 39890 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video_cpu.pngbin0 -> 36258 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full.pngbin0 -> 39879 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full_cpu.pngbin0 -> 36021 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video.pngbin0 -> 39951 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video_cpu.pngbin0 -> 36189 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video.pngbin0 -> 40898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video_cpu.pngbin0 -> 35874 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full.pngbin0 -> 40908 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full_cpu.pngbin0 -> 35882 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video.pngbin0 -> 40978 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video_cpu.pngbin0 -> 35946 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full.pngbin0 -> 40854 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video.pngbin0 -> 40904 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video_cpu.pngbin0 -> 35900 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full.pngbin0 -> 40945 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full_cpu.pngbin0 -> 35877 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video.pngbin0 -> 40959 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video_cpu.pngbin0 -> 35898 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/tst_qvideoframecolormanagement.cpp475
-rw-r--r--tests/auto/unit/multimedia/qvideoframeformat/CMakeLists.txt5
-rw-r--r--tests/auto/unit/multimedia/qvideoframeformat/tst_qvideoframeformat.cpp108
-rw-r--r--tests/auto/unit/multimedia/qvideotexturehelper/CMakeLists.txt10
-rw-r--r--tests/auto/unit/multimedia/qvideotexturehelper/tst_qvideotexturehelper.cpp260
-rw-r--r--tests/auto/unit/multimedia/qwavedecoder/CMakeLists.txt5
-rwxr-xr-xtests/auto/unit/multimedia/qwavedecoder/data/gendata.sh29
-rw-r--r--tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_even_bext.wavbin0 -> 2064 bytes
-rw-r--r--tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_odd_bext.wavbin0 -> 2064 bytes
-rw-r--r--tests/auto/unit/multimedia/qwavedecoder/tst_qwavedecoder.cpp117
-rw-r--r--tests/auto/unit/multimediawidgets/CMakeLists.txt3
-rw-r--r--tests/auto/unit/multimediawidgets/qcamerawidgets/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimediawidgets/qcamerawidgets/tst_qcamerawidgets.cpp41
-rw-r--r--tests/auto/unit/multimediawidgets/qgraphicsvideoitem/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimediawidgets/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp45
-rw-r--r--tests/auto/unit/multimediawidgets/qmediaplayerwidgets/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimediawidgets/qmediaplayerwidgets/tst_qmediaplayerwidgets.cpp66
-rw-r--r--tests/auto/unit/multimediawidgets/qvideowidget/BLACKLIST3
-rw-r--r--tests/auto/unit/multimediawidgets/qvideowidget/CMakeLists.txt7
-rw-r--r--tests/auto/unit/multimediawidgets/qvideowidget/tst_qvideowidget.cpp80
-rw-r--r--tests/manual/CMakeLists.txt22
-rw-r--r--tests/manual/audiodecoder/CMakeLists.txt45
-rw-r--r--tests/manual/audiodecoder/audiodecoder.cpp162
-rw-r--r--tests/manual/audiodecoder/audiodecoder.h55
-rw-r--r--tests/manual/audiodecoder/audiodecoder.pro13
-rw-r--r--tests/manual/audiodecoder/main.cpp83
-rw-r--r--tests/manual/devices/CMakeLists.txt40
-rw-r--r--tests/manual/devices/devices.pro12
-rw-r--r--tests/manual/devices/main.cpp136
-rw-r--r--tests/manual/gstreamer-custom-camera-rtp/CMakeLists.txt39
-rw-r--r--tests/manual/gstreamer-custom-camera-rtp/Info.plist.in46
-rw-r--r--tests/manual/gstreamer-custom-camera-rtp/gstreamer-custom-camera-rtp.cpp57
-rw-r--r--tests/manual/gstreamer-custom-camera/CMakeLists.txt37
-rw-r--r--tests/manual/gstreamer-custom-camera/Info.plist.in46
-rw-r--r--tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp50
-rw-r--r--tests/manual/mediaformats/CMakeLists.txt37
-rw-r--r--tests/manual/mediaformats/main.cpp87
-rw-r--r--tests/manual/minimal-player/CMakeLists.txt35
-rw-r--r--tests/manual/minimal-player/Info.plist.in46
-rw-r--r--tests/manual/minimal-player/minimal-player.cpp94
-rw-r--r--tests/manual/qml-gstreamer-rtp/CMakeLists.txt42
-rw-r--r--tests/manual/qml-gstreamer-rtp/Info.plist.in46
-rw-r--r--tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.cpp32
-rw-r--r--tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.qml29
-rw-r--r--tests/manual/qml-minimal-camera/CMakeLists.txt42
-rw-r--r--tests/manual/qml-minimal-camera/Info.plist.in46
-rw-r--r--tests/manual/qml-minimal-camera/qml-minimal-camera.cpp17
-rw-r--r--tests/manual/qml-minimal-camera/qml-minimal-camera.qml34
-rw-r--r--tests/manual/qml-minimal-player/CMakeLists.txt42
-rw-r--r--tests/manual/qml-minimal-player/Info.plist.in46
-rw-r--r--tests/manual/qml-minimal-player/qml-minimal-player.cpp17
-rw-r--r--tests/manual/qml-minimal-player/qml-minimal-player.qml42
-rw-r--r--tests/manual/wasm/CMakeLists.txt6
-rw-r--r--tests/manual/wasm/camera/CMakeLists.txt42
-rw-r--r--tests/manual/wasm/camera/camera-test.pro69
-rw-r--r--tests/manual/wasm/camera/main.cpp17
-rw-r--r--tests/manual/wasm/camera/mainwindow.cpp261
-rw-r--r--tests/manual/wasm/camera/mainwindow.h53
-rw-r--r--tests/manual/wasm/camera/mainwindow.ui107
-rw-r--r--tests/systemtests/audio_playback/sys_audio.qtt374
-rw-r--r--tests/systemtests/audio_recording/sys_audio_recording.qtt64
-rw-r--r--tests/systemtests/radio/sys_radio.qtt286
-rw-r--r--tests/systemtests/still_camera/sys_camera.qtt162
-rw-r--r--tests/systemtests/video_playback/sys_video.qtt180
672 files changed, 16720 insertions, 4913 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 221413713..800bc265b 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from tests.pro.
if(QT_BUILD_STANDALONE_TESTS)
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index 7a402f847..66b291222 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -1,7 +1,6 @@
-# Generated from auto.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+add_subdirectory(cmake)
add_subdirectory(unit)
add_subdirectory(integration)
-# special case begin
-# add_subdirectory(cmake)
-# special case end
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
index 62b88dcc1..6e556ff93 100644
--- a/tests/auto/cmake/CMakeLists.txt
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -1,24 +1,26 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
-
-project(qmake_cmake_files)
+project(qtmultimedia_cmake_tests)
enable_testing()
-find_package(Qt5Core REQUIRED)
+find_package(Qt6 REQUIRED COMPONENTS Core)
+find_package(Qt6 OPTIONAL_COMPONENTS Widgets)
-include("${_Qt5CTestMacros}")
+include("${_Qt6CTestMacros}")
set(qt_module_includes
Multimedia QCamera
)
-if (NOT NO_WIDGETS)
+if(TARGET Qt6::Widgets)
list(APPEND qt_module_includes
MultimediaWidgets QVideoWidget
)
endif()
-test_module_includes(
+_qt_internal_test_module_includes(
${qt_module_includes}
)
diff --git a/tests/auto/integration/CMakeLists.txt b/tests/auto/integration/CMakeLists.txt
index 3f27496cb..9be80db63 100644
--- a/tests/auto/integration/CMakeLists.txt
+++ b/tests/auto/integration/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from integration.pro.
# special case begin
@@ -6,10 +9,17 @@ add_subdirectory(qaudiodevice)
add_subdirectory(qaudiosource)
add_subdirectory(qaudiosink)
add_subdirectory(qmediaplayerbackend)
+add_subdirectory(qmediaplayerformatsupport)
add_subdirectory(qsoundeffect)
+add_subdirectory(qvideoframebackend)
+add_subdirectory(backends)
+add_subdirectory(multiapp)
+add_subdirectory(qmediaframeinputsbackend)
if(TARGET Qt::Widgets)
add_subdirectory(qmediacapturesession)
add_subdirectory(qcamerabackend)
+ add_subdirectory(qscreencapturebackend)
+ add_subdirectory(qwindowcapturebackend)
endif()
if(TARGET Qt::Quick)
add_subdirectory(qquickvideooutput)
diff --git a/tests/auto/integration/backends/CMakeLists.txt b/tests/auto/integration/backends/CMakeLists.txt
new file mode 100644
index 000000000..b65293b5e
--- /dev/null
+++ b/tests/auto/integration/backends/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_backends
+ SOURCES
+ tst_backends.cpp
+ LIBRARIES
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/integration/backends/tst_backends.cpp b/tests/auto/integration/backends/tst_backends.cpp
new file mode 100644
index 000000000..2cc1df256
--- /dev/null
+++ b/tests/auto/integration/backends/tst_backends.cpp
@@ -0,0 +1,60 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QDebug>
+#include <QtCore/qsysinfo.h>
+#include <private/qplatformmediaintegration_p.h>
+
+QT_USE_NAMESPACE
+
+class tst_backends : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase()
+ {
+ // Log operating system name and currently supported backends
+ qDebug() << QSysInfo::prettyProductName() << "supports backends"
+ << QPlatformMediaIntegration::availableBackends().join(", ");
+ }
+
+private slots:
+ void availableBackends_returns_expectedBackends_data()
+ {
+ QTest::addColumn<QStringList>("expectedBackends");
+ QStringList backends;
+
+#if defined(Q_OS_WIN)
+ backends << "windows";
+ if (QSysInfo::currentCpuArchitecture() == "x86_64")
+ backends << "ffmpeg";
+#elif defined(Q_OS_ANDROID)
+ backends << "android" << "ffmpeg";
+#elif defined(Q_OS_DARWIN)
+ backends << "darwin" << "ffmpeg";
+#elif defined(Q_OS_WASM)
+ backends << "wasm";
+#elif defined(Q_OS_QNX)
+ backends << "qnx";
+#else
+ backends << "ffmpeg" << "gstreamer";
+#endif
+
+ QTest::addRow("backends") << backends;
+ }
+
+ void availableBackends_returns_expectedBackends()
+ {
+ QFETCH(QStringList, expectedBackends);
+ QStringList actualBackends = QPlatformMediaIntegration::availableBackends();
+ for (const auto &expectedBackend : expectedBackends) {
+ QVERIFY(actualBackends.contains(expectedBackend));
+ }
+ }
+};
+
+QTEST_MAIN(tst_backends)
+
+#include "tst_backends.moc"
diff --git a/tests/auto/integration/multiapp/CMakeLists.txt b/tests/auto/integration/multiapp/CMakeLists.txt
new file mode 100644
index 000000000..8a297cafc
--- /dev/null
+++ b/tests/auto/integration/multiapp/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_multiapp
+ SOURCES
+ tst_multiapp.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::MultimediaPrivate
+)
+
+set(resources_resource_files
+ "double-drop.wav"
+)
+
+qt_add_resources(tst_multiapp "resources"
+ PREFIX
+ "/"
+ FILES
+ ${resources_resource_files}
+)
diff --git a/tests/auto/integration/multiapp/double-drop.wav b/tests/auto/integration/multiapp/double-drop.wav
new file mode 100644
index 000000000..bd9a507c7
--- /dev/null
+++ b/tests/auto/integration/multiapp/double-drop.wav
Binary files differ
diff --git a/tests/auto/integration/multiapp/tst_multiapp.cpp b/tests/auto/integration/multiapp/tst_multiapp.cpp
new file mode 100644
index 000000000..793a56e9d
--- /dev/null
+++ b/tests/auto/integration/multiapp/tst_multiapp.cpp
@@ -0,0 +1,161 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QtCore/qdebug.h>
+#include <QtCore/qprocess.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmetaobject.h>
+#include <QtMultimedia/qsoundeffect.h>
+#include <QtMultimedia/qmediadevices.h>
+#include <QtMultimedia/qaudiodevice.h>
+
+using namespace Qt::StringLiterals;
+
+QT_USE_NAMESPACE
+
+namespace {
+bool executeTestOutOfProcess(const QString &testName);
+void playSound();
+} // namespace
+
+class tst_multiapp : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase()
+ {
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
+ QSKIP("Out-of-process testing does not behave correctly on mobile OS");
+#endif
+ }
+
+private slots:
+ void mediaDevices_doesNotCrash_whenRecreatingApplication()
+ {
+ QVERIFY(executeTestOutOfProcess(
+ "mediaDevices_doesNotCrash_whenRecreatingApplication_impl"_L1));
+ }
+
+ bool mediaDevices_doesNotCrash_whenRecreatingApplication_impl(int argc, char ** argv)
+ {
+ {
+ QCoreApplication app{ argc, argv };
+ QMediaDevices::defaultAudioOutput();
+ }
+ {
+ QCoreApplication app{ argc, argv };
+ QMediaDevices::defaultAudioOutput();
+ }
+
+ return true;
+ }
+
+ void soundEffect_doesNotCrash_whenRecreatingApplication()
+ {
+ QVERIFY(executeTestOutOfProcess(
+ "soundEffect_doesNotCrash_whenRecreatingApplication_impl"_L1));
+ }
+
+ bool soundEffect_doesNotCrash_whenRecreatingApplication_impl(int argc, char **argv)
+ {
+ Q_ASSERT(!qApp);
+
+ // Play a sound twice under two different application objects
+ // This verifies that QSoundEffect works in use cases where
+ // client application recreates Qt application instances,
+ // for example when the client application loads plugins
+ // implemented using Qt.
+ {
+ QCoreApplication app{ argc, argv };
+ playSound();
+ }
+ {
+ QCoreApplication app{ argc, argv };
+ playSound();
+ }
+
+ return true;
+ }
+
+};
+
+namespace {
+
+void playSound()
+{
+ const QUrl url{ "qrc:double-drop.wav"_L1 };
+
+ QSoundEffect effect;
+ effect.setSource(url);
+ effect.play();
+
+ QObject::connect(&effect, &QSoundEffect::playingChanged, qApp, [&]() {
+ if (!effect.isPlaying())
+ qApp->quit();
+ });
+
+ // In some CI configurations, we do not have any audio devices. We must therefore
+ // close the qApp on error signal instead of on playingChanged.
+ QObject::connect(&effect, &QSoundEffect::statusChanged, qApp, [&]() {
+ if (effect.status() == QSoundEffect::Status::Error) {
+ qDebug() << "Failed to play sound effect";
+ qApp->quit();
+ }
+ });
+
+ qApp->exec();
+}
+
+bool executeTestOutOfProcess(const QString &testName)
+{
+ const QStringList args{ "--run-test"_L1, testName };
+ const QString processName = QCoreApplication::applicationFilePath();
+ const int status = QProcess::execute(processName, args);
+ return status == 0;
+}
+
+} // namespace
+
+// This main function executes tests like normal qTest, and adds support
+// for executing specific test functions when called out of process. In this
+// case we don't create a QApplication, because the intent is to test how features
+// behave when no QApplication exists.
+int main(int argc, char *argv[])
+{
+ QCommandLineParser cmd;
+ const QCommandLineOption runTest{ QStringList{ "run-test" }, "Executes a named test",
+ "runTest" };
+ cmd.addOption(runTest);
+ cmd.parse({ argv, argv + argc });
+
+ if (cmd.isSet(runTest)) {
+ // We are requested to run a test case in a separate process without a Qt application
+ const QString testName = cmd.value(runTest);
+
+ bool returnValue = false;
+ tst_multiapp tc;
+
+ // Call the requested function on the test class
+ const bool invokeResult =
+ QMetaObject::invokeMethod(&tc, testName.toLatin1(), Qt::DirectConnection,
+ qReturnArg(returnValue), argc, argv);
+
+ return (invokeResult && returnValue) ? 0 : 1;
+ }
+
+ // If no special arguments are set, enter the regular QTest main routine
+ // The below lines are the same that QTEST_GUILESS_MAIN would stamp out,
+ // except the `int main(...)`
+ TESTLIB_SELFCOVERAGE_START("tst_multiapp")
+ QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<tst_multiapp>();
+ QCoreApplication app(argc, argv);
+ app.setAttribute(Qt::AA_Use96Dpi, true);
+ tst_multiapp tc;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_multiapp.moc"
diff --git a/tests/auto/integration/qaudiodecoderbackend/CMakeLists.txt b/tests/auto/integration/qaudiodecoderbackend/CMakeLists.txt
index bef856a1e..d2206182f 100644
--- a/tests/auto/integration/qaudiodecoderbackend/CMakeLists.txt
+++ b/tests/auto/integration/qaudiodecoderbackend/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qaudiodecoderbackend.pro.
#####################################################################
@@ -12,21 +15,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qaudiodecoderbackend
SOURCES
- ../shared/mediafileselector.h
tst_qaudiodecoderbackend.cpp
+ ../shared/mediafileselector.h
+ ../shared/mediabackendutils.h
INCLUDE_DIRECTORIES
+ ../shared/
../../../../src/multimedia/audio
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Multimedia
Qt::MultimediaPrivate
TESTDATA ${test_data}
)
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(tst_qaudiodecoderbackend CONDITION boot2qt
- DEFINES
- WAV_SUPPORT_NOT_FORCED
-)
diff --git a/tests/auto/integration/qaudiodecoderbackend/testdata/test-no-audio-track.mp4 b/tests/auto/integration/qaudiodecoderbackend/testdata/test-no-audio-track.mp4
new file mode 100644
index 000000000..6b67a3433
--- /dev/null
+++ b/tests/auto/integration/qaudiodecoderbackend/testdata/test-no-audio-track.mp4
Binary files differ
diff --git a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
index c04d7ea2f..5a48b4457 100644
--- a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
+++ b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
@@ -1,43 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
#include "qaudiodecoder.h"
-#ifdef WAV_SUPPORT_NOT_FORCED
-#include "../shared/mediafileselector.h"
-#endif
+#include "mediafileselector.h"
+#include "mediabackendutils.h"
+
+constexpr char TEST_FILE_NAME[] = "testdata/test.wav";
+constexpr char TEST_UNSUPPORTED_FILE_NAME[] = "testdata/test-unsupported.avi";
+constexpr char TEST_CORRUPTED_FILE_NAME[] = "testdata/test-corrupted.wav";
+constexpr char TEST_INVALID_SOURCE[] = "invalid";
+constexpr char TEST_NO_AUDIO_TRACK[] = "testdata/test-no-audio-track.mp4";
+
+constexpr int testFileSampleCount = 44094;
+constexpr int testFileSampleRate = 44100;
-#define TEST_FILE_NAME "testdata/test.wav"
-#define TEST_UNSUPPORTED_FILE_NAME "testdata/test-unsupported.avi"
-#define TEST_CORRUPTED_FILE_NAME "testdata/test-corrupted.wav"
-#define TEST_INVALID_SOURCE "invalid"
+constexpr std::chrono::microseconds testFileDuration = [] {
+ using namespace std::chrono;
+ using namespace std::chrono_literals;
+ auto duration = nanoseconds(1s) * testFileSampleCount / testFileSampleRate;
+ return round<microseconds>(duration);
+}();
+
+constexpr qint64 testFileDurationUs = qint64(testFileDuration.count());
QT_USE_NAMESPACE
@@ -57,14 +44,29 @@ public slots:
void initTestCase();
private slots:
+ void testMediaFilesAreSupported();
+ void directBruteForceReading();
+ void indirectReadingByBufferReadySignal();
+ void indirectReadingByBufferAvailableSignal();
+ void stopOnBufferReady();
+ void restartOnBufferReady();
+ void restartOnFinish();
void fileTest();
void unsupportedFileTest();
void corruptedFileTest();
void invalidSource();
void deviceTest();
+ void play_emitsFormatError_whenMediaHasNoAudioTrack();
private:
- bool isWavSupported();
+ QUrl testFileUrl(const QString filePath);
+ void checkNoMoreChanges(QAudioDecoder &decoder);
+#ifdef Q_OS_ANDROID
+ QTemporaryFile *temporaryFile = nullptr;
+#endif
+
+ MediaFileSelector m_mediaSelector;
+ MaybeUrl m_wavFile = QUnexpect{};
};
void tst_QAudioDecoderBackend::init()
@@ -76,25 +78,289 @@ void tst_QAudioDecoderBackend::initTestCase()
QAudioDecoder d;
if (!d.isSupported())
QSKIP("Audio decoder service is not available");
+
+ m_wavFile = m_mediaSelector.select(QFINDTESTDATA(TEST_FILE_NAME));
}
void tst_QAudioDecoderBackend::cleanup()
{
+#ifdef Q_OS_ANDROID
+ if (temporaryFile) {
+ delete temporaryFile;
+ temporaryFile = nullptr;
+ }
+#endif
}
-bool tst_QAudioDecoderBackend::isWavSupported()
+QUrl tst_QAudioDecoderBackend::testFileUrl(const QString filePath)
{
-#ifdef WAV_SUPPORT_NOT_FORCED
- return !MediaFileSelector::selectMediaFile(QStringList() << QFINDTESTDATA(TEST_FILE_NAME)).isNull();
+ QUrl url;
+#ifndef Q_OS_ANDROID
+ QFileInfo fileInfo(QFINDTESTDATA(filePath));
+ url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
#else
- return true;
+ QFile file(":/" + filePath);
+ if (temporaryFile) {
+ delete temporaryFile;
+ temporaryFile = nullptr;
+ }
+ if (file.open(QIODevice::ReadOnly)) {
+ temporaryFile = QTemporaryFile::createNativeFile(file);
+ url = QUrl(temporaryFile->fileName());
+ }
#endif
+ return url;
+}
+
+void tst_QAudioDecoderBackend::checkNoMoreChanges(QAudioDecoder &decoder)
+{
+ QSignalSpy finishedSpy(&decoder, &QAudioDecoder::finished);
+ QSignalSpy bufferReadySpy(&decoder, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferAvailableSpy(&decoder, &QAudioDecoder::bufferAvailableChanged);
+
+ QTest::qWait(50); // wait a bit to check nothing happened after finish
+
+ QCOMPARE(finishedSpy.size(), 0);
+ QCOMPARE(bufferReadySpy.size(), 0);
+ QCOMPARE(bufferAvailableSpy.size(), 0);
+}
+
+void tst_QAudioDecoderBackend::testMediaFilesAreSupported()
+{
+ QCOMPARE(m_mediaSelector.dumpErrors(), "");
+}
+
+void tst_QAudioDecoderBackend::directBruteForceReading()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ decoder.setSource(*m_wavFile);
+ QVERIFY(!decoder.isDecoding());
+ QVERIFY(!decoder.bufferAvailable());
+
+ decoder.start();
+ QTRY_VERIFY(decoder.isDecoding());
+
+ auto waitAndCheck = [](auto &&predicate) { QVERIFY(QTest::qWaitFor(predicate)); };
+
+ auto waitForBufferAvailable = [&]() {
+ waitAndCheck([&]() { return !decoder.isDecoding() || decoder.bufferAvailable(); });
+
+ return decoder.bufferAvailable();
+ };
+
+ while (waitForBufferAvailable()) {
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+
+ sampleCount += buffer.sampleCount();
+ }
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+}
+
+void tst_QAudioDecoderBackend::indirectReadingByBufferReadySignal()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ QVERIFY(decoder.bufferAvailable());
+
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+ QVERIFY(!decoder.bufferAvailable());
+
+ sampleCount += buffer.sampleCount();
+ });
+
+ QSignalSpy decodingSpy(&decoder, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ decoder.setSource(*m_wavFile);
+ QVERIFY(!decoder.isDecoding());
+ QVERIFY(!decoder.bufferAvailable());
+
+ decoder.start();
+ QTRY_VERIFY(decodingSpy.size() >= 1);
+
+ QTRY_VERIFY(finishSpy.size() == 1);
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+ QCOMPARE(finishSpy.size(), 1);
+}
+
+void tst_QAudioDecoderBackend::indirectReadingByBufferAvailableSignal() {
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ connect(&decoder, &QAudioDecoder::bufferAvailableChanged, this, [&](bool available) {
+ QCOMPARE(decoder.bufferAvailable(), available);
+
+ if (!available)
+ return;
+
+ while (decoder.bufferAvailable()) {
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+
+ sampleCount += buffer.sampleCount();
+ }
+ });
+
+ QSignalSpy decodingSpy(&decoder, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ decoder.setSource(*m_wavFile);
+ QVERIFY(!decoder.isDecoding());
+ QVERIFY(!decoder.bufferAvailable());
+
+ decoder.start();
+ QTRY_VERIFY(decodingSpy.size() >= 1);
+
+ QTRY_VERIFY(finishSpy.size() == 1);
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+ QCOMPARE(finishSpy.size(), 1);
+}
+
+void tst_QAudioDecoderBackend::stopOnBufferReady()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ decoder.read(); // run next reading
+ decoder.stop();
+ });
+
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+ QSignalSpy bufferReadySpy(&decoder, &QAudioDecoder::bufferReady);
+
+ decoder.setSource(*m_wavFile);
+ decoder.start();
+
+ bufferReadySpy.wait();
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(bufferReadySpy.size(), 1);
+}
+
+void tst_QAudioDecoderBackend::restartOnBufferReady()
+{
+ QSKIP_GSTREAMER("QTBUG-124005: failures on gstreamer");
+
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ std::once_flag restartOnce;
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ QVERIFY(decoder.bufferAvailable());
+
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+ QVERIFY(!decoder.bufferAvailable());
+
+ sampleCount += buffer.sampleCount();
+
+ std::call_once(restartOnce, [&]() {
+ sampleCount = 0;
+ decoder.stop();
+ decoder.start();
+ });
+ });
+
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ decoder.setSource(*m_wavFile);
+ decoder.start();
+
+ QTRY_VERIFY2(finishSpy.size() == 2, "Wait for signals after restart and after finishing");
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+}
+
+void tst_QAudioDecoderBackend::restartOnFinish()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+
+ sampleCount += buffer.sampleCount();
+ });
+
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ std::once_flag restartOnce;
+ connect(&decoder, &QAudioDecoder::finished, this, [&]() {
+ QVERIFY(!decoder.bufferAvailable());
+ QVERIFY(!decoder.isDecoding());
+
+ std::call_once(restartOnce, [&]() {
+ sampleCount = 0;
+ decoder.start();
+ });
+ });
+
+ decoder.setSource(*m_wavFile);
+ decoder.start();
+
+ QTRY_VERIFY(finishSpy.size() == 2);
+
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+ QCOMPARE(sampleCount, testFileSampleCount);
}
void tst_QAudioDecoderBackend::fileTest()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ CHECK_SELECTED_URL(m_wavFile);
QAudioDecoder d;
if (d.error() == QAudioDecoder::NotSupportedError)
@@ -106,40 +372,44 @@ void tst_QAudioDecoderBackend::fileTest()
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.source(), QString(""));
+ QCOMPARE(d.source(), QStringLiteral(""));
QVERIFY(d.audioFormat() == QAudioFormat());
// Test local file
- QFileInfo fileInfo(QFINDTESTDATA(TEST_FILE_NAME));
- QUrl url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
- d.setSource(url);
+
+ d.setSource(*m_wavFile);
QVERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QCOMPARE(d.source(), url);
+ QCOMPARE(d.source(), *m_wavFile);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy isDecodingSpy(&d, SIGNAL(isDecodingChanged(bool)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
d.start();
- QTRY_VERIFY(d.isDecoding());
+
QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+
+ QVERIFY(qAbs(durationSpy.front().front().value<qint64>() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
// Test file is 44.1K 16bit mono, 44094 samples
QCOMPARE(buffer.format().channelCount(), 1);
- QCOMPARE(buffer.format().sampleRate(), 44100);
+ QCOMPARE(buffer.format().sampleRate(), testFileSampleRate);
QCOMPARE(buffer.format().sampleFormat(), QAudioFormat::Int16);
QCOMPARE(buffer.byteCount(), buffer.sampleCount() * 2); // 16bit mono
@@ -152,37 +422,44 @@ void tst_QAudioDecoderBackend::fileTest()
byteCount += buffer.byteCount();
// Now drain the decoder
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
+ auto durationToMs = [](uint64_t dur) {
+ if (isGStreamerPlatform())
+ return std::round(dur / 1000.0);
+ else
+ return dur / 1000.0;
+ };
+
while (d.bufferAvailable()) {
buffer = d.read();
QVERIFY(buffer.isValid());
QTRY_VERIFY(!positionSpy.isEmpty());
- QCOMPARE(positionSpy.takeLast().at(0).toLongLong(), qint64(duration / 1000));
+ QCOMPARE(positionSpy.takeLast().at(0).toLongLong(), qint64(durationToMs(duration)));
duration += buffer.duration();
sampleCount += buffer.sampleCount();
byteCount += buffer.byteCount();
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
}
// Make sure the duration is roughly correct (+/- 20ms)
- QCOMPARE(sampleCount, 44094);
- QCOMPARE(byteCount, 44094 * 2);
+ QCOMPARE(sampleCount, testFileSampleCount);
+ QCOMPARE(byteCount, testFileSampleCount * 2);
QVERIFY(qAbs(qint64(duration) - 1000000) < 20000);
QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20);
- QTRY_COMPARE(finishedSpy.count(), 1);
+ QTRY_COMPARE(finishedSpy.size(), 1);
QVERIFY(!d.bufferAvailable());
QTRY_VERIFY(!d.isDecoding());
d.stop();
QTRY_VERIFY(!d.isDecoding());
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
QVERIFY(!d.bufferAvailable());
readySpy.clear();
@@ -192,6 +469,9 @@ void tst_QAudioDecoderBackend::fileTest()
finishedSpy.clear();
positionSpy.clear();
+#ifdef Q_OS_ANDROID
+ QSKIP("Setting a desired audio format is not yet supported on Android", QTest::SkipSingle);
+#endif
// change output audio format
QAudioFormat format;
format.setChannelCount(2);
@@ -211,13 +491,16 @@ void tst_QAudioDecoderBackend::fileTest()
byteCount = 0;
d.start();
- QTRY_VERIFY(d.isDecoding());
QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+ QVERIFY(qAbs(durationSpy.front().front().value<qint64>() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
@@ -233,40 +516,35 @@ void tst_QAudioDecoderBackend::fileTest()
sampleCount += buffer.sampleCount();
byteCount += buffer.byteCount();
- // Now drain the decoder
- if (duration < 996000) {
- QTRY_COMPARE(d.bufferAvailable(), true);
- }
+ while (finishedSpy.isEmpty() || d.bufferAvailable()) {
+ if (!d.bufferAvailable()) {
+ QTest::qWait(std::chrono::milliseconds(10));
+ continue;
+ }
- while (d.bufferAvailable()) {
buffer = d.read();
QVERIFY(buffer.isValid());
QTRY_VERIFY(!positionSpy.isEmpty());
- QCOMPARE(positionSpy.takeLast().at(0).toLongLong(), qint64(duration / 1000));
- QVERIFY(d.position() - (duration / 1000) < 20);
+ QCOMPARE(positionSpy.takeLast().at(0).toLongLong(), qlonglong(durationToMs(duration)));
+ QCOMPARE_LT(d.position() - durationToMs(duration), 20u);
duration += buffer.duration();
sampleCount += buffer.sampleCount();
byteCount += buffer.byteCount();
-
- if (duration < 996000) {
- QTRY_COMPARE(d.bufferAvailable(), true);
- }
}
// Resampling might end up with fewer or more samples
// so be a bit sloppy
- QVERIFY(qAbs(sampleCount - 22047) < 100);
- QVERIFY(qAbs(byteCount - 22047) < 100);
- QVERIFY(qAbs(qint64(duration) - 1000000) < 20000);
- QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20);
- QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE_LT(qAbs(sampleCount - 22047), 100);
+ QCOMPARE_LT(qAbs(byteCount - 22047), 100);
+ QCOMPARE_LT(qAbs(qint64(duration) - testFileDurationUs), 20000);
+ QCOMPARE_LT(qAbs((d.position() + (buffer.duration() / 1000)) - 1000), 20);
QVERIFY(!d.bufferAvailable());
QVERIFY(!d.isDecoding());
d.stop();
QTRY_VERIFY(!d.isDecoding());
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
QVERIFY(!d.bufferAvailable());
}
@@ -283,24 +561,23 @@ void tst_QAudioDecoderBackend::unsupportedFileTest()
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.source(), QString(""));
+ QCOMPARE(d.source(), QStringLiteral(""));
QVERIFY(d.audioFormat() == QAudioFormat());
// Test local file
- QFileInfo fileInfo(QFINDTESTDATA(TEST_UNSUPPORTED_FILE_NAME));
- QUrl url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+ QUrl url = testFileUrl(TEST_UNSUPPORTED_FILE_NAME);
d.setSource(url);
QVERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
QCOMPARE(d.source(), url);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy isDecodingSpy(&d, SIGNAL(isDecodingChanged(bool)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
d.start();
QTRY_VERIFY(!d.isDecoding());
@@ -324,7 +601,7 @@ void tst_QAudioDecoderBackend::unsupportedFileTest()
QVERIFY(finishedSpy.isEmpty());
QVERIFY(positionSpy.isEmpty());
// Either reject the file directly, or set the duration to 5secs on setUrl() and back to -1 on start()
- QVERIFY(durationSpy.isEmpty() || durationSpy.count() == 2);
+ QVERIFY(durationSpy.isEmpty() || durationSpy.size() == 2);
errorSpy.clear();
@@ -341,7 +618,7 @@ void tst_QAudioDecoderBackend::unsupportedFileTest()
QVERIFY(isDecodingSpy.isEmpty());
QVERIFY(finishedSpy.isEmpty());
QVERIFY(positionSpy.isEmpty());
- QVERIFY(durationSpy.isEmpty() || durationSpy.count() == 2);
+ QVERIFY(durationSpy.isEmpty() || durationSpy.size() == 2);
d.stop();
@@ -367,20 +644,19 @@ void tst_QAudioDecoderBackend::corruptedFileTest()
QVERIFY(d.audioFormat() == QAudioFormat());
// Test local file
- QFileInfo fileInfo(QFINDTESTDATA(TEST_CORRUPTED_FILE_NAME));
- QUrl url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+ QUrl url = testFileUrl(TEST_CORRUPTED_FILE_NAME);
d.setSource(url);
QVERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
QCOMPARE(d.source(), url);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy isDecodingSpy(&d, SIGNAL(isDecodingChanged(bool)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
d.start();
QTRY_VERIFY(!d.isDecoding());
@@ -422,7 +698,6 @@ void tst_QAudioDecoderBackend::corruptedFileTest()
QVERIFY(positionSpy.isEmpty());
QVERIFY(durationSpy.isEmpty());
-
d.stop();
QTRY_VERIFY(!d.isDecoding());
QCOMPARE(d.duration(), qint64(-1));
@@ -449,13 +724,13 @@ void tst_QAudioDecoderBackend::invalidSource()
QVERIFY(!d.bufferAvailable());
QCOMPARE(d.source(), url);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy isDecodingSpy(&d, SIGNAL(isDecodingChanged(bool)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
d.start();
QTRY_VERIFY(!d.isDecoding());
@@ -522,8 +797,8 @@ void tst_QAudioDecoderBackend::invalidSource()
void tst_QAudioDecoderBackend::deviceTest()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ using namespace std::chrono;
+ CHECK_SELECTED_URL(m_wavFile);
QAudioDecoder d;
if (d.error() == QAudioDecoder::NotSupportedError)
@@ -532,21 +807,19 @@ void tst_QAudioDecoderBackend::deviceTest()
quint64 duration = 0;
int sampleCount = 0;
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy isDecodingSpy(&d, SIGNAL(isDecodingChanged(bool)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.source(), QString(""));
+ QCOMPARE(d.source(), QStringLiteral(""));
QVERIFY(d.audioFormat() == QAudioFormat());
-
- QFileInfo fileInfo(QFINDTESTDATA(TEST_FILE_NAME));
- QFile file(fileInfo.absoluteFilePath());
+ QFile file(m_wavFile->toString());
QVERIFY(file.open(QIODevice::ReadOnly));
d.setSourceDevice(&file);
@@ -558,20 +831,22 @@ void tst_QAudioDecoderBackend::deviceTest()
d.start();
- QTRY_VERIFY(d.isDecoding());
QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
// Test file is 44.1K 16bit mono
QCOMPARE(buffer.format().channelCount(), 1);
- QCOMPARE(buffer.format().sampleRate(), 44100);
+ QCOMPARE(buffer.format().sampleRate(), testFileSampleRate);
QCOMPARE(buffer.format().sampleFormat(), QAudioFormat::Int16);
QVERIFY(errorSpy.isEmpty());
@@ -580,7 +855,7 @@ void tst_QAudioDecoderBackend::deviceTest()
sampleCount += buffer.sampleCount();
// Now drain the decoder
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
@@ -588,28 +863,34 @@ void tst_QAudioDecoderBackend::deviceTest()
buffer = d.read();
QVERIFY(buffer.isValid());
QTRY_VERIFY(!positionSpy.isEmpty());
- QVERIFY(positionSpy.takeLast().at(0).toLongLong() == qint64(duration / 1000));
+ if (isGStreamerPlatform())
+ QCOMPARE_EQ(positionSpy.takeLast().at(0).toLongLong(),
+ round<milliseconds>(microseconds{ duration }).count());
+ else
+ QCOMPARE_EQ(positionSpy.takeLast().at(0).toLongLong(),
+ floor<milliseconds>(microseconds{ duration }).count());
+
QVERIFY(d.position() - (duration / 1000) < 20);
duration += buffer.duration();
sampleCount += buffer.sampleCount();
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
}
// Make sure the duration is roughly correct (+/- 20ms)
- QCOMPARE(sampleCount, 44094);
+ QCOMPARE(sampleCount, testFileSampleCount);
QVERIFY(qAbs(qint64(duration) - 1000000) < 20000);
QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20);
- QTRY_COMPARE(finishedSpy.count(), 1);
+ QTRY_COMPARE(finishedSpy.size(), 1);
QVERIFY(!d.bufferAvailable());
QTRY_VERIFY(!d.isDecoding());
d.stop();
QTRY_VERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
readySpy.clear();
bufferChangedSpy.clear();
@@ -618,6 +899,9 @@ void tst_QAudioDecoderBackend::deviceTest()
finishedSpy.clear();
positionSpy.clear();
+#ifdef Q_OS_ANDROID
+ QSKIP("Setting a desired audio format is not yet supported on Android", QTest::SkipSingle);
+#endif
// Now try changing formats
QAudioFormat format;
format.setChannelCount(2);
@@ -631,13 +915,17 @@ void tst_QAudioDecoderBackend::deviceTest()
d.start();
QVERIFY(d.error() == QAudioDecoder::NoError);
- QTRY_VERIFY(d.isDecoding());
QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+
+ QVERIFY(qAbs(durationSpy.front().front().value<qint64>() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
@@ -652,10 +940,26 @@ void tst_QAudioDecoderBackend::deviceTest()
d.stop();
QTRY_VERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
}
+void tst_QAudioDecoderBackend::play_emitsFormatError_whenMediaHasNoAudioTrack()
+{
+ QSKIP_GSTREAMER("QTBUG-124206: gstreamer does not emit errors");
+
+ QAudioDecoder decoder;
+
+ QSignalSpy errors{ &decoder, qOverload<QAudioDecoder::Error>(&QAudioDecoder::error) };
+
+ decoder.setSource(testFileUrl(TEST_NO_AUDIO_TRACK));
+ decoder.start();
+
+ QTRY_VERIFY(!errors.empty());
+
+ QCOMPARE_EQ(decoder.error(), QAudioDecoder::Error::FormatError);
+}
+
QTEST_MAIN(tst_QAudioDecoderBackend)
#include "tst_qaudiodecoderbackend.moc"
diff --git a/tests/auto/integration/qaudiodevice/CMakeLists.txt b/tests/auto/integration/qaudiodevice/CMakeLists.txt
index 059e62f87..93f0d49dd 100644
--- a/tests/auto/integration/qaudiodevice/CMakeLists.txt
+++ b/tests/auto/integration/qaudiodevice/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qaudiodevice.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qaudiodevice
SOURCES
tst_qaudiodevice.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/integration/qaudiodevice/tst_qaudiodevice.cpp b/tests/auto/integration/qaudiodevice/tst_qaudiodevice.cpp
index af48c4f3a..cd686bd08 100644
--- a/tests/auto/integration/qaudiodevice/tst_qaudiodevice.cpp
+++ b/tests/auto/integration/qaudiodevice/tst_qaudiodevice.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -35,8 +10,6 @@
#include <QList>
#include <QMediaDevices>
-//TESTED_COMPONENT=src/multimedia
-
class tst_QAudioDevice : public QObject
{
Q_OBJECT
@@ -45,7 +18,6 @@ public:
private slots:
void initTestCase();
- void cleanupTestCase();
void checkAvailableDefaultInput();
void checkAvailableDefaultOutput();
void channels();
@@ -59,7 +31,7 @@ private slots:
void equalityOperator();
private:
- QAudioDevice* device;
+ std::unique_ptr<QAudioDevice> device;
};
void tst_QAudioDevice::initTestCase()
@@ -69,21 +41,18 @@ void tst_QAudioDevice::initTestCase()
if (devices.size() == 0) {
QSKIP("NOTE: no audio output device found, no tests will be performed");
} else {
- device = new QAudioDevice(devices.at(0));
+ device = std::make_unique<QAudioDevice>(devices.at(0));
}
}
-void tst_QAudioDevice::cleanupTestCase()
-{
- delete device;
-}
-
void tst_QAudioDevice::checkAvailableDefaultInput()
{
// Only perform tests if audio input device exists!
QList<QAudioDevice> devices = QMediaDevices::audioInputs();
if (devices.size() > 0) {
- QVERIFY(!QMediaDevices::defaultAudioInput().isNull());
+ auto defaultInput = QMediaDevices::defaultAudioInput();
+ QVERIFY(!defaultInput.isNull());
+ QCOMPARE(std::count(devices.begin(), devices.end(), defaultInput), 1);
}
}
@@ -92,7 +61,9 @@ void tst_QAudioDevice::checkAvailableDefaultOutput()
// Only perform tests if audio input device exists!
QList<QAudioDevice> devices = QMediaDevices::audioOutputs();
if (devices.size() > 0) {
- QVERIFY(!QMediaDevices::defaultAudioOutput().isNull());
+ auto defaultOutput = QMediaDevices::defaultAudioOutput();
+ QVERIFY(!defaultOutput.isNull());
+ QCOMPARE(std::count(devices.begin(), devices.end(), defaultOutput), 1);
}
}
diff --git a/tests/auto/integration/qaudiosink/BLACKLIST b/tests/auto/integration/qaudiosink/BLACKLIST
index 966b48af6..0b8789267 100644
--- a/tests/auto/integration/qaudiosink/BLACKLIST
+++ b/tests/auto/integration/qaudiosink/BLACKLIST
@@ -1 +1,11 @@
-linux ci
+#QTBUG-113194
+[pullSuspendResume]
+macos ci
+
+#QTBUG-113194
+[pushSuspendResume]
+macos ci
+
+#QTBUG-122309
+[pullResumeFromUnderrun]
+rhel-9.2
diff --git a/tests/auto/integration/qaudiosink/CMakeLists.txt b/tests/auto/integration/qaudiosink/CMakeLists.txt
index 26b1c50a2..902326dcc 100644
--- a/tests/auto/integration/qaudiosink/CMakeLists.txt
+++ b/tests/auto/integration/qaudiosink/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#####################################################################
## tst_qaudiosink Test:
#####################################################################
@@ -5,7 +8,7 @@
qt_internal_add_test(tst_qaudiosink
SOURCES
tst_qaudiosink.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/integration/qaudiosink/tst_qaudiosink.cpp b/tests/auto/integration/qaudiosink/tst_qaudiosink.cpp
index d957cecc7..6fdfe8221 100644
--- a/tests/auto/integration/qaudiosink/tst_qaudiosink.cpp
+++ b/tests/auto/integration/qaudiosink/tst_qaudiosink.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/qlocale.h>
@@ -75,6 +48,8 @@ private slots:
void pushSuspendResume_data(){generate_audiofile_testrows();}
void pushSuspendResume();
+ void pushResetResume();
+
void pushUnderrun_data(){generate_audiofile_testrows();}
void pushUnderrun();
@@ -84,8 +59,16 @@ private slots:
private:
using FilePtr = QSharedPointer<QFile>;
- QString formatToFileName(const QAudioFormat &format);
+ static QString formatToFileName(const QAudioFormat &format);
void createSineWaveData(const QAudioFormat &format, qint64 length, int sampleRate = 440);
+ static QString dumpStateSignalSpy(const QSignalSpy &stateSignalSpy);
+
+ static qint64 wavDataSize(QIODevice &input);
+
+ template<typename Checker>
+ static void pushDataToAudioSink(QAudioSink &sink, QIODevice &input, QIODevice &feed,
+ qint64 &allWritten, qint64 writtenLimit, Checker &&checker,
+ bool checkOnlyFirst = false);
void generate_audiofile_testrows();
@@ -100,10 +83,10 @@ private:
QString tst_QAudioSink::formatToFileName(const QAudioFormat &format)
{
- return QString("%1_%2_%3")
- .arg(format.sampleRate())
- .arg(format.bytesPerSample())
- .arg(format.channelCount());
+ return QStringLiteral("%1_%2_%3")
+ .arg(format.sampleRate())
+ .arg(format.bytesPerSample())
+ .arg(format.channelCount());
}
void tst_QAudioSink::createSineWaveData(const QAudioFormat &format, qint64 length, int sampleRate)
@@ -155,15 +138,69 @@ void tst_QAudioSink::createSineWaveData(const QAudioFormat &format, qint64 lengt
Q_ASSERT(m_buffer->open(QIODevice::ReadOnly));
}
+QString tst_QAudioSink::dumpStateSignalSpy(const QSignalSpy& stateSignalSpy) {
+ QString result = "[";
+ bool first = true;
+ for (auto& params : stateSignalSpy)
+ {
+ if (!std::exchange(first, false))
+ result += ',';
+ result += QString::number(params.front().value<QAudio::State>());
+ }
+ result.append(']');
+ return result;
+}
+
+qint64 tst_QAudioSink::wavDataSize(QIODevice &input)
+{
+ return input.size() - QWaveDecoder::headerLength();
+}
+
+template<typename Checker>
+void tst_QAudioSink::pushDataToAudioSink(QAudioSink &sink, QIODevice &input, QIODevice &feed,
+ qint64 &allWritten, qint64 writtenLimit, Checker &&checker,
+ bool checkOnlyFirst)
+{
+ bool firstBuffer = true;
+ qint64 offset = 0;
+ QByteArray buffer;
+
+ while ((allWritten < writtenLimit || writtenLimit < 0) && !input.atEnd()
+ && !QTest::currentTestFailed()) {
+ if (sink.bytesFree() > 0) {
+ if (buffer.isNull())
+ buffer = input.read(sink.bytesFree());
+
+ const auto written = feed.write(buffer);
+ allWritten += written;
+ offset += written;
+
+ if (offset >= buffer.size()) {
+ offset = 0;
+ buffer.clear();
+ }
+
+ if (!checkOnlyFirst || firstBuffer)
+ checker();
+
+ firstBuffer = false;
+ } else {
+ // wait a bit to ensure some the sink has consumed some data
+ // The delay getting might need some improvements
+ const auto delay = qMin(10, sink.format().durationForBytes(sink.bufferSize()) / 1000 / 2);
+ QTest::qWait(delay);
+ }
+ }
+}
+
void tst_QAudioSink::generate_audiofile_testrows()
{
QTest::addColumn<FilePtr>("audioFile");
QTest::addColumn<QAudioFormat>("audioFormat");
- for (int i=0; i<audioFiles.count(); i++) {
- QTest::newRow(QString("Audio File %1").arg(i).toUtf8().constData())
+ for (int i=0; i<audioFiles.size(); i++) {
+ QTest::newRow(QStringLiteral("Audio File %1").arg(i).toUtf8().constData())
<< audioFiles.at(i) << testFormats.at(i);
-
}
}
@@ -205,6 +242,13 @@ void tst_QAudioSink::initTestCase()
// PCM 44100 stereo S16LE
format.setSampleRate(44100);
if (audioDevice.isFormatSupported(format))
+#ifdef Q_OS_ANDROID
+ // Testset crash on emulator x86 with API 23 (Android 6) for 44,1 MHz.
+ // It is not happen on x86 with API 24. What is more, there is no crash when
+ // tested sample rate is 44,999 or any other value. Seems like problem on
+ // emulator side. Let's turn off this frequency for API 23
+ if (QNativeInterface::QAndroidApplication::sdkVersion() > __ANDROID_API_M__)
+#endif
testFormats.append(format);
// PCM 48000 stereo S16LE
@@ -224,7 +268,7 @@ void tst_QAudioSink::initTestCase()
QVERIFY(m_temporaryDir->isValid());
const QString temporaryAudioPath = m_temporaryDir->path() + slash;
- for (const QAudioFormat &format : qAsConst(testFormats)) {
+ for (const QAudioFormat &format : std::as_const(testFormats)) {
qint64 len = format.sampleRate()*format.bytesPerFrame(); // 1 second
createSineWaveData(format, len);
// Write generate sine wave data to file
@@ -250,11 +294,23 @@ void tst_QAudioSink::format()
QAudioFormat actual = audioOutput.format();
QVERIFY2((requested.channelCount() == actual.channelCount()),
- QString("channels: requested=%1, actual=%2").arg(requested.channelCount()).arg(actual.channelCount()).toUtf8().constData());
+ QStringLiteral("channels: requested=%1, actual=%2")
+ .arg(requested.channelCount())
+ .arg(actual.channelCount())
+ .toUtf8()
+ .constData());
QVERIFY2((requested.sampleRate() == actual.sampleRate()),
- QString("sampleRate: requested=%1, actual=%2").arg(requested.sampleRate()).arg(actual.sampleRate()).toUtf8().constData());
+ QStringLiteral("sampleRate: requested=%1, actual=%2")
+ .arg(requested.sampleRate())
+ .arg(actual.sampleRate())
+ .toUtf8()
+ .constData());
QVERIFY2((requested.sampleFormat() == actual.sampleFormat()),
- QString("sampleFormat: requested=%1, actual=%2").arg((ushort)requested.sampleFormat()).arg((ushort)actual.sampleFormat()).toUtf8().constData());
+ QStringLiteral("sampleFormat: requested=%1, actual=%2")
+ .arg((ushort)requested.sampleFormat())
+ .arg((ushort)actual.sampleFormat())
+ .toUtf8()
+ .constData());
QVERIFY(requested == actual);
}
@@ -314,12 +370,20 @@ void tst_QAudioSink::bufferSize()
QFETCH(int, bufferSize);
QAudioSink audioOutput(audioDevice.preferredFormat(), this);
- QVERIFY2((audioOutput.error() == QAudio::NoError), QString("error() was not set to QAudio::NoError on creation(%1)").arg(bufferSize).toUtf8().constData());
+ QVERIFY2((audioOutput.error() == QAudio::NoError),
+ QStringLiteral("error() was not set to QAudio::NoError on creation(%1)")
+ .arg(bufferSize)
+ .toUtf8()
+ .constData());
audioOutput.setBufferSize(bufferSize);
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() is not QAudio::NoError after setBufferSize");
QVERIFY2((audioOutput.bufferSize() == bufferSize),
- QString("bufferSize: requested=%1, actual=%2").arg(bufferSize).arg(audioOutput.bufferSize()).toUtf8().constData());
+ QStringLiteral("bufferSize: requested=%1, actual=%2")
+ .arg(bufferSize)
+ .arg(audioOutput.bufferSize())
+ .toUtf8()
+ .constData());
}
void tst_QAudioSink::stopWhileStopped()
@@ -334,11 +398,11 @@ void tst_QAudioSink::stopWhileStopped()
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() was not set to QAudio::NoError before start()");
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
audioOutput.stop();
// Check that no state transition occurred
- QVERIFY2((stateSignal.count() == 0), "stop() while stopped is emitting a signal and it shouldn't");
+ QVERIFY2((stateSignal.size() == 0), "stop() while stopped is emitting a signal and it shouldn't");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() was not set to QAudio::NoError after stop()");
}
@@ -354,11 +418,11 @@ void tst_QAudioSink::suspendWhileStopped()
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() was not set to QAudio::NoError before start()");
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
audioOutput.suspend();
// Check that no state transition occurred
- QVERIFY2((stateSignal.count() == 0), "stop() while suspended is emitting a signal and it shouldn't");
+ QVERIFY2((stateSignal.size() == 0), "stop() while suspended is emitting a signal and it shouldn't");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() was not set to QAudio::NoError after stop()");
}
@@ -374,11 +438,11 @@ void tst_QAudioSink::resumeWhileStopped()
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() was not set to QAudio::NoError before start()");
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
audioOutput.resume();
// Check that no state transition occurred
- QVERIFY2((stateSignal.count() == 0), "resume() while stopped is emitting a signal and it shouldn't");
+ QVERIFY2((stateSignal.size() == 0), "resume() while stopped is emitting a signal and it shouldn't");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() was not set to QAudio::NoError after resume()");
}
@@ -391,7 +455,7 @@ void tst_QAudioSink::pull()
audioOutput.setVolume(0.1f);
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -405,8 +469,11 @@ void tst_QAudioSink::pull()
audioOutput.start(audioFile.data());
// Check that QAudioSink immediately transitions to ActiveState
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal on start(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal on start(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after start()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
stateSignal.clear();
@@ -417,8 +484,8 @@ void tst_QAudioSink::pull()
// Wait until playback finishes
QTRY_VERIFY2(audioFile->atEnd(), "didn't play to EOF");
- QTRY_VERIFY(stateSignal.count() > 0);
- QCOMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
+ QTRY_VERIFY(stateSignal.size() > 0);
+ QTRY_COMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transitions to IdleState when at EOF");
stateSignal.clear();
@@ -426,8 +493,11 @@ void tst_QAudioSink::pull()
audioOutput.stop();
QTest::qWait(40);
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
@@ -444,7 +514,7 @@ void tst_QAudioSink::pullSuspendResume()
audioOutput.setVolume(0.1f);
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -457,21 +527,29 @@ void tst_QAudioSink::pullSuspendResume()
audioOutput.start(audioFile.data());
// Check that QAudioSink immediately transitions to ActiveState
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal on start(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal on start(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after start()");
- QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
- stateSignal.clear();
+ QVERIFY2((audioOutput.error() == QAudio::NoError),
+ "error state is not equal to QAudio::NoError after start()");
+ stateSignal.clear();
// Wait for half of clip to play
QTest::qWait(500);
audioOutput.suspend();
QTest::qWait(100);
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit SuspendedState signal after suspend(), got %1 signals instead")
- .arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral(
+ "didn't emit SuspendedState signal after suspend(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::SuspendedState), "didn't transition to SuspendedState after suspend()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after suspend()");
stateSignal.clear();
@@ -486,16 +564,19 @@ void tst_QAudioSink::pullSuspendResume()
audioOutput.resume();
// Check that QAudioSink immediately transitions to ActiveState
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal after resume(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal after resume(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after resume()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after resume()");
stateSignal.clear();
// Wait until playback finishes
QTRY_VERIFY2(audioFile->atEnd(), "didn't play to EOF");
- QTRY_VERIFY(stateSignal.count() > 0);
- QCOMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
+ QTRY_VERIFY(stateSignal.size() > 0);
+ QTRY_COMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transitions to IdleState when at EOF");
stateSignal.clear();
@@ -503,8 +584,11 @@ void tst_QAudioSink::pullSuspendResume()
audioOutput.stop();
QTest::qWait(40);
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
@@ -513,68 +597,71 @@ void tst_QAudioSink::pullSuspendResume()
audioFile->close();
}
-class AudioPullSource : public QIODevice
+void tst_QAudioSink::pullResumeFromUnderrun()
{
- Q_OBJECT
-public:
- qint64 readData(char *data, qint64 len) override {
- qint64 read = qMin(len, available);
- available -= read;
- memset(data, 0, read);
- return read;
- }
- qint64 writeData(const char *, qint64) override { return 0; }
- bool isSequential() const override { return true; }
+ class AudioPullSource : public QIODevice
+ {
+ public:
+ qint64 readData(char *data, qint64 len) override {
+ qint64 read = qMin(len, available);
+ available -= read;
+ memset(data, 0, read);
+ return read;
+ }
+ qint64 writeData(const char *, qint64) override { return 0; }
+ bool isSequential() const override { return true; }
- qint64 bytesAvailable() const override { return available; }
- bool atEnd() const override { return signalEnd && available == 0; }
+ qint64 bytesAvailable() const override { return available; }
+ bool atEnd() const override { return signalEnd && available == 0; }
- qint64 available = 0;
- bool signalEnd = false;
-};
+ qint64 available = 0;
+ bool signalEnd = false;
+ };
+
+ constexpr int chunkSize = 128;
-void tst_QAudioSink::pullResumeFromUnderrun()
-{
- AudioPullSource audioSource;
QAudioFormat format;
format.setChannelCount(1);
format.setSampleFormat(QAudioFormat::UInt8);
- format.setSampleRate(1024);
- QAudioSink audioOutput(format, this);
+ format.setSampleRate(8000);
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ AudioPullSource audioSource;
+ QAudioSink audioOutput(format, this);
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
audioSource.open(QIODeviceBase::ReadOnly);
- audioSource.available = 128;
+ audioSource.available = chunkSize;
+ QCOMPARE(audioOutput.state(), QAudio::StoppedState);
audioOutput.start(&audioSource);
- QTRY_VERIFY(stateSignal.count() == 1);
- QVERIFY(audioOutput.state() == QAudio::ActiveState);
- QVERIFY(audioOutput.error() == QAudio::NoError);
+ QTRY_COMPARE(stateSignal.size(), 1);
+ QCOMPARE(audioOutput.state(), QAudio::ActiveState);
+ QCOMPARE(audioOutput.error(), QAudio::NoError);
stateSignal.clear();
- QTRY_VERIFY(stateSignal.count() == 1);
- QVERIFY(audioOutput.state() == QAudio::IdleState);
- QVERIFY(audioOutput.error() == QAudio::UnderrunError);
+ QTRY_COMPARE(stateSignal.size(), 1);
+ QCOMPARE(audioOutput.state(), QAudio::IdleState);
+ QCOMPARE(audioOutput.error(), QAudio::UnderrunError);
stateSignal.clear();
QTest::qWait(300);
- audioSource.available = 128;
+ audioSource.available = chunkSize;
audioSource.signalEnd = true;
// Resume pull
emit audioSource.readyRead();
- QTRY_VERIFY(stateSignal.count() == 1);
- QVERIFY(audioOutput.state() == QAudio::ActiveState);
- QVERIFY(audioOutput.error() == QAudio::NoError);
- stateSignal.clear();
+ QTRY_COMPARE(stateSignal.size(), 2);
+ QCOMPARE(stateSignal.at(0).front().value<QAudio::State>(), QAudio::ActiveState);
+ QCOMPARE(stateSignal.at(1).front().value<QAudio::State>(), QAudio::IdleState);
- QTRY_VERIFY(stateSignal.count() == 1);
- QVERIFY(audioOutput.state() == QAudio::IdleState);
- QVERIFY(audioOutput.error() == QAudio::NoError);
+ QCOMPARE(audioOutput.error(), QAudio::NoError);
+ QCOMPARE(audioOutput.state(), QAudio::IdleState);
- QTRY_COMPARE(audioOutput.processedUSecs(), 250000);
+ // we played two chunks, sample rate is per second
+ const int expectedUSecs = (double(chunkSize) / double(format.sampleRate()))
+ * 2 * 1000 * 1000;
+ QTRY_COMPARE(audioOutput.processedUSecs(), expectedUSecs);
}
void tst_QAudioSink::push()
@@ -586,7 +673,7 @@ void tst_QAudioSink::push()
audioOutput.setVolume(0.1f);
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -600,8 +687,11 @@ void tst_QAudioSink::push()
QIODevice* feed = audioOutput.start();
// Check that QAudioSink immediately transitions to IdleState
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal on start(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal on start(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transition to IdleState after start()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
stateSignal.clear();
@@ -612,33 +702,29 @@ void tst_QAudioSink::push()
QVERIFY2((audioOutput.processedUSecs() == qint64(0)), "processedUSecs() is not zero after start()");
qint64 written = 0;
- bool firstBuffer = true;
- while (written < audioFile->size() - QWaveDecoder::headerLength()) {
-
- if (audioOutput.bytesFree() > 0) {
- auto buffer = audioFile->read(audioOutput.bytesFree());
- written += feed->write(buffer);
-
- if (firstBuffer) {
- // Check for transition to ActiveState when data is provided
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal after receiving data, got %1 signals instead")
- .arg(stateSignal.count()).toUtf8().constData());
- QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after receiving data");
- QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after receiving data");
- firstBuffer = false;
- stateSignal.clear();
- }
- } else
- QTest::qWait(20);
- }
+ auto checker = [&]() {
+ // Check for transition to ActiveState when data is provided
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal after receiving data, got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
+ QVERIFY2((audioOutput.state() == QAudio::ActiveState),
+ "didn't transition to ActiveState after receiving data");
+ QVERIFY2((audioOutput.error() == QAudio::NoError),
+ "error state is not equal to QAudio::NoError after receiving data");
+ stateSignal.clear();
+ };
+
+ pushDataToAudioSink(audioOutput, *audioFile, *feed, written, wavDataSize(*audioFile), checker,
+ true);
// Wait until playback finishes
QVERIFY2(audioFile->atEnd(), "didn't play to EOF");
QTRY_VERIFY(audioOutput.state() == QAudio::IdleState);
- QTRY_VERIFY(stateSignal.count() > 0);
- QCOMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
+ QTRY_VERIFY(stateSignal.size() > 0);
+ QTRY_COMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transitions to IdleState when at EOF");
stateSignal.clear();
@@ -646,8 +732,11 @@ void tst_QAudioSink::push()
audioOutput.stop();
QTest::qWait(40);
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
@@ -665,7 +754,7 @@ void tst_QAudioSink::pushSuspendResume()
audioOutput.setVolume(0.1f);
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -679,8 +768,11 @@ void tst_QAudioSink::pushSuspendResume()
QIODevice* feed = audioOutput.start();
// Check that QAudioSink immediately transitions to IdleState
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal on start(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal on start(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transition to IdleState after start()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
stateSignal.clear();
@@ -690,35 +782,35 @@ void tst_QAudioSink::pushSuspendResume()
QVERIFY2((audioOutput.elapsedUSecs() > 0), "elapsedUSecs() is still zero after start()");
QVERIFY2((audioOutput.processedUSecs() == qint64(0)), "processedUSecs() is not zero after start()");
- qint64 written = 0;
- bool firstBuffer = true;
+ auto firstHalfChecker = [&]() {
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal after receiving data, got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
+ QVERIFY2((audioOutput.state() == QAudio::ActiveState),
+ "didn't transition to ActiveState after receiving data");
+ QVERIFY2((audioOutput.error() == QAudio::NoError),
+ "error state is not equal to QAudio::NoError after receiving data");
+ };
+ qint64 written = 0;
// Play half of the clip
- while (written < (audioFile->size() - QWaveDecoder::headerLength()) / 2) {
-
- if (audioOutput.bytesFree() > 0) {
- auto buffer = audioFile->read(audioOutput.bytesFree());
- written += feed->write(buffer);
-
- if (firstBuffer) {
- // Check for transition to ActiveState when data is provided
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal after receiving data, got %1 signals instead")
- .arg(stateSignal.count()).toUtf8().constData());
- QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after receiving data");
- QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after receiving data");
- firstBuffer = false;
- }
- } else
- QTest::qWait(20);
- }
+ pushDataToAudioSink(audioOutput, *audioFile, *feed, written, wavDataSize(*audioFile) / 2,
+ firstHalfChecker, true);
+
stateSignal.clear();
+ const auto suspendedInState = audioOutput.state();
audioOutput.suspend();
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit SuspendedState signal after suspend(), got %1 signals instead")
- .arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral(
+ "didn't emit SuspendedState signal after suspend(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::SuspendedState), "didn't transition to SuspendedState after suspend()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after suspend()");
stateSignal.clear();
@@ -737,27 +829,30 @@ void tst_QAudioSink::pushSuspendResume()
QTest::qWait(20);
// Check that QAudioSink immediately transitions to IdleState
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal after resume(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
- QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transition to IdleState after resume()");
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal after resume(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
+ QVERIFY2((audioOutput.state() == suspendedInState), "resume() didn't transition to state before suspend()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after resume()");
stateSignal.clear();
// Play rest of the clip
- while (!audioFile->atEnd()) {
- if (audioOutput.bytesFree() > 0) {
- auto buffer = audioFile->read(audioOutput.bytesFree());
- written += feed->write(buffer);
- QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after writing audio data");
- } else
- QTest::qWait(20);
- }
+
+ auto restChecker = [&]() {
+ QVERIFY2((audioOutput.state() == QAudio::ActiveState),
+ "didn't transition to ActiveState after writing audio data");
+ };
+
+ pushDataToAudioSink(audioOutput, *audioFile, *feed, written, -1, restChecker);
+
QVERIFY(audioOutput.state() != QAudio::IdleState);
stateSignal.clear();
QVERIFY2(audioFile->atEnd(), "didn't play to EOF");
- QTRY_VERIFY(stateSignal.count() > 0);
- QCOMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
+ QTRY_VERIFY(stateSignal.size() > 0);
+ QTRY_COMPARE(qvariant_cast<QAudio::State>(stateSignal.last().at(0)), QAudio::IdleState);
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transitions to IdleState when at EOF");
stateSignal.clear();
@@ -765,8 +860,11 @@ void tst_QAudioSink::pushSuspendResume()
audioOutput.stop();
QTest::qWait(40);
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
@@ -775,6 +873,46 @@ void tst_QAudioSink::pushSuspendResume()
audioFile->close();
}
+void tst_QAudioSink::pushResetResume()
+{
+ auto audioFile = audioFiles.at(0);
+ auto audioFormat = testFormats.at(0);
+
+ QAudioSink audioOutput(audioFormat, this);
+
+ audioOutput.setBufferSize(8192);
+ audioOutput.setVolume(0.1f);
+
+ audioFile->close();
+ audioFile->open(QIODevice::ReadOnly);
+ audioFile->seek(QWaveDecoder::headerLength());
+
+ QPointer<QIODevice> feed = audioOutput.start();
+
+ QTest::qWait(20);
+
+ auto buffer = audioFile->read(audioOutput.bytesFree());
+ feed->write(buffer);
+
+ QTest::qWait(20);
+ QTRY_COMPARE(audioOutput.state(), QAudio::ActiveState);
+
+ audioOutput.reset();
+ QCOMPARE(audioOutput.state(), QAudio::StoppedState);
+ QCOMPARE(audioOutput.error(), QAudio::NoError);
+
+ const auto processedUSecs = audioOutput.processedUSecs();
+
+ audioOutput.resume();
+ QTest::qWait(40);
+
+ // Nothing changed if resume after reset
+ QCOMPARE(audioOutput.state(), QAudio::StoppedState);
+ QCOMPARE(audioOutput.error(), QAudio::NoError);
+
+ QCOMPARE(audioOutput.processedUSecs(), processedUSecs);
+}
+
void tst_QAudioSink::pushUnderrun()
{
QFETCH(FilePtr, audioFile);
@@ -784,7 +922,7 @@ void tst_QAudioSink::pushUnderrun()
audioOutput.setVolume(0.1f);
- QSignalSpy stateSignal(&audioOutput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioOutput, &QAudioSink::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -798,8 +936,11 @@ void tst_QAudioSink::pushUnderrun()
QIODevice* feed = audioOutput.start();
// Check that QAudioSink immediately transitions to IdleState
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal on start(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal on start(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transition to IdleState after start()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
stateSignal.clear();
@@ -810,64 +951,61 @@ void tst_QAudioSink::pushUnderrun()
QVERIFY2((audioOutput.processedUSecs() == qint64(0)), "processedUSecs() is not zero after start()");
qint64 written = 0;
- bool firstBuffer = true;
- QByteArray buffer(AUDIO_BUFFER, 0);
// Play half of the clip
- while (written < (audioFile->size() - QWaveDecoder::headerLength()) / 2) {
-
- if (audioOutput.bytesFree() > 0) {
- auto buffer = audioFile->read(audioOutput.bytesFree());
- written += feed->write(buffer);
-
- if (firstBuffer) {
- // Check for transition to ActiveState when data is provided
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal after receiving data, got %1 signals instead")
- .arg(stateSignal.count()).toUtf8().constData());
- QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after receiving data");
- QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after receiving data");
- firstBuffer = false;
- }
- } else
- QTest::qWait(20);
- }
+
+ auto firstHalfChecker = [&]() {
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal after receiving data, got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
+ QVERIFY2((audioOutput.state() == QAudio::ActiveState),
+ "didn't transition to ActiveState after receiving data");
+ QVERIFY2((audioOutput.error() == QAudio::NoError),
+ "error state is not equal to QAudio::NoError after receiving data");
+ };
+
+ pushDataToAudioSink(audioOutput, *audioFile, *feed, written, wavDataSize(*audioFile) / 2,
+ firstHalfChecker, true);
+
stateSignal.clear();
// Wait for data to be played
QTest::qWait(700);
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit IdleState signal after suspend(), got %1 signals instead")
- .arg(stateSignal.count()).toUtf8().constData());
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit IdleState signal after suspend(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transition to IdleState, no data");
QVERIFY2((audioOutput.error() == QAudio::UnderrunError), "error state is not equal to QAudio::UnderrunError, no data");
stateSignal.clear();
- firstBuffer = true;
// Play rest of the clip
- while (!audioFile->atEnd()) {
- if (audioOutput.bytesFree() > 0) {
- auto buffer = audioFile->read(audioOutput.bytesFree());
- written += feed->write(buffer);
- if (firstBuffer) {
- // Check for transition to ActiveState when data is provided
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal after receiving data, got %1 signals instead")
- .arg(stateSignal.count()).toUtf8().constData());
- QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after receiving data");
- QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after receiving data");
- firstBuffer = false;
- }
- } else
- QTest::qWait(20);
- }
+ auto restChecker = [&]() {
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal after receiving data, got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
+ QVERIFY2((audioOutput.state() == QAudio::ActiveState),
+ "didn't transition to ActiveState after receiving data");
+ QVERIFY2((audioOutput.error() == QAudio::NoError),
+ "error state is not equal to QAudio::NoError after receiving data");
+ };
+ pushDataToAudioSink(audioOutput, *audioFile, *feed, written, -1, restChecker, true);
+
stateSignal.clear();
// Wait until playback finishes
QVERIFY2(audioFile->atEnd(), "didn't play to EOF");
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit IdleState signal when at EOF, got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit IdleState signal when at EOF, got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transitions to IdleState when at EOF");
stateSignal.clear();
@@ -875,8 +1013,11 @@ void tst_QAudioSink::pushUnderrun()
audioOutput.stop();
QTest::qWait(40);
- QVERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QVERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(dumpStateSignalSpy(stateSignal))
+ .toUtf8()
+ .constData());
QVERIFY2((audioOutput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2((audioOutput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
diff --git a/tests/auto/integration/qaudiosource/CMakeLists.txt b/tests/auto/integration/qaudiosource/CMakeLists.txt
index e9026e963..0e572e804 100644
--- a/tests/auto/integration/qaudiosource/CMakeLists.txt
+++ b/tests/auto/integration/qaudiosource/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#####################################################################
## tst_qaudiosource Test:
#####################################################################
@@ -5,7 +8,7 @@
qt_internal_add_test(tst_qaudiosource
SOURCES
tst_qaudiosource.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/integration/qaudiosource/tst_qaudiosource.cpp b/tests/auto/integration/qaudiosource/tst_qaudiosource.cpp
index d343fb8a8..ae100a08b 100644
--- a/tests/auto/integration/qaudiosource/tst_qaudiosource.cpp
+++ b/tests/auto/integration/qaudiosource/tst_qaudiosource.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/qlocale.h>
@@ -40,8 +15,6 @@
#include <qwavedecoder.h>
-//TESTED_COMPONENT=src/multimedia
-
#define RANGE_ERR 0.5
template<typename T> inline bool qTolerantCompare(T value, T expected)
@@ -101,7 +74,7 @@ private:
QScopedPointer<QByteArray> m_byteArray;
QScopedPointer<QBuffer> m_buffer;
- bool m_inCISystem;
+ bool m_inCISystem = false;
};
void tst_QAudioSource::generate_audiofile_testrows()
@@ -109,8 +82,8 @@ void tst_QAudioSource::generate_audiofile_testrows()
QTest::addColumn<FilePtr>("audioFile");
QTest::addColumn<QAudioFormat>("audioFormat");
- for (int i=0; i<audioFiles.count(); i++) {
- QTest::newRow(QString("%1").arg(i).toUtf8().constData())
+ for (int i=0; i<audioFiles.size(); i++) {
+ QTest::newRow(QStringLiteral("%1").arg(i).toUtf8().constData())
<< audioFiles.at(i) << testFormats.at(i);
// Only run first format in CI system to reduce test times
@@ -121,16 +94,30 @@ void tst_QAudioSource::generate_audiofile_testrows()
QString tst_QAudioSource::formatToFileName(const QAudioFormat &format)
{
- return QString("%1_%2_%3")
- .arg(format.sampleRate())
- .arg(format.bytesPerSample())
- .arg(format.channelCount());
+ return QStringLiteral("%1_%2_%3")
+ .arg(format.sampleRate())
+ .arg(format.bytesPerSample())
+ .arg(format.channelCount());
}
void tst_QAudioSource::initTestCase()
{
- // Only perform tests if audio output device exists
- const QList<QAudioDevice> devices = QMediaDevices::audioOutputs();
+#ifdef Q_OS_ANDROID
+ // The test might fail because libOpenSLES cannot create AudioRecorder for that emulator. The
+ // Android documentation states that the emulator doesn't support this at all all
+ // https://developer.android.com/media/platform/mediarecorder. However, in practice this test
+ // fails only prior to Android 10.
+ if (QNativeInterface::QAndroidApplication::sdkVersion() < __ANDROID_API_Q__)
+ QSKIP("Emulated Android version doesn't support audio recording");
+#endif
+
+ m_inCISystem = qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci";
+
+ if (m_inCISystem)
+ QSKIP("SKIP initTestCase on CI. To be fixed");
+
+ // Only perform tests if audio input device exists
+ const QList<QAudioDevice> devices = QMediaDevices::audioInputs();
if (devices.size() <= 0)
QSKIP("No audio backend");
@@ -184,11 +171,10 @@ void tst_QAudioSource::initTestCase()
QVERIFY(m_temporaryDir->isValid());
const QString temporaryAudioPath = m_temporaryDir->path() + slash;
- for (const QAudioFormat &format : qAsConst(testFormats)) {
+ for (const QAudioFormat &format : std::as_const(testFormats)) {
const QString fileName = temporaryAudioPath + formatToFileName(format) + QStringLiteral(".wav");
audioFiles.append(FilePtr::create(fileName));
}
- qgetenv("QT_TEST_CI").toInt(&m_inCISystem,10);
}
void tst_QAudioSource::format()
@@ -199,11 +185,23 @@ void tst_QAudioSource::format()
QAudioFormat actual = audioInput.format();
QVERIFY2((requested.channelCount() == actual.channelCount()),
- QString("channels: requested=%1, actual=%2").arg(requested.channelCount()).arg(actual.channelCount()).toUtf8().constData());
+ QStringLiteral("channels: requested=%1, actual=%2")
+ .arg(requested.channelCount())
+ .arg(actual.channelCount())
+ .toUtf8()
+ .constData());
QVERIFY2((requested.sampleRate() == actual.sampleRate()),
- QString("sampleRate: requested=%1, actual=%2").arg(requested.sampleRate()).arg(actual.sampleRate()).toUtf8().constData());
+ QStringLiteral("sampleRate: requested=%1, actual=%2")
+ .arg(requested.sampleRate())
+ .arg(actual.sampleRate())
+ .toUtf8()
+ .constData());
QVERIFY2((requested.sampleFormat() == actual.sampleFormat()),
- QString("sampleFormat: requested=%1, actual=%2").arg((ushort)requested.sampleFormat()).arg((ushort)actual.sampleFormat()).toUtf8().constData());
+ QStringLiteral("sampleFormat: requested=%1, actual=%2")
+ .arg((ushort)requested.sampleFormat())
+ .arg((ushort)actual.sampleFormat())
+ .toUtf8()
+ .constData());
QCOMPARE(actual, requested);
}
@@ -260,17 +258,26 @@ void tst_QAudioSource::bufferSize()
audioInput.setBufferSize(512);
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after setBufferSize(512)");
QVERIFY2((audioInput.bufferSize() == 512),
- QString("bufferSize: requested=512, actual=%2").arg(audioInput.bufferSize()).toUtf8().constData());
+ QStringLiteral("bufferSize: requested=512, actual=%2")
+ .arg(audioInput.bufferSize())
+ .toUtf8()
+ .constData());
audioInput.setBufferSize(4096);
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after setBufferSize(4096)");
QVERIFY2((audioInput.bufferSize() == 4096),
- QString("bufferSize: requested=4096, actual=%2").arg(audioInput.bufferSize()).toUtf8().constData());
+ QStringLiteral("bufferSize: requested=4096, actual=%2")
+ .arg(audioInput.bufferSize())
+ .toUtf8()
+ .constData());
audioInput.setBufferSize(8192);
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after setBufferSize(8192)");
QVERIFY2((audioInput.bufferSize() == 8192),
- QString("bufferSize: requested=8192, actual=%2").arg(audioInput.bufferSize()).toUtf8().constData());
+ QStringLiteral("bufferSize: requested=8192, actual=%2")
+ .arg(audioInput.bufferSize())
+ .toUtf8()
+ .constData());
}
void tst_QAudioSource::stopWhileStopped()
@@ -285,11 +292,11 @@ void tst_QAudioSource::stopWhileStopped()
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() was not set to QAudio::NoError before start()");
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
audioInput.stop();
// Check that no state transition occurred
- QVERIFY2((stateSignal.count() == 0), "stop() while stopped is emitting a signal and it shouldn't");
+ QVERIFY2((stateSignal.size() == 0), "stop() while stopped is emitting a signal and it shouldn't");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() was not set to QAudio::NoError after stop()");
}
@@ -305,11 +312,11 @@ void tst_QAudioSource::suspendWhileStopped()
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() was not set to QAudio::NoError before start()");
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
audioInput.suspend();
// Check that no state transition occurred
- QVERIFY2((stateSignal.count() == 0), "stop() while suspended is emitting a signal and it shouldn't");
+ QVERIFY2((stateSignal.size() == 0), "stop() while suspended is emitting a signal and it shouldn't");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() was not set to QAudio::NoError after stop()");
}
@@ -325,11 +332,11 @@ void tst_QAudioSource::resumeWhileStopped()
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() was not set to QAudio::NoError before start()");
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
audioInput.resume();
// Check that no state transition occurred
- QVERIFY2((stateSignal.count() == 0), "resume() while stopped is emitting a signal and it shouldn't");
+ QVERIFY2((stateSignal.size() == 0), "resume() while stopped is emitting a signal and it shouldn't");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() was not set to QAudio::NoError after resume()");
}
@@ -340,7 +347,7 @@ void tst_QAudioSource::pull()
QAudioSource audioInput(audioFormat, this);
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -360,7 +367,7 @@ void tst_QAudioSource::pull()
audioInput.start(audioFile.data());
// Check that QAudioSource immediately transitions to ActiveState or IdleState
- QTRY_VERIFY2((stateSignal.count() > 0),"didn't emit signals on start()");
+ QTRY_VERIFY2((stateSignal.size() > 0),"didn't emit signals on start()");
QVERIFY2((audioInput.state() == QAudio::ActiveState || audioInput.state() == QAudio::IdleState),
"didn't transition to ActiveState or IdleState after start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
@@ -371,17 +378,25 @@ void tst_QAudioSource::pull()
QTRY_VERIFY2((audioInput.processedUSecs() > 0), "elapsedUSecs() is still zero after start()");
// Allow some recording to happen
- QTest::qWait(300); // .3 seconds should be plenty
+ QTest::qWait(3000); // 3 seconds should be plenty
stateSignal.clear();
qint64 processedUs = audioInput.processedUSecs();
- QVERIFY2(qTolerantCompare(processedUs, 300000LL),
- QString("processedUSecs() doesn't fall in acceptable range, should be 300000 (%1)").arg(processedUs).toUtf8().constData());
+ QVERIFY2(qTolerantCompare(processedUs, 3000000LL),
+ QStringLiteral(
+ "processedUSecs() doesn't fall in acceptable range, should be 3000000 (%1)")
+ .arg(processedUs)
+ .toUtf8()
+ .constData());
audioInput.stop();
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(stateSignal.size())
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
@@ -396,16 +411,12 @@ void tst_QAudioSource::pull()
void tst_QAudioSource::pullSuspendResume()
{
-#ifdef Q_OS_LINUX
- if (m_inCISystem)
- QSKIP("QTBUG-26504 Fails 20% of time with pulseaudio backend");
-#endif
QFETCH(FilePtr, audioFile);
QFETCH(QAudioFormat, audioFormat);
QAudioSource audioInput(audioFormat, this);
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -425,7 +436,7 @@ void tst_QAudioSource::pullSuspendResume()
audioInput.start(audioFile.data());
// Check that QAudioSource immediately transitions to ActiveState or IdleState
- QTRY_VERIFY2((stateSignal.count() > 0),"didn't emit signals on start()");
+ QTRY_VERIFY2((stateSignal.size() > 0),"didn't emit signals on start()");
QVERIFY2((audioInput.state() == QAudio::ActiveState || audioInput.state() == QAudio::IdleState),
"didn't transition to ActiveState or IdleState after start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
@@ -436,7 +447,7 @@ void tst_QAudioSource::pullSuspendResume()
QTRY_VERIFY2((audioInput.processedUSecs() > 0), "elapsedUSecs() is still zero after start()");
// Allow some recording to happen
- QTest::qWait(300); // .3 seconds should be plenty
+ QTest::qWait(3000); // 3 seconds should be plenty
QVERIFY2((audioInput.state() == QAudio::ActiveState),
"didn't transition to ActiveState after some recording");
@@ -446,8 +457,13 @@ void tst_QAudioSource::pullSuspendResume()
audioInput.suspend();
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit SuspendedState signal after suspend(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral(
+ "didn't emit SuspendedState signal after suspend(), got %1 signals instead")
+ .arg(stateSignal.size())
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.state() == QAudio::SuspendedState), "didn't transitions to SuspendedState after stop()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
stateSignal.clear();
@@ -455,24 +471,35 @@ void tst_QAudioSource::pullSuspendResume()
// Check that only 'elapsed', and not 'processed' increases while suspended
qint64 elapsedUs = audioInput.elapsedUSecs();
qint64 processedUs = audioInput.processedUSecs();
- QVERIFY2(qTolerantCompare(processedUs, 300000LL),
- QString("processedUSecs() doesn't fall in acceptable range, should be 300000 (%1)").arg(processedUs).toUtf8().constData());
+ QVERIFY2(qTolerantCompare(processedUs, 3000000LL),
+ QStringLiteral(
+ "processedUSecs() doesn't fall in acceptable range, should be 3000000 (%1)")
+ .arg(processedUs)
+ .toUtf8()
+ .constData());
QTRY_VERIFY(audioInput.elapsedUSecs() > elapsedUs);
QVERIFY(audioInput.processedUSecs() == processedUs);
audioInput.resume();
// Check that QAudioSource immediately transitions to ActiveState
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit signal after resume(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2((stateSignal.size() == 1),
+ QStringLiteral("didn't emit signal after resume(), got %1 signals instead")
+ .arg(stateSignal.size())
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.state() == QAudio::ActiveState), "didn't transition to ActiveState after resume()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after resume()");
stateSignal.clear();
audioInput.stop();
QTest::qWait(40);
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(stateSignal.size())
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
@@ -491,7 +518,7 @@ void tst_QAudioSource::push()
QAudioSource audioInput(audioFormat, this);
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -514,7 +541,7 @@ void tst_QAudioSource::push()
QIODevice* feed = audioInput.start();
// Check that QAudioSource immediately transitions to IdleState
- QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit IdleState signal on start()");
+ QTRY_VERIFY2((stateSignal.size() == 1),"didn't emit IdleState signal on start()");
QVERIFY2((audioInput.state() == QAudio::IdleState),
"didn't transition to IdleState after start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
@@ -534,7 +561,7 @@ void tst_QAudioSource::push()
totalBytesRead += buffer.size();
if (firstBuffer && buffer.size()) {
// Check for transition to ActiveState when data is provided
- QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit ActiveState signal on data");
+ QTRY_VERIFY2((stateSignal.size() == 1),"didn't emit ActiveState signal on data");
QVERIFY2((audioInput.state() == QAudio::ActiveState),
"didn't transition to ActiveState after data");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
@@ -547,12 +574,20 @@ void tst_QAudioSource::push()
qint64 processedUs = audioInput.processedUSecs();
audioInput.stop();
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(stateSignal.size())
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2(qTolerantCompare(processedUs, 500000LL),
- QString("processedUSecs() doesn't fall in acceptable range, should be 500000 (%1)").arg(processedUs).toUtf8().constData());
+ QStringLiteral(
+ "processedUSecs() doesn't fall in acceptable range, should be 500000 (%1)")
+ .arg(processedUs)
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
QVERIFY2((audioInput.elapsedUSecs() == (qint64)0), "elapsedUSecs() not equal to zero in StoppedState");
@@ -574,7 +609,7 @@ void tst_QAudioSource::pushSuspendResume()
audioInput.setBufferSize(audioFormat.bytesForDuration(100000));
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -594,7 +629,7 @@ void tst_QAudioSource::pushSuspendResume()
QIODevice* feed = audioInput.start();
// Check that QAudioSource immediately transitions to IdleState
- QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit IdleState signal on start()");
+ QTRY_VERIFY2((stateSignal.size() == 1),"didn't emit IdleState signal on start()");
QVERIFY2((audioInput.state() == QAudio::IdleState),
"didn't transition to IdleState after start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
@@ -613,7 +648,7 @@ void tst_QAudioSource::pushSuspendResume()
totalBytesRead += buffer.size();
if (firstBuffer && buffer.size()) {
// Check for transition to ActiveState when data is provided
- QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit ActiveState signal on data");
+ QTRY_VERIFY2((stateSignal.size() == 1),"didn't emit ActiveState signal on data");
QVERIFY2((audioInput.state() == QAudio::ActiveState),
"didn't transition to ActiveState after data");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
@@ -624,8 +659,13 @@ void tst_QAudioSource::pushSuspendResume()
audioInput.suspend();
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit SuspendedState signal after suspend(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral(
+ "didn't emit SuspendedState signal after suspend(), got %1 signals instead")
+ .arg(stateSignal.size())
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.state() == QAudio::SuspendedState), "didn't transitions to SuspendedState after stop()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()");
stateSignal.clear();
@@ -644,7 +684,7 @@ void tst_QAudioSource::pushSuspendResume()
audioInput.resume();
// Check that QAudioSource immediately transitions to Active or IdleState
- QTRY_VERIFY2((stateSignal.count() > 0),"didn't emit signals on resume()");
+ QTRY_VERIFY2((stateSignal.size() > 0),"didn't emit signals on resume()");
QVERIFY2((audioInput.state() == QAudio::ActiveState || audioInput.state() == QAudio::IdleState),
"didn't transition to ActiveState or IdleState after resume()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after resume()");
@@ -665,12 +705,20 @@ void tst_QAudioSource::pushSuspendResume()
processedUs = audioInput.processedUSecs();
audioInput.stop();
- QTRY_VERIFY2((stateSignal.count() == 1),
- QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData());
+ QTRY_VERIFY2(
+ (stateSignal.size() == 1),
+ QStringLiteral("didn't emit StoppedState signal after stop(), got %1 signals instead")
+ .arg(stateSignal.size())
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()");
QVERIFY2(qTolerantCompare(processedUs, 1000000LL),
- QString("processedUSecs() doesn't fall in acceptable range, should be 2040000 (%1)").arg(processedUs).toUtf8().constData());
+ QStringLiteral(
+ "processedUSecs() doesn't fall in acceptable range, should be 2040000 (%1)")
+ .arg(processedUs)
+ .toUtf8()
+ .constData());
QVERIFY2((audioInput.elapsedUSecs() == (qint64)0), "elapsedUSecs() not equal to zero in StoppedState");
//WavHeader::writeDataLength(*audioFile,audioFile->pos()-WavHeader::headerLength());
@@ -687,7 +735,7 @@ void tst_QAudioSource::reset()
{
QAudioSource audioInput(audioFormat, this);
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -696,7 +744,7 @@ void tst_QAudioSource::reset()
QIODevice* device = audioInput.start();
// Check that QAudioSource immediately transitions to IdleState
- QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit IdleState signal on start()");
+ QTRY_VERIFY2((stateSignal.size() == 1),"didn't emit IdleState signal on start()");
QVERIFY2((audioInput.state() == QAudio::IdleState), "didn't transition to IdleState after start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
QTRY_VERIFY2_WITH_TIMEOUT((audioInput.bytesAvailable() > 0), "no bytes available after starting", 10000);
@@ -707,7 +755,7 @@ void tst_QAudioSource::reset()
stateSignal.clear();
audioInput.reset();
- QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit StoppedState signal after reset()");
+ QTRY_VERIFY2((stateSignal.size() == 1),"didn't emit StoppedState signal after reset()");
QVERIFY2((audioInput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after reset()");
QVERIFY2((audioInput.bytesAvailable() == 0), "buffer not cleared after reset()");
}
@@ -717,7 +765,7 @@ void tst_QAudioSource::reset()
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
- QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
+ QSignalSpy stateSignal(&audioInput, &QAudioSource::stateChanged);
// Check that we are in the default state before calling start
QVERIFY2((audioInput.state() == QAudio::StoppedState), "state() was not set to StoppedState before start()");
@@ -727,13 +775,13 @@ void tst_QAudioSource::reset()
audioInput.start(&buffer);
// Check that QAudioSource immediately transitions to ActiveState
- QTRY_VERIFY2((stateSignal.count() >= 1),"didn't emit state changed signal on start()");
+ QTRY_VERIFY2((stateSignal.size() >= 1),"didn't emit state changed signal on start()");
QTRY_VERIFY2((audioInput.state() == QAudio::ActiveState), "didn't transition to ActiveState after start()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
stateSignal.clear();
audioInput.reset();
- QTRY_VERIFY2((stateSignal.count() >= 1),"didn't emit StoppedState signal after reset()");
+ QTRY_VERIFY2((stateSignal.size() >= 1),"didn't emit StoppedState signal after reset()");
QVERIFY2((audioInput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after reset()");
QVERIFY2((audioInput.bytesAvailable() == 0), "buffer not cleared after reset()");
}
diff --git a/tests/auto/integration/qcamerabackend/BLACKLIST b/tests/auto/integration/qcamerabackend/BLACKLIST
index 0521c9fbd..e958c2103 100644
--- a/tests/auto/integration/qcamerabackend/BLACKLIST
+++ b/tests/auto/integration/qcamerabackend/BLACKLIST
@@ -1,3 +1,4 @@
+ci
[testCameraCaptureMetadata]
osx
diff --git a/tests/auto/integration/qcamerabackend/CMakeLists.txt b/tests/auto/integration/qcamerabackend/CMakeLists.txt
index c89456e8a..07a6a4cae 100644
--- a/tests/auto/integration/qcamerabackend/CMakeLists.txt
+++ b/tests/auto/integration/qcamerabackend/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qcamerabackend.pro.
#####################################################################
@@ -7,14 +10,17 @@
qt_internal_add_test(tst_qcamerabackend
SOURCES
tst_qcamerabackend.cpp
- PUBLIC_LIBRARIES
+ ../shared/mediabackendutils.h
+ INCLUDE_DIRECTORIES
+ ../shared/
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
Qt::Widgets
)
# special case begin
-if (APPLE)
+if(APPLE)
set_property(TARGET tst_qcamerabackend PROPERTY MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist")
set_property(TARGET tst_qcamerabackend PROPERTY PROPERTY MACOSX_BUNDLE TRUE)
endif()
diff --git a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp
index 0edc9256e..63790dfd2 100644
--- a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp
+++ b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtGui/QImageReader>
@@ -34,9 +7,11 @@
#include <QtCore/qlocale.h>
#include <QDebug>
#include <QVideoSink>
+#include <QMediaPlayer>
#include <private/qplatformcamera_p.h>
#include <private/qplatformimagecapture_p.h>
+#include <private/qplatformmediaintegration_p.h>
#include <qcamera.h>
#include <qcameradevice.h>
#include <qimagecapture.h>
@@ -47,6 +22,12 @@
#include <qmediaplayer.h>
#include <qaudiooutput.h>
+#ifdef Q_OS_DARWIN
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
+#include <mediabackendutils.h>
+
QT_USE_NAMESPACE
/*
@@ -83,6 +64,8 @@ private slots:
void testNativeMetadata();
+ void multipleCameraSet();
+
private:
bool noCamera = false;
};
@@ -116,6 +99,14 @@ public Q_SLOTS:
if (surfaceFormat.pixelFormat() == cameraFormat.pixelFormat()
&& surfaceFormat.frameSize() == cameraFormat.resolution()) {
formatMismatch = 0;
+#ifdef Q_OS_ANDROID
+ } else if ((surfaceFormat.pixelFormat() == QVideoFrameFormat::Format_YUV420P
+ || surfaceFormat.pixelFormat() == QVideoFrameFormat::Format_NV12)
+ && (cameraFormat.pixelFormat() == QVideoFrameFormat::Format_YUV420P
+ || cameraFormat.pixelFormat() == QVideoFrameFormat::Format_NV12)
+ && surfaceFormat.frameSize() == cameraFormat.resolution()) {
+ formatMismatch = 0;
+#endif
} else {
formatMismatch = 1;
}
@@ -222,8 +213,8 @@ void tst_QCameraBackend::testCameraActive()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy errorSignal(&camera, SIGNAL(errorOccurred(QCamera::Error, const QString &)));
- QSignalSpy activeChangedSignal(&camera, SIGNAL(activeChanged(bool)));
+ QSignalSpy errorSignal(&camera, &QCamera::errorOccurred);
+ QSignalSpy activeChangedSignal(&camera, &QCamera::activeChanged);
QCOMPARE(camera.isActive(), false);
@@ -233,7 +224,7 @@ void tst_QCameraBackend::testCameraActive()
QCOMPARE(camera.error(), QCamera::NoError);
camera.start();
- QCOMPARE(camera.isActive(), true);
+ QTRY_COMPARE(camera.isActive(), true);
QTRY_COMPARE(activeChangedSignal.size(), 1);
QCOMPARE(activeChangedSignal.last().first().value<bool>(), true);
@@ -246,6 +237,14 @@ void tst_QCameraBackend::testCameraActive()
void tst_QCameraBackend::testCameraStartParallel()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Multi-camera feature is currently not supported on Android. "
+ "Cannot open same device twice.");
+#endif
+#ifdef Q_OS_LINUX
+ QSKIP("Multi-camera feature is currently not supported on Linux. "
+ "Cannot open same device twice.");
+#endif
if (noCamera)
QSKIP("No camera available");
@@ -266,8 +265,8 @@ void tst_QCameraBackend::testCameraStartParallel()
QCOMPARE(camera2.isActive(), true);
QCOMPARE(camera2.error(), QCamera::NoError);
- QCOMPARE(errorSpy1.count(), 0);
- QCOMPARE(errorSpy2.count(), 0);
+ QCOMPARE(errorSpy1.size(), 0);
+ QCOMPARE(errorSpy2.size(), 0);
}
void tst_QCameraBackend::testCameraFormat()
@@ -278,15 +277,15 @@ void tst_QCameraBackend::testCameraFormat()
if (videoFormats.isEmpty())
QSKIP("No Camera available, skipping test.");
QCameraFormat cameraFormat = videoFormats.first();
- QSignalSpy spy(&camera, SIGNAL(cameraFormatChanged()));
- QVERIFY(spy.count() == 0);
+ QSignalSpy spy(&camera, &QCamera::cameraFormatChanged);
+ QVERIFY(spy.size() == 0);
QMediaCaptureSession session;
session.setCamera(&camera);
- QVERIFY(videoFormats.count());
+ QVERIFY(videoFormats.size());
camera.setCameraFormat(cameraFormat);
QCOMPARE(camera.cameraFormat(), cameraFormat);
- QVERIFY(spy.count() == 1);
+ QVERIFY(spy.size() == 1);
TestVideoFormat videoFormatTester(cameraFormat);
session.setVideoOutput(&videoFormatTester);
@@ -296,11 +295,11 @@ void tst_QCameraBackend::testCameraFormat()
spy.clear();
camera.stop();
// Change camera format
- if (videoFormats.count() > 1) {
+ if (videoFormats.size() > 1) {
QCameraFormat secondFormat = videoFormats.at(1);
camera.setCameraFormat(secondFormat);
QCOMPARE(camera.cameraFormat(), secondFormat);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(camera.cameraFormat(), secondFormat);
videoFormatTester.setCameraFormatToTest(secondFormat);
camera.start();
@@ -315,7 +314,7 @@ void tst_QCameraBackend::testCameraFormat()
spy.clear();
camera.stop();
camera.setCameraFormat({});
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
videoFormatTester.setCameraFormatToTest({});
camera.start();
// In case of a null format, the backend should have picked
@@ -326,7 +325,7 @@ void tst_QCameraBackend::testCameraFormat()
spy.clear();
// Shouldn't change anything as it's the same device
camera.setCameraDevice(device);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
}
void tst_QCameraBackend::testCameraCapture()
@@ -342,9 +341,9 @@ void tst_QCameraBackend::testCameraCapture()
QVERIFY(!imageCapture.isReadyForCapture());
- QSignalSpy capturedSignal(&imageCapture, SIGNAL(imageCaptured(int,QImage)));
- QSignalSpy savedSignal(&imageCapture, SIGNAL(imageSaved(int,QString)));
- QSignalSpy errorSignal(&imageCapture, SIGNAL(errorOccurred(int,QImageCapture::Error,const QString&)));
+ QSignalSpy capturedSignal(&imageCapture, &QImageCapture::imageCaptured);
+ QSignalSpy savedSignal(&imageCapture, &QImageCapture::imageSaved);
+ QSignalSpy errorSignal(&imageCapture, &QImageCapture::errorOccurred);
imageCapture.captureToFile();
QTRY_COMPARE(errorSignal.size(), 1);
@@ -365,7 +364,7 @@ void tst_QCameraBackend::testCameraCapture()
int id = imageCapture.captureToFile();
- QTRY_VERIFY(!savedSignal.isEmpty());
+ QTRY_VERIFY_WITH_TIMEOUT(!savedSignal.isEmpty(), 8s);
QTRY_COMPARE(capturedSignal.size(), 1);
QCOMPARE(capturedSignal.last().first().toInt(), id);
@@ -401,10 +400,10 @@ void tst_QCameraBackend::testCaptureToBuffer()
QTRY_VERIFY(camera.isActive());
- QSignalSpy capturedSignal(&imageCapture, SIGNAL(imageCaptured(int,QImage)));
- QSignalSpy imageAvailableSignal(&imageCapture, SIGNAL(imageAvailable(int,QVideoFrame)));
- QSignalSpy savedSignal(&imageCapture, SIGNAL(imageSaved(int,QString)));
- QSignalSpy errorSignal(&imageCapture, SIGNAL(errorOccurred(int,QImageCapture::Error,const QString&)));
+ QSignalSpy capturedSignal(&imageCapture, &QImageCapture::imageCaptured);
+ QSignalSpy imageAvailableSignal(&imageCapture, &QImageCapture::imageAvailable);
+ QSignalSpy savedSignal(&imageCapture, &QImageCapture::imageSaved);
+ QSignalSpy errorSignal(&imageCapture, &QImageCapture::errorOccurred);
camera.start();
QTRY_VERIFY(imageCapture.isReadyForCapture());
@@ -446,8 +445,14 @@ void tst_QCameraBackend::testCameraCaptureMetadata()
camera.setFlashMode(QCamera::FlashOff);
- QSignalSpy metadataSignal(&imageCapture, SIGNAL(imageMetadataAvailable(int,const QMediaMetaData&)));
- QSignalSpy savedSignal(&imageCapture, SIGNAL(imageSaved(int,QString)));
+ QMediaMetaData referenceMetaData;
+ referenceMetaData.insert(QMediaMetaData::Title, QStringLiteral("Title"));
+ referenceMetaData.insert(QMediaMetaData::Language, QVariant::fromValue(QLocale::German));
+ referenceMetaData.insert(QMediaMetaData::Description, QStringLiteral("Description"));
+ imageCapture.setMetaData(referenceMetaData);
+
+ QSignalSpy metadataSignal(&imageCapture, &QImageCapture::imageMetadataAvailable);
+ QSignalSpy savedSignal(&imageCapture, &QImageCapture::imageSaved);
camera.start();
@@ -458,7 +463,19 @@ void tst_QCameraBackend::testCameraCaptureMetadata()
int id = imageCapture.captureToFile(tmpFile);
QTRY_VERIFY(!savedSignal.isEmpty());
QVERIFY(!metadataSignal.isEmpty());
+
QCOMPARE(metadataSignal.first().first().toInt(), id);
+ QMediaMetaData receivedMetaData = metadataSignal.first()[1].value<QMediaMetaData>();
+
+ if (isGStreamerPlatform()) {
+ for (auto key : {
+ QMediaMetaData::Title,
+ QMediaMetaData::Language,
+ QMediaMetaData::Description,
+ })
+ QCOMPARE(receivedMetaData[key], referenceMetaData[key]);
+ QVERIFY(receivedMetaData[QMediaMetaData::Resolution].isValid());
+ }
}
void tst_QCameraBackend::testExposureCompensation()
@@ -470,22 +487,22 @@ void tst_QCameraBackend::testExposureCompensation()
QCamera camera;
session.setCamera(&camera);
- QSignalSpy exposureCompensationSignal(&camera, SIGNAL(exposureCompensationChanged(float)));
+ QSignalSpy exposureCompensationSignal(&camera, &QCamera::exposureCompensationChanged);
- //it should be possible to set exposure parameters in Unloaded state
+ // it should be possible to set exposure parameters in Unloaded state
QCOMPARE(camera.exposureCompensation(), 0.);
if (!(camera.supportedFeatures() & QCamera::Feature::ExposureCompensation))
return;
camera.setExposureCompensation(1.0);
QCOMPARE(camera.exposureCompensation(), 1.0);
- QTRY_COMPARE(exposureCompensationSignal.count(), 1);
+ QTRY_COMPARE(exposureCompensationSignal.size(), 1);
QCOMPARE(exposureCompensationSignal.last().first().toReal(), 1.0);
//exposureCompensationChanged should not be emitted when value is not changed
camera.setExposureCompensation(1.0);
QTest::qWait(50);
- QCOMPARE(exposureCompensationSignal.count(), 1);
+ QCOMPARE(exposureCompensationSignal.size(), 1);
//exposure compensation should be preserved during start
camera.start();
@@ -496,7 +513,7 @@ void tst_QCameraBackend::testExposureCompensation()
exposureCompensationSignal.clear();
camera.setExposureCompensation(-1.0);
QCOMPARE(camera.exposureCompensation(), -1.0);
- QTRY_COMPARE(exposureCompensationSignal.count(), 1);
+ QTRY_COMPARE(exposureCompensationSignal.size(), 1);
QCOMPARE(exposureCompensationSignal.last().first().toReal(), -1.0);
}
@@ -525,7 +542,7 @@ void tst_QCameraBackend::testExposureMode()
camera.setExposureMode(QCamera::ExposureAuto);
QCOMPARE(camera.exposureMode(), QCamera::ExposureAuto);
camera.start();
- QVERIFY(camera.isActive());
+ QTRY_VERIFY(camera.isActive());
QCOMPARE(camera.exposureMode(), QCamera::ExposureAuto);
// Manual
@@ -569,16 +586,16 @@ void tst_QCameraBackend::testVideoRecording()
QMediaRecorder recorder;
session.setRecorder(&recorder);
- QSignalSpy errorSignal(camera.data(), SIGNAL(errorOccurred(QCamera::Error, const QString &)));
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy recorderStateChanged(&recorder, SIGNAL(recorderStateChanged(RecorderState)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy errorSignal(camera.data(), &QCamera::errorOccurred);
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy recorderStateChanged(&recorder, &QMediaRecorder::recorderStateChanged);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
recorder.setVideoResolution(320, 240);
// Insert metadata
QMediaMetaData metaData;
- metaData.insert(QMediaMetaData::Author, QString::fromUtf8("Author"));
+ metaData.insert(QMediaMetaData::Author, QStringLiteral("Author"));
metaData.insert(QMediaMetaData::Date, QDateTime::currentDateTime());
recorder.setMetaData(metaData);
@@ -591,27 +608,41 @@ void tst_QCameraBackend::testVideoRecording()
QTRY_VERIFY(camera->isActive());
- for (int recordings = 0; recordings < 2; ++recordings) {
- //record 200ms clip
- recorder.record();
- durationChanged.clear();
- QTRY_VERIFY(durationChanged.count());
+ recorder.record();
+ if (!recorderErrorSignal.empty() || recorderErrorSignal.wait(550)) {
+ QEXPECT_FAIL_GSTREAMER("", "QTBUG-124148: GStreamer might return ResourceError", Continue);
+
+ QCOMPARE(recorderErrorSignal.last().first().toInt(), QMediaRecorder::FormatError);
+ return;
+ }
+
+ QTRY_VERIFY(durationChanged.size());
- QCOMPARE(recorder.metaData(), metaData);
+ QCOMPARE(recorder.metaData(), metaData);
- recorderStateChanged.clear();
- recorder.stop();
- QTRY_VERIFY(recorderStateChanged.size() > 0);
- QVERIFY(recorder.recorderState() == QMediaRecorder::StoppedState);
+ recorderStateChanged.clear();
+ recorder.stop();
+ QTRY_VERIFY(recorderStateChanged.size() > 0);
+ QVERIFY(recorder.recorderState() == QMediaRecorder::StoppedState);
- QVERIFY(errorSignal.isEmpty());
- QVERIFY(recorderErrorSignal.isEmpty());
+ QVERIFY(errorSignal.isEmpty());
+ QVERIFY(recorderErrorSignal.isEmpty());
- QString fileName = recorder.actualLocation().toLocalFile();
- QVERIFY(!fileName.isEmpty());
- QVERIFY(QFileInfo(fileName).size() > 0);
- QFile(fileName).remove();
- }
+ QString fileName = recorder.actualLocation().toLocalFile();
+ QVERIFY(!fileName.isEmpty());
+ QVERIFY(QFileInfo(fileName).size() > 0);
+
+ QMediaPlayer player;
+ player.setSource(fileName);
+
+ QTRY_COMPARE_WITH_TIMEOUT(player.mediaStatus(), QMediaPlayer::LoadedMedia, 8s);
+ QCOMPARE_EQ(player.metaData().value(QMediaMetaData::Resolution).toSize(), QSize(320, 240));
+ QCOMPARE_GT(player.duration(), 350);
+ QCOMPARE_LT(player.duration(), 650);
+
+ // TODO: integrate with a virtual camera and check mediaplayer output
+
+ QFile(fileName).remove();
}
void tst_QCameraBackend::testNativeMetadata()
@@ -627,10 +658,10 @@ void tst_QCameraBackend::testNativeMetadata()
QMediaRecorder recorder;
session.setRecorder(&recorder);
- QSignalSpy errorSignal(&camera, SIGNAL(errorOccurred(QCamera::Error, const QString &)));
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy recorderStateChanged(&recorder, SIGNAL(recorderStateChanged(RecorderState)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy errorSignal(&camera, &QCamera::errorOccurred);
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy recorderStateChanged(&recorder, &QMediaRecorder::recorderStateChanged);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
camera.start();
if (device.isNull()) {
@@ -643,15 +674,15 @@ void tst_QCameraBackend::testNativeMetadata()
// Insert common metadata supported on all platforms
// Don't use Date, as some backends set that on their own
QMediaMetaData metaData;
- metaData.insert(QMediaMetaData::Title, QString::fromUtf8("Title"));
+ metaData.insert(QMediaMetaData::Title, QStringLiteral("Title"));
metaData.insert(QMediaMetaData::Language, QVariant::fromValue(QLocale::German));
- metaData.insert(QMediaMetaData::Description, QString::fromUtf8("Description"));
+ metaData.insert(QMediaMetaData::Description, QStringLiteral("Description"));
recorder.setMetaData(metaData);
recorder.record();
- durationChanged.clear();
- QTRY_VERIFY(durationChanged.count());
+ QTRY_VERIFY(durationChanged.size());
+ QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::RecorderState::RecordingState);
QCOMPARE(recorder.metaData(), metaData);
@@ -659,9 +690,13 @@ void tst_QCameraBackend::testNativeMetadata()
recorder.stop();
QTRY_VERIFY(recorderStateChanged.size() > 0);
+ QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::RecorderState::StoppedState);
QVERIFY(errorSignal.isEmpty());
- QVERIFY(recorderErrorSignal.isEmpty());
+ if (!isGStreamerPlatform()) {
+ // https://bugreports.qt.io/browse/QTBUG-124183
+ QVERIFY(recorderErrorSignal.isEmpty());
+ }
QString fileName = recorder.actualLocation().toLocalFile();
QVERIFY(!fileName.isEmpty());
@@ -669,30 +704,60 @@ void tst_QCameraBackend::testNativeMetadata()
// QMediaRecorder::metaData() can only test that QMediaMetaData is set properly on the recorder.
// Use QMediaPlayer to test that the native metadata is properly set on the track
- QMediaPlayer player;
QAudioOutput output;
+ QMediaPlayer player;
player.setAudioOutput(&output);
- QSignalSpy metadataChangedSpy(&player, SIGNAL(metaDataChanged()));
+ QSignalSpy metadataChangedSpy(&player, &QMediaPlayer::metaDataChanged);
player.setSource(QUrl::fromLocalFile(fileName));
player.play();
- QTRY_VERIFY(metadataChangedSpy.count() > 0);
+ int metadataChangedRequiredCount = isGStreamerPlatform() ? 2 : 1;
+
+ QTRY_VERIFY(metadataChangedSpy.size() >= metadataChangedRequiredCount);
- QCOMPARE(player.metaData().value(QMediaMetaData::Title).toString(), metaData.value(QMediaMetaData::Title).toString());
+ QCOMPARE(player.metaData().value(QMediaMetaData::Title).toString(),
+ metaData.value(QMediaMetaData::Title).toString());
auto lang = player.metaData().value(QMediaMetaData::Language).value<QLocale::Language>();
if (lang != QLocale::AnyLanguage)
QCOMPARE(lang, metaData.value(QMediaMetaData::Language).value<QLocale::Language>());
QCOMPARE(player.metaData().value(QMediaMetaData::Description).toString(), metaData.value(QMediaMetaData::Description).toString());
+ QVERIFY(player.metaData().value(QMediaMetaData::Resolution).isValid());
- metadataChangedSpy.clear();
+ if (isGStreamerPlatform())
+ QVERIFY(player.metaData().value(QMediaMetaData::Date).isValid());
player.stop();
player.setSource({});
QFile(fileName).remove();
}
+void tst_QCameraBackend::multipleCameraSet()
+{
+ if (noCamera)
+ QSKIP("No camera available");
+
+ QMediaCaptureSession session;
+ QCameraDevice device = QMediaDevices::defaultVideoInput();
+
+ QMediaRecorder recorder;
+ session.setRecorder(&recorder);
+
+ for (int i = 0; i < 5; ++i) {
+#ifdef Q_OS_DARWIN
+ QMacAutoReleasePool releasePool;
+#endif
+
+ QCamera camera(device);
+ session.setCamera(&camera);
+
+ camera.start();
+
+ QTest::qWait(100);
+ }
+}
+
QTEST_MAIN(tst_QCameraBackend)
#include "tst_qcamerabackend.moc"
diff --git a/tests/auto/integration/qmediacapturesession/BLACKLIST b/tests/auto/integration/qmediacapturesession/BLACKLIST
new file mode 100644
index 000000000..550ecdd6f
--- /dev/null
+++ b/tests/auto/integration/qmediacapturesession/BLACKLIST
@@ -0,0 +1 @@
+ci
diff --git a/tests/auto/integration/qmediacapturesession/CMakeLists.txt b/tests/auto/integration/qmediacapturesession/CMakeLists.txt
index 63ac2e99f..1aec26493 100644
--- a/tests/auto/integration/qmediacapturesession/CMakeLists.txt
+++ b/tests/auto/integration/qmediacapturesession/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qcamerabackend.pro.
#####################################################################
@@ -7,7 +10,10 @@
qt_internal_add_test(tst_qmediacapturesession
SOURCES
tst_qmediacapturesession.cpp
- PUBLIC_LIBRARIES
+ ../shared/mediabackendutils.h
+ INCLUDE_DIRECTORIES
+ ../shared/
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
Qt::MultimediaWidgets
diff --git a/tests/auto/integration/qmediacapturesession/tst_qmediacapturesession.cpp b/tests/auto/integration/qmediacapturesession/tst_qmediacapturesession.cpp
index a5a3741b2..0a42851e5 100644
--- a/tests/auto/integration/qmediacapturesession/tst_qmediacapturesession.cpp
+++ b/tests/auto/integration/qmediacapturesession/tst_qmediacapturesession.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtGui/QImageReader>
@@ -34,6 +7,7 @@
#include <QDebug>
#include <QVideoSink>
#include <QVideoWidget>
+#include <QSysInfo>
#include <qcamera.h>
#include <qcameradevice.h>
@@ -47,11 +21,17 @@
#include <qaudiodevice.h>
#include <qaudiodecoder.h>
#include <qaudiobuffer.h>
+#include <qscreencapture.h>
+#include <qwindowcapture.h>
+#include <qaudiobufferinput.h>
+#include <qvideoframeinput.h>
#include <qcamera.h>
#include <QMediaFormat>
#include <QtMultimediaWidgets/QVideoWidget>
+#include <mediabackendutils.h>
+
QT_USE_NAMESPACE
/*
@@ -69,6 +49,12 @@ private slots:
void testAudioMute();
void stress_test_setup_and_teardown();
+ void stress_test_setup_and_teardown_keep_session();
+ void stress_test_setup_and_teardown_keep_recorder();
+ void stress_test_setup_and_teardown_keep_camera();
+ void stress_test_setup_and_teardown_keep_audioinput();
+ void stress_test_setup_and_teardown_keep_audiooutput();
+ void stress_test_setup_and_teardown_keep_video();
void record_video_without_preview();
@@ -77,9 +63,16 @@ private slots:
void can_change_AudioInput_during_recording();
void disconnects_deleted_AudioInput();
void can_move_AudioInput_between_sessions();
+
void disconnects_deleted_AudioOutput();
void can_move_AudioOutput_between_sessions_and_player();
+ void disconnects_deleted_AudioBufferInput();
+ void can_move_AudioBufferInput_between_sessions();
+
+ void disconnects_deleted_VideoFrameInput();
+ void can_move_VideoFrameInput_between_sessions();
+
void can_add_and_remove_Camera();
void can_move_Camera_between_sessions();
void can_disconnect_Camera_when_recording();
@@ -101,6 +94,8 @@ private slots:
void capture_is_not_available_when_Camera_is_null();
void can_add_ImageCapture_and_capture_during_recording();
+ void can_reset_audio_input_output();
+
private:
void recordOk(QMediaCaptureSession &session);
void recordFail(QMediaCaptureSession &session);
@@ -112,8 +107,8 @@ void tst_QMediaCaptureSession::recordOk(QMediaCaptureSession &session)
QMediaRecorder recorder;
session.setRecorder(&recorder);
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
recorder.record();
QTRY_VERIFY_WITH_TIMEOUT(recorder.recorderState() == QMediaRecorder::RecordingState, 2000);
@@ -132,12 +127,12 @@ void tst_QMediaCaptureSession::recordOk(QMediaCaptureSession &session)
void tst_QMediaCaptureSession::recordFail(QMediaCaptureSession &session)
{
QMediaRecorder recorder;
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
session.setRecorder(&recorder);
recorder.record();
- QTRY_VERIFY_WITH_TIMEOUT(recorderErrorSignal.count() == 1, 2000);
+ QTRY_VERIFY_WITH_TIMEOUT(recorderErrorSignal.size() == 1, 2000);
QTRY_VERIFY_WITH_TIMEOUT(recorder.recorderState() == QMediaRecorder::StoppedState, 2000);
}
@@ -162,6 +157,132 @@ void tst_QMediaCaptureSession::stress_test_setup_and_teardown()
}
}
+void tst_QMediaCaptureSession::stress_test_setup_and_teardown_keep_session()
+{
+ QMediaCaptureSession session;
+ for (int i = 0; i < 50; i++) {
+ QMediaRecorder recorder;
+ QCamera camera;
+ QAudioInput input;
+ QAudioOutput output;
+ QVideoWidget video;
+
+ session.setAudioInput(&input);
+ session.setAudioOutput(&output);
+ session.setRecorder(&recorder);
+ session.setCamera(&camera);
+ session.setVideoOutput(&video);
+
+ QRandomGenerator rng;
+ QTest::qWait(rng.bounded(200));
+ }
+}
+
+void tst_QMediaCaptureSession::stress_test_setup_and_teardown_keep_recorder()
+{
+ QMediaCaptureSession session;
+ QMediaRecorder recorder;
+ for (int i = 0; i < 50; i++) {
+ QCamera camera;
+ QAudioInput input;
+ QAudioOutput output;
+ QVideoWidget video;
+
+ session.setAudioInput(&input);
+ session.setAudioOutput(&output);
+ session.setRecorder(&recorder);
+ session.setCamera(&camera);
+ session.setVideoOutput(&video);
+
+ QRandomGenerator rng;
+ QTest::qWait(rng.bounded(200));
+ }
+}
+
+void tst_QMediaCaptureSession::stress_test_setup_and_teardown_keep_camera()
+{
+ QCamera camera;
+ for (int i = 0; i < 50; i++) {
+ QMediaCaptureSession session;
+ QMediaRecorder recorder;
+ QAudioInput input;
+ QAudioOutput output;
+ QVideoWidget video;
+
+ session.setAudioInput(&input);
+ session.setAudioOutput(&output);
+ session.setRecorder(&recorder);
+ session.setCamera(&camera);
+ session.setVideoOutput(&video);
+
+ QRandomGenerator rng;
+ QTest::qWait(rng.bounded(200));
+ }
+}
+
+void tst_QMediaCaptureSession::stress_test_setup_and_teardown_keep_audioinput()
+{
+ QAudioInput input;
+ for (int i = 0; i < 50; i++) {
+ QMediaCaptureSession session;
+ QMediaRecorder recorder;
+ QCamera camera;
+ QAudioOutput output;
+ QVideoWidget video;
+
+ session.setAudioInput(&input);
+ session.setAudioOutput(&output);
+ session.setRecorder(&recorder);
+ session.setCamera(&camera);
+ session.setVideoOutput(&video);
+
+ QRandomGenerator rng;
+ QTest::qWait(rng.bounded(200));
+ }
+}
+
+void tst_QMediaCaptureSession::stress_test_setup_and_teardown_keep_audiooutput()
+{
+ QAudioOutput output;
+ for (int i = 0; i < 50; i++) {
+ QMediaCaptureSession session;
+ QMediaRecorder recorder;
+ QCamera camera;
+ QAudioInput input;
+ QVideoWidget video;
+
+ session.setAudioInput(&input);
+ session.setAudioOutput(&output);
+ session.setRecorder(&recorder);
+ session.setCamera(&camera);
+ session.setVideoOutput(&video);
+
+ QRandomGenerator rng;
+ QTest::qWait(rng.bounded(200));
+ }
+}
+
+void tst_QMediaCaptureSession::stress_test_setup_and_teardown_keep_video()
+{
+ QVideoWidget video;
+ for (int i = 0; i < 50; i++) {
+ QMediaCaptureSession session;
+ QMediaRecorder recorder;
+ QCamera camera;
+ QAudioInput input;
+ QAudioOutput output;
+
+ session.setAudioInput(&input);
+ session.setAudioOutput(&output);
+ session.setRecorder(&recorder);
+ session.setCamera(&camera);
+ session.setVideoOutput(&video);
+
+ QRandomGenerator rng;
+ QTest::qWait(rng.bounded(200));
+ }
+}
+
void tst_QMediaCaptureSession::record_video_without_preview()
{
QCamera camera;
@@ -174,17 +295,18 @@ void tst_QMediaCaptureSession::record_video_without_preview()
session.setRecorder(&recorder);
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
session.setCamera(&camera);
camera.setActive(true);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
+ QTRY_COMPARE(camera.isActive(), true);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
session.setCamera(nullptr);
- QTRY_COMPARE(cameraChanged.count(), 2);
+ QTRY_COMPARE(cameraChanged.size(), 2);
// can't record without audio and video
recordFail(session);
@@ -198,29 +320,29 @@ void tst_QMediaCaptureSession::can_add_and_remove_AudioInput_with_and_without_Au
QSKIP("No audio input available");
QMediaCaptureSession session;
- QSignalSpy audioInputChanged(&session, SIGNAL(audioInputChanged()));
- QSignalSpy audioOutputChanged(&session, SIGNAL(audioOutputChanged()));
+ QSignalSpy audioInputChanged(&session, &QMediaCaptureSession::audioInputChanged);
+ QSignalSpy audioOutputChanged(&session, &QMediaCaptureSession::audioOutputChanged);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 1);
+ QTRY_COMPARE(audioInputChanged.size(), 1);
session.setAudioInput(nullptr);
- QTRY_COMPARE(audioInputChanged.count(), 2);
+ QTRY_COMPARE(audioInputChanged.size(), 2);
QAudioOutput output;
if (output.device().isNull())
return;
session.setAudioOutput(&output);
- QTRY_COMPARE(audioOutputChanged.count(), 1);
+ QTRY_COMPARE(audioOutputChanged.size(), 1);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 3);
+ QTRY_COMPARE(audioInputChanged.size(), 3);
session.setAudioOutput(nullptr);
- QTRY_COMPARE(audioOutputChanged.count(), 2);
+ QTRY_COMPARE(audioOutputChanged.size(), 2);
session.setAudioInput(nullptr);
- QTRY_COMPARE(audioInputChanged.count(), 4);
+ QTRY_COMPARE(audioInputChanged.size(), 4);
}
void tst_QMediaCaptureSession::can_change_AudioDevices_on_attached_AudioInput()
@@ -230,25 +352,25 @@ void tst_QMediaCaptureSession::can_change_AudioDevices_on_attached_AudioInput()
QSKIP("Two audio inputs are not available");
QAudioInput input(audioInputs[0]);
- QSignalSpy deviceChanged(&input, SIGNAL(deviceChanged()));
+ QSignalSpy deviceChanged(&input, &QAudioInput::deviceChanged);
QMediaCaptureSession session;
- QSignalSpy audioInputChanged(&session, SIGNAL(audioInputChanged()));
+ QSignalSpy audioInputChanged(&session, &QMediaCaptureSession::audioInputChanged);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 1);
+ QTRY_COMPARE(audioInputChanged.size(), 1);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
input.setDevice(audioInputs[1]);
- QTRY_COMPARE(deviceChanged.count(), 1);
+ QTRY_COMPARE(deviceChanged.size(), 1);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
input.setDevice(audioInputs[0]);
- QTRY_COMPARE(deviceChanged.count(), 2);
+ QTRY_COMPARE(deviceChanged.size(), 2);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
@@ -265,27 +387,27 @@ void tst_QMediaCaptureSession::can_change_AudioInput_during_recording()
session.setRecorder(&recorder);
- QSignalSpy audioInputChanged(&session, SIGNAL(audioInputChanged()));
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy audioInputChanged(&session, &QMediaCaptureSession::audioInputChanged);
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 1);
+ QTRY_COMPARE(audioInputChanged.size(), 1);
recorder.record();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::RecordingState);
QVERIFY(durationChanged.wait(2000));
session.setAudioInput(nullptr);
- QTRY_COMPARE(audioInputChanged.count(), 2);
+ QTRY_COMPARE(audioInputChanged.size(), 2);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 3);
+ QTRY_COMPARE(audioInputChanged.size(), 3);
recorder.stop();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::StoppedState);
QVERIFY(recorderErrorSignal.isEmpty());
session.setAudioInput(nullptr);
- QTRY_COMPARE(audioInputChanged.count(), 4);
+ QTRY_COMPARE(audioInputChanged.size(), 4);
QString fileName = recorder.actualLocation().toLocalFile();
QVERIFY(!fileName.isEmpty());
@@ -299,14 +421,14 @@ void tst_QMediaCaptureSession::disconnects_deleted_AudioInput()
QSKIP("No audio input available");
QMediaCaptureSession session;
- QSignalSpy audioInputChanged(&session, SIGNAL(audioInputChanged()));
+ QSignalSpy audioInputChanged(&session, &QMediaCaptureSession::audioInputChanged);
{
QAudioInput input;
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 1);
+ QTRY_COMPARE(audioInputChanged.size(), 1);
}
QVERIFY(session.audioInput() == nullptr);
- QTRY_COMPARE(audioInputChanged.count(), 2);
+ QTRY_COMPARE(audioInputChanged.size(), 2);
}
void tst_QMediaCaptureSession::can_move_AudioInput_between_sessions()
@@ -316,24 +438,24 @@ void tst_QMediaCaptureSession::can_move_AudioInput_between_sessions()
QMediaCaptureSession session0;
QMediaCaptureSession session1;
- QSignalSpy audioInputChanged0(&session0, SIGNAL(audioInputChanged()));
- QSignalSpy audioInputChanged1(&session1, SIGNAL(audioInputChanged()));
+ QSignalSpy audioInputChanged0(&session0, &QMediaCaptureSession::audioInputChanged);
+ QSignalSpy audioInputChanged1(&session1, &QMediaCaptureSession::audioInputChanged);
QAudioInput input;
{
QMediaCaptureSession session2;
- QSignalSpy audioInputChanged2(&session2, SIGNAL(audioInputChanged()));
+ QSignalSpy audioInputChanged2(&session2, &QMediaCaptureSession::audioInputChanged);
session2.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged2.count(), 1);
+ QTRY_COMPARE(audioInputChanged2.size(), 1);
}
session0.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged0.count(), 1);
+ QTRY_COMPARE(audioInputChanged0.size(), 1);
QVERIFY(session0.audioInput() != nullptr);
session1.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged0.count(), 2);
+ QTRY_COMPARE(audioInputChanged0.size(), 2);
QVERIFY(session0.audioInput() == nullptr);
- QTRY_COMPARE(audioInputChanged1.count(), 1);
+ QTRY_COMPARE(audioInputChanged1.size(), 1);
QVERIFY(session1.audioInput() != nullptr);
}
@@ -343,14 +465,14 @@ void tst_QMediaCaptureSession::disconnects_deleted_AudioOutput()
QSKIP("No audio output available");
QMediaCaptureSession session;
- QSignalSpy audioOutputChanged(&session, SIGNAL(audioOutputChanged()));
+ QSignalSpy audioOutputChanged(&session, &QMediaCaptureSession::audioOutputChanged);
{
QAudioOutput output;
session.setAudioOutput(&output);
- QTRY_COMPARE(audioOutputChanged.count(), 1);
+ QTRY_COMPARE(audioOutputChanged.size(), 1);
}
QVERIFY(session.audioOutput() == nullptr);
- QTRY_COMPARE(audioOutputChanged.count(), 2);
+ QTRY_COMPARE(audioOutputChanged.size(), 2);
}
void tst_QMediaCaptureSession::can_move_AudioOutput_between_sessions_and_player()
@@ -358,46 +480,130 @@ void tst_QMediaCaptureSession::can_move_AudioOutput_between_sessions_and_player(
if (QMediaDevices::audioOutputs().isEmpty())
QSKIP("No audio output available");
+ QAudioOutput output;
+
QMediaCaptureSession session0;
QMediaCaptureSession session1;
QMediaPlayer player;
- QSignalSpy audioOutputChanged0(&session0, SIGNAL(audioOutputChanged()));
- QSignalSpy audioOutputChanged1(&session1, SIGNAL(audioOutputChanged()));
- QSignalSpy audioOutputChangedPlayer(&player, SIGNAL(audioOutputChanged()));
+ QSignalSpy audioOutputChanged0(&session0, &QMediaCaptureSession::audioOutputChanged);
+ QSignalSpy audioOutputChanged1(&session1, &QMediaCaptureSession::audioOutputChanged);
+ QSignalSpy audioOutputChangedPlayer(&player, &QMediaPlayer::audioOutputChanged);
- QAudioOutput output;
{
QMediaCaptureSession session2;
- QSignalSpy audioOutputChanged2(&session2, SIGNAL(audioOutputChanged()));
+ QSignalSpy audioOutputChanged2(&session2, &QMediaCaptureSession::audioOutputChanged);
session2.setAudioOutput(&output);
- QTRY_COMPARE(audioOutputChanged2.count(), 1);
+ QTRY_COMPARE(audioOutputChanged2.size(), 1);
}
session0.setAudioOutput(&output);
- QTRY_COMPARE(audioOutputChanged0.count(), 1);
+ QTRY_COMPARE(audioOutputChanged0.size(), 1);
QVERIFY(session0.audioOutput() != nullptr);
session1.setAudioOutput(&output);
- QTRY_COMPARE(audioOutputChanged0.count(), 2);
+ QTRY_COMPARE(audioOutputChanged0.size(), 2);
QVERIFY(session0.audioOutput() == nullptr);
- QTRY_COMPARE(audioOutputChanged1.count(), 1);
+ QTRY_COMPARE(audioOutputChanged1.size(), 1);
QVERIFY(session1.audioOutput() != nullptr);
player.setAudioOutput(&output);
- QTRY_COMPARE(audioOutputChanged0.count(), 2);
+ QTRY_COMPARE(audioOutputChanged0.size(), 2);
QVERIFY(session0.audioOutput() == nullptr);
- QTRY_COMPARE(audioOutputChanged1.count(), 2);
+ QTRY_COMPARE(audioOutputChanged1.size(), 2);
QVERIFY(session1.audioOutput() == nullptr);
- QTRY_COMPARE(audioOutputChangedPlayer.count(), 1);
+ QTRY_COMPARE(audioOutputChangedPlayer.size(), 1);
QVERIFY(player.audioOutput() != nullptr);
session0.setAudioOutput(&output);
- QTRY_COMPARE(audioOutputChanged0.count(), 3);
+ QTRY_COMPARE(audioOutputChanged0.size(), 3);
QVERIFY(session0.audioOutput() != nullptr);
- QTRY_COMPARE(audioOutputChangedPlayer.count(), 2);
+ QTRY_COMPARE(audioOutputChangedPlayer.size(), 2);
QVERIFY(player.audioOutput() == nullptr);
}
+void tst_QMediaCaptureSession::disconnects_deleted_AudioBufferInput()
+{
+ QMediaCaptureSession session;
+ QSignalSpy audioBufferInputChanged(&session, &QMediaCaptureSession::audioBufferInputChanged);
+ {
+ QAudioBufferInput input;
+ session.setAudioBufferInput(&input);
+ QTRY_COMPARE(audioBufferInputChanged.size(), 1);
+ }
+ QCOMPARE(session.audioBufferInput(), nullptr);
+ QCOMPARE(audioBufferInputChanged.size(), 2);
+}
+
+void tst_QMediaCaptureSession::can_move_AudioBufferInput_between_sessions()
+{
+ QMediaCaptureSession session0;
+ QMediaCaptureSession session1;
+ QSignalSpy audioBufferInputChanged0(&session0, &QMediaCaptureSession::audioBufferInputChanged);
+ QSignalSpy audioBufferInputChanged1(&session1, &QMediaCaptureSession::audioBufferInputChanged);
+
+ QAudioBufferInput input;
+ {
+ QMediaCaptureSession session2;
+ QSignalSpy audioBufferInputChanged2(&session2,
+ &QMediaCaptureSession::audioBufferInputChanged);
+ session2.setAudioBufferInput(&input);
+ QCOMPARE(audioBufferInputChanged2.size(), 1);
+ }
+ session0.setAudioBufferInput(&input);
+ QCOMPARE(audioBufferInputChanged0.size(), 1);
+ QCOMPARE(session0.audioBufferInput(), &input);
+ QCOMPARE(input.captureSession(), &session0);
+
+ session1.setAudioBufferInput(&input);
+
+ QCOMPARE(audioBufferInputChanged0.size(), 2);
+ QCOMPARE(session0.audioBufferInput(), nullptr);
+ QCOMPARE(audioBufferInputChanged1.size(), 1);
+ QCOMPARE(session1.audioBufferInput(), &input);
+ QCOMPARE(input.captureSession(), &session1);
+}
+
+void tst_QMediaCaptureSession::disconnects_deleted_VideoFrameInput()
+{
+ QMediaCaptureSession session;
+ QSignalSpy videoFrameInputChanged(&session, &QMediaCaptureSession::videoFrameInputChanged);
+ {
+ QVideoFrameInput input;
+ session.setVideoFrameInput(&input);
+ QTRY_COMPARE(videoFrameInputChanged.size(), 1);
+ }
+ QCOMPARE(session.videoFrameInput(), nullptr);
+ QCOMPARE(videoFrameInputChanged.size(), 2);
+}
+
+void tst_QMediaCaptureSession::can_move_VideoFrameInput_between_sessions()
+{
+ QMediaCaptureSession session0;
+ QMediaCaptureSession session1;
+ QSignalSpy videoFrameInputChanged0(&session0, &QMediaCaptureSession::videoFrameInputChanged);
+ QSignalSpy videoFrameInputChanged1(&session1, &QMediaCaptureSession::videoFrameInputChanged);
+
+ QVideoFrameInput input;
+ {
+ QMediaCaptureSession session2;
+ QSignalSpy videoFrameInputChanged2(&session2,
+ &QMediaCaptureSession::videoFrameInputChanged);
+ session2.setVideoFrameInput(&input);
+ QCOMPARE(videoFrameInputChanged2.size(), 1);
+ }
+ session0.setVideoFrameInput(&input);
+ QCOMPARE(videoFrameInputChanged0.size(), 1);
+ QCOMPARE(session0.videoFrameInput(), &input);
+ QCOMPARE(input.captureSession(), &session0);
+
+ session1.setVideoFrameInput(&input);
+
+ QCOMPARE(videoFrameInputChanged0.size(), 2);
+ QCOMPARE(session0.videoFrameInput(), nullptr);
+ QCOMPARE(videoFrameInputChanged1.size(), 1);
+ QCOMPARE(session1.videoFrameInput(), &input);
+ QCOMPARE(input.captureSession(), &session1);
+}
void tst_QMediaCaptureSession::can_add_and_remove_Camera()
{
@@ -411,17 +617,18 @@ void tst_QMediaCaptureSession::can_add_and_remove_Camera()
session.setRecorder(&recorder);
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
session.setCamera(&camera);
camera.setActive(true);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
+ QTRY_COMPARE(camera.isActive(), true);
session.setCamera(nullptr);
- QTRY_COMPARE(cameraChanged.count(), 2);
+ QTRY_COMPARE(cameraChanged.size(), 2);
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 3);
+ QTRY_COMPARE(cameraChanged.size(), 3);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
@@ -431,31 +638,31 @@ void tst_QMediaCaptureSession::can_move_Camera_between_sessions()
{
QMediaCaptureSession session0;
QMediaCaptureSession session1;
- QSignalSpy cameraChanged0(&session0, SIGNAL(cameraChanged()));
- QSignalSpy cameraChanged1(&session1, SIGNAL(cameraChanged()));
+ QSignalSpy cameraChanged0(&session0, &QMediaCaptureSession::cameraChanged);
+ QSignalSpy cameraChanged1(&session1, &QMediaCaptureSession::cameraChanged);
{
QCamera camera;
{
QMediaCaptureSession session2;
- QSignalSpy cameraChanged2(&session2, SIGNAL(cameraChanged()));
+ QSignalSpy cameraChanged2(&session2, &QMediaCaptureSession::cameraChanged);
session2.setCamera(&camera);
- QTRY_COMPARE(cameraChanged2.count(), 1);
+ QTRY_COMPARE(cameraChanged2.size(), 1);
}
QVERIFY(camera.captureSession() == nullptr);
session0.setCamera(&camera);
- QTRY_COMPARE(cameraChanged0.count(), 1);
+ QTRY_COMPARE(cameraChanged0.size(), 1);
QVERIFY(session0.camera() == &camera);
QVERIFY(camera.captureSession() == &session0);
session1.setCamera(&camera);
- QTRY_COMPARE(cameraChanged0.count(), 2);
+ QTRY_COMPARE(cameraChanged0.size(), 2);
QVERIFY(session0.camera() == nullptr);
- QTRY_COMPARE(cameraChanged1.count(), 1);
+ QTRY_COMPARE(cameraChanged1.size(), 1);
QVERIFY(session1.camera() == &camera);
QVERIFY(camera.captureSession() == &session1);
}
- QTRY_COMPARE(cameraChanged1.count(), 2);
+ QTRY_COMPARE(cameraChanged1.size(), 2);
QVERIFY(session1.camera() == nullptr);
}
@@ -471,21 +678,22 @@ void tst_QMediaCaptureSession::can_disconnect_Camera_when_recording()
session.setRecorder(&recorder);
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
camera.setActive(true);
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
+ QTRY_COMPARE(camera.isActive(), true);
durationChanged.clear();
recorder.record();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::RecordingState);
- QTRY_VERIFY(durationChanged.count() > 0);
+ QTRY_VERIFY(durationChanged.size() > 0);
session.setCamera(nullptr);
- QTRY_COMPARE(cameraChanged.count(), 2);
+ QTRY_COMPARE(cameraChanged.size(), 2);
recorder.stop();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::StoppedState);
@@ -512,18 +720,20 @@ void tst_QMediaCaptureSession::can_add_and_remove_different_Cameras()
session.setRecorder(&recorder);
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
camera.setActive(true);
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
+ QTRY_COMPARE(camera.isActive(), true);
session.setCamera(nullptr);
- QTRY_COMPARE(cameraChanged.count(), 2);
+ QTRY_COMPARE(cameraChanged.size(), 2);
session.setCamera(&camera2);
camera2.setActive(true);
- QTRY_COMPARE(cameraChanged.count(), 3);
+ QTRY_COMPARE(cameraChanged.size(), 3);
+ QTRY_COMPARE(camera2.isActive(), true);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
@@ -543,22 +753,25 @@ void tst_QMediaCaptureSession::can_change_CameraDevice_on_attached_Camera()
session.setRecorder(&recorder);
- QSignalSpy cameraDeviceChanged(&camera, SIGNAL(cameraDeviceChanged()));
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
+ QSignalSpy cameraDeviceChanged(&camera, &QCamera::cameraDeviceChanged);
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
recordFail(session);
QVERIFY(!QTest::currentTestFailed());
camera.setActive(true);
+ QTRY_COMPARE(camera.isActive(), true);
+
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
camera.setCameraDevice(cameraDevices[1]);
camera.setActive(true);
- QTRY_COMPARE(cameraDeviceChanged.count(), 1);
+ QTRY_COMPARE(cameraDeviceChanged.size(), 1);
+ QTRY_COMPARE(camera.isActive(), true);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
@@ -577,26 +790,26 @@ void tst_QMediaCaptureSession::can_change_VideoOutput_with_and_without_camera()
QMediaCaptureSession session;
- QSignalSpy videoOutputChanged(&session, SIGNAL(videoOutputChanged()));
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
+ QSignalSpy videoOutputChanged(&session, &QMediaCaptureSession::videoOutputChanged);
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
session.setVideoOutput(&videoOutput);
- QTRY_COMPARE(videoOutputChanged.count(), 1);
+ QTRY_COMPARE(videoOutputChanged.size(), 1);
session.setVideoOutput(nullptr);
- QTRY_COMPARE(videoOutputChanged.count(), 2);
+ QTRY_COMPARE(videoOutputChanged.size(), 2);
session.setVideoOutput(&videoOutput2);
- QTRY_COMPARE(videoOutputChanged.count(), 3);
+ QTRY_COMPARE(videoOutputChanged.size(), 3);
session.setCamera(nullptr);
- QTRY_COMPARE(cameraChanged.count(), 2);
+ QTRY_COMPARE(cameraChanged.size(), 2);
session.setVideoOutput(nullptr);
- QTRY_COMPARE(videoOutputChanged.count(), 4);
+ QTRY_COMPARE(videoOutputChanged.size(), 4);
}
void tst_QMediaCaptureSession::can_change_VideoOutput_when_recording()
@@ -613,27 +826,28 @@ void tst_QMediaCaptureSession::can_change_VideoOutput_when_recording()
session.setRecorder(&recorder);
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
- QSignalSpy videoOutputChanged(&session, SIGNAL(videoOutputChanged()));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
+ QSignalSpy videoOutputChanged(&session, &QMediaCaptureSession::videoOutputChanged);
camera.setActive(true);
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
+ QTRY_COMPARE(camera.isActive(), true);
recorder.record();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::RecordingState);
QVERIFY(durationChanged.wait(2000));
session.setVideoOutput(&videoOutput);
- QTRY_COMPARE(videoOutputChanged.count(), 1);
+ QTRY_COMPARE(videoOutputChanged.size(), 1);
session.setVideoOutput(nullptr);
- QTRY_COMPARE(videoOutputChanged.count(), 2);
+ QTRY_COMPARE(videoOutputChanged.size(), 2);
session.setVideoOutput(&videoOutput);
- QTRY_COMPARE(videoOutputChanged.count(), 3);
+ QTRY_COMPARE(videoOutputChanged.size(), 3);
recorder.stop();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::StoppedState);
@@ -655,20 +869,20 @@ void tst_QMediaCaptureSession::can_add_and_remove_recorders()
QMediaRecorder recorder2;
QMediaCaptureSession session;
- QSignalSpy audioInputChanged(&session, SIGNAL(audioInputChanged()));
- QSignalSpy recorderChanged(&session, SIGNAL(recorderChanged()));
+ QSignalSpy audioInputChanged(&session, &QMediaCaptureSession::audioInputChanged);
+ QSignalSpy recorderChanged(&session, &QMediaCaptureSession::recorderChanged);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 1);
+ QTRY_COMPARE(audioInputChanged.size(), 1);
session.setRecorder(&recorder);
- QTRY_COMPARE(recorderChanged.count(), 1);
+ QTRY_COMPARE(recorderChanged.size(), 1);
session.setRecorder(&recorder2);
- QTRY_COMPARE(recorderChanged.count(), 2);
+ QTRY_COMPARE(recorderChanged.size(), 2);
session.setRecorder(&recorder);
- QTRY_COMPARE(recorderChanged.count(), 3);
+ QTRY_COMPARE(recorderChanged.size(), 3);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
@@ -678,31 +892,31 @@ void tst_QMediaCaptureSession::can_move_Recorder_between_sessions()
{
QMediaCaptureSession session0;
QMediaCaptureSession session1;
- QSignalSpy recorderChanged0(&session0, SIGNAL(recorderChanged()));
- QSignalSpy recorderChanged1(&session1, SIGNAL(recorderChanged()));
+ QSignalSpy recorderChanged0(&session0, &QMediaCaptureSession::recorderChanged);
+ QSignalSpy recorderChanged1(&session1, &QMediaCaptureSession::recorderChanged);
{
QMediaRecorder recorder;
{
QMediaCaptureSession session2;
- QSignalSpy recorderChanged2(&session2, SIGNAL(recorderChanged()));
+ QSignalSpy recorderChanged2(&session2, &QMediaCaptureSession::recorderChanged);
session2.setRecorder(&recorder);
- QTRY_COMPARE(recorderChanged2.count(), 1);
+ QTRY_COMPARE(recorderChanged2.size(), 1);
}
QVERIFY(recorder.captureSession() == nullptr);
session0.setRecorder(&recorder);
- QTRY_COMPARE(recorderChanged0.count(), 1);
+ QTRY_COMPARE(recorderChanged0.size(), 1);
QVERIFY(session0.recorder() == &recorder);
QVERIFY(recorder.captureSession() == &session0);
session1.setRecorder(&recorder);
- QTRY_COMPARE(recorderChanged0.count(), 2);
+ QTRY_COMPARE(recorderChanged0.size(), 2);
QVERIFY(session0.recorder() == nullptr);
- QTRY_COMPARE(recorderChanged1.count(), 1);
+ QTRY_COMPARE(recorderChanged1.size(), 1);
QVERIFY(session1.recorder() == &recorder);
QVERIFY(recorder.captureSession() == &session1);
}
- QTRY_COMPARE(recorderChanged1.count(), 2);
+ QTRY_COMPARE(recorderChanged1.size(), 2);
QVERIFY(session1.recorder() == nullptr);
}
@@ -721,10 +935,10 @@ void tst_QMediaCaptureSession::can_record_AudioInput_with_null_AudioDevice()
QAudioInput input(nullDevice);
QMediaCaptureSession session;
- QSignalSpy audioInputChanged(&session, SIGNAL(audioInputChanged()));
+ QSignalSpy audioInputChanged(&session, &QMediaCaptureSession::audioInputChanged);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 1);
+ QTRY_COMPARE(audioInputChanged.size(), 1);
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
@@ -739,12 +953,14 @@ void tst_QMediaCaptureSession::can_record_Camera_with_null_CameraDevice()
QCamera camera(nullDevice);
QMediaCaptureSession session;
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
camera.setActive(true);
+ QTRY_COMPARE(camera.isActive(), true);
+
recordOk(session);
QVERIFY(!QTest::currentTestFailed());
}
@@ -758,23 +974,23 @@ void tst_QMediaCaptureSession::recording_stops_when_recorder_removed()
QMediaRecorder recorder;
QMediaCaptureSession session;
- QSignalSpy audioInputChanged(&session, SIGNAL(audioInputChanged()));
- QSignalSpy recorderChanged(&session, SIGNAL(recorderChanged()));
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy audioInputChanged(&session, &QMediaCaptureSession::audioInputChanged);
+ QSignalSpy recorderChanged(&session, &QMediaCaptureSession::recorderChanged);
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
session.setAudioInput(&input);
- QTRY_COMPARE(audioInputChanged.count(), 1);
+ QTRY_COMPARE(audioInputChanged.size(), 1);
session.setRecorder(&recorder);
- QTRY_COMPARE(recorderChanged.count(), 1);
+ QTRY_COMPARE(recorderChanged.size(), 1);
recorder.record();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::RecordingState);
QVERIFY(durationChanged.wait(2000));
session.setRecorder(nullptr);
- QTRY_COMPARE(recorderChanged.count(), 2);
+ QTRY_COMPARE(recorderChanged.size(), 2);
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::StoppedState);
QVERIFY(recorderErrorSignal.isEmpty());
@@ -795,75 +1011,78 @@ void tst_QMediaCaptureSession::can_add_and_remove_ImageCapture()
QImageCapture capture;
QMediaCaptureSession session;
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
- QSignalSpy imageCaptureChanged(&session, SIGNAL(imageCaptureChanged()));
- QSignalSpy readyForCaptureChanged(&capture, SIGNAL(readyForCaptureChanged(bool)));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
+ QSignalSpy imageCaptureChanged(&session, &QMediaCaptureSession::imageCaptureChanged);
+ QSignalSpy readyForCaptureChanged(&capture, &QImageCapture::readyForCaptureChanged);
QVERIFY(!capture.isAvailable());
QVERIFY(!capture.isReadyForCapture());
session.setImageCapture(&capture);
- QTRY_COMPARE(imageCaptureChanged.count(), 1);
+ QTRY_COMPARE(imageCaptureChanged.size(), 1);
QVERIFY(!capture.isAvailable());
QVERIFY(!capture.isReadyForCapture());
session.setCamera(&camera);
- QTRY_COMPARE(cameraChanged.count(), 1);
+ QTRY_COMPARE(cameraChanged.size(), 1);
QVERIFY(capture.isAvailable());
QVERIFY(!capture.isReadyForCapture());
camera.setActive(true);
- QTRY_COMPARE(readyForCaptureChanged.count(), 1);
+ QTRY_COMPARE(camera.isActive(), true);
+
+ QTRY_COMPARE(readyForCaptureChanged.size(), 1);
QVERIFY(capture.isReadyForCapture());
session.setImageCapture(nullptr);
- QTRY_COMPARE(imageCaptureChanged.count(), 2);
- QTRY_COMPARE(readyForCaptureChanged.count(), 2);
+ QTRY_COMPARE(imageCaptureChanged.size(), 2);
+ QTRY_COMPARE(readyForCaptureChanged.size(), 2);
QVERIFY(!capture.isAvailable());
QVERIFY(!capture.isReadyForCapture());
session.setImageCapture(&capture);
- QTRY_COMPARE(imageCaptureChanged.count(), 3);
- QTRY_COMPARE(readyForCaptureChanged.count(), 3);
+ QTRY_COMPARE(imageCaptureChanged.size(), 3);
+ QTRY_COMPARE(readyForCaptureChanged.size(), 3);
QVERIFY(capture.isAvailable());
QVERIFY(capture.isReadyForCapture());
}
void tst_QMediaCaptureSession::can_move_ImageCapture_between_sessions()
{
+ QSKIP_GSTREAMER("QTBUG-124005: Spurious failure on CI");
+
QMediaCaptureSession session0;
QMediaCaptureSession session1;
- QSignalSpy imageCaptureChanged0(&session0, SIGNAL(imageCaptureChanged()));
- QSignalSpy imageCaptureChanged1(&session1, SIGNAL(imageCaptureChanged()));
+ QSignalSpy imageCaptureChanged0(&session0, &QMediaCaptureSession::imageCaptureChanged);
+ QSignalSpy imageCaptureChanged1(&session1, &QMediaCaptureSession::imageCaptureChanged);
{
QImageCapture imageCapture;
{
QMediaCaptureSession session2;
- QSignalSpy imageCaptureChanged2(&session2, SIGNAL(imageCaptureChanged()));
+ QSignalSpy imageCaptureChanged2(&session2, &QMediaCaptureSession::imageCaptureChanged);
session2.setImageCapture(&imageCapture);
- QTRY_COMPARE(imageCaptureChanged2.count(), 1);
+ QTRY_COMPARE(imageCaptureChanged2.size(), 1);
}
QVERIFY(imageCapture.captureSession() == nullptr);
session0.setImageCapture(&imageCapture);
- QTRY_COMPARE(imageCaptureChanged0.count(), 1);
+ QTRY_COMPARE(imageCaptureChanged0.size(), 1);
QVERIFY(session0.imageCapture() == &imageCapture);
QVERIFY(imageCapture.captureSession() == &session0);
session1.setImageCapture(&imageCapture);
- QTRY_COMPARE(imageCaptureChanged0.count(), 2);
+ QTRY_COMPARE(imageCaptureChanged0.size(), 2);
QVERIFY(session0.imageCapture() == nullptr);
- QTRY_COMPARE(imageCaptureChanged1.count(), 1);
+ QTRY_COMPARE(imageCaptureChanged1.size(), 1);
QVERIFY(session1.imageCapture() == &imageCapture);
QVERIFY(imageCapture.captureSession() == &session1);
}
- QTRY_COMPARE(imageCaptureChanged1.count(), 2);
+ QTRY_COMPARE(imageCaptureChanged1.size(), 2);
QVERIFY(session1.imageCapture() == nullptr);
}
-
void tst_QMediaCaptureSession::capture_is_not_available_when_Camera_is_null()
{
QCamera camera;
@@ -874,26 +1093,27 @@ void tst_QMediaCaptureSession::capture_is_not_available_when_Camera_is_null()
QImageCapture capture;
QMediaCaptureSession session;
- QSignalSpy cameraChanged(&session, SIGNAL(cameraChanged()));
- QSignalSpy capturedSignal(&capture, SIGNAL(imageCaptured(int,QImage)));
- QSignalSpy readyForCaptureChanged(&capture, SIGNAL(readyForCaptureChanged(bool)));
+ QSignalSpy cameraChanged(&session, &QMediaCaptureSession::cameraChanged);
+ QSignalSpy capturedSignal(&capture, &QImageCapture::imageCaptured);
+ QSignalSpy readyForCaptureChanged(&capture, &QImageCapture::readyForCaptureChanged);
session.setImageCapture(&capture);
session.setCamera(&camera);
camera.setActive(true);
+ QTRY_COMPARE(camera.isActive(), true);
- QTRY_COMPARE(readyForCaptureChanged.count(), 1);
+ QTRY_COMPARE(readyForCaptureChanged.size(), 1);
QVERIFY(capture.isReadyForCapture());
QVERIFY(capture.capture() >= 0);
- QTRY_COMPARE(capturedSignal.count(), 1);
+ QTRY_COMPARE(capturedSignal.size(), 1);
QVERIFY(capture.isReadyForCapture());
- int readyCount = readyForCaptureChanged.count();
+ int readyCount = readyForCaptureChanged.size();
session.setCamera(nullptr);
- QTRY_COMPARE(readyForCaptureChanged.count(), readyCount + 1);
+ QTRY_COMPARE(readyForCaptureChanged.size(), readyCount + 1);
QVERIFY(!capture.isReadyForCapture());
QVERIFY(!capture.isAvailable());
QVERIFY(capture.capture() < 0);
@@ -910,33 +1130,34 @@ void tst_QMediaCaptureSession::can_add_ImageCapture_and_capture_during_recording
QMediaCaptureSession session;
QMediaRecorder recorder;
- QSignalSpy recorderChanged(&session, SIGNAL(recorderChanged()));
- QSignalSpy recorderErrorSignal(&recorder, SIGNAL(errorOccurred(Error, const QString &)));
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
- QSignalSpy imageCaptureChanged(&session, SIGNAL(imageCaptureChanged()));
- QSignalSpy readyForCaptureChanged(&capture, SIGNAL(readyForCaptureChanged(bool)));
- QSignalSpy capturedSignal(&capture, SIGNAL(imageCaptured(int,QImage)));
+ QSignalSpy recorderChanged(&session, &QMediaCaptureSession::recorderChanged);
+ QSignalSpy recorderErrorSignal(&recorder, &QMediaRecorder::errorOccurred);
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
+ QSignalSpy imageCaptureChanged(&session, &QMediaCaptureSession::imageCaptureChanged);
+ QSignalSpy readyForCaptureChanged(&capture, &QImageCapture::readyForCaptureChanged);
+ QSignalSpy capturedSignal(&capture, &QImageCapture::imageCaptured);
session.setCamera(&camera);
camera.setActive(true);
+ QTRY_COMPARE(camera.isActive(), true);
session.setRecorder(&recorder);
- QTRY_COMPARE(recorderChanged.count(), 1);
+ QTRY_COMPARE(recorderChanged.size(), 1);
recorder.record();
QTRY_VERIFY(recorder.recorderState() == QMediaRecorder::RecordingState);
QVERIFY(durationChanged.wait(2000));
session.setImageCapture(&capture);
- QTRY_COMPARE(imageCaptureChanged.count(), 1);
- QTRY_COMPARE(readyForCaptureChanged.count(), 1);
+ QTRY_COMPARE(imageCaptureChanged.size(), 1);
+ QTRY_COMPARE(readyForCaptureChanged.size(), 1);
QVERIFY(capture.isReadyForCapture());
QVERIFY(capture.capture() >= 0);
- QTRY_COMPARE(capturedSignal.count(), 1);
+ QTRY_COMPARE(capturedSignal.size(), 1);
session.setImageCapture(nullptr);
- QVERIFY(readyForCaptureChanged.count() >= 2);
+ QVERIFY(readyForCaptureChanged.size() >= 2);
QVERIFY(!capture.isReadyForCapture());
recorder.stop();
@@ -966,28 +1187,26 @@ void tst_QMediaCaptureSession::testAudioMute()
recorder.setOutputLocation(QStringLiteral("test"));
QSignalSpy spy(&audioInput, &QAudioInput::mutedChanged);
- QSignalSpy durationChanged(&recorder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy durationChanged(&recorder, &QMediaRecorder::durationChanged);
QMediaFormat format;
- format.setAudioCodec(QMediaFormat::AudioCodec::MP3);
+ format.setAudioCodec(QMediaFormat::AudioCodec::Wave);
recorder.setMediaFormat(format);
- recorder.record();
audioInput.setMuted(true);
- QCOMPARE(spy.count(), 1);
+ recorder.record();
+
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.last()[0], true);
QTRY_VERIFY_WITH_TIMEOUT(recorder.recorderState() == QMediaRecorder::RecordingState, 2000);
QVERIFY(durationChanged.wait(2000));
- audioInput.setMuted(false);
-
- QCOMPARE(spy.count(), 2);
- QCOMPARE(spy.last()[0], false);
-
recorder.stop();
+ QTRY_COMPARE(recorder.recorderState(), QMediaRecorder::StoppedState);
+
QString actualLocation = recorder.actualLocation().toLocalFile();
QVERIFY2(!actualLocation.isEmpty(), "Recorder did not save a file");
@@ -1016,6 +1235,33 @@ void tst_QMediaCaptureSession::testAudioMute()
decoder.stop();
QFile(actualLocation).remove();
+
+ audioInput.setMuted(false);
+
+ QCOMPARE(spy.size(), 2);
+ QCOMPARE(spy.last()[0], false);
+}
+
+void tst_QMediaCaptureSession::can_reset_audio_input_output()
+{
+ QAudioInput in1;
+ QMediaCaptureSession session;
+ session.setAudioInput(&in1);
+ QVERIFY(session.audioInput() != nullptr);
+ QAudioInput in2;
+ QSignalSpy changeSpy1(&session, &QMediaCaptureSession::audioInputChanged);
+ session.setAudioInput(&in2);
+ QVERIFY(session.audioInput() != nullptr);
+ QCOMPARE(changeSpy1.count(), 1);
+
+ QAudioOutput out1;
+ session.setAudioOutput(&out1);
+ QVERIFY(session.audioOutput() != nullptr);
+ QSignalSpy changeSpy2(&session, &QMediaCaptureSession::audioOutputChanged);
+ QAudioOutput out2;
+ session.setAudioOutput(&out2);
+ QVERIFY(session.audioOutput() != nullptr);
+ QCOMPARE(changeSpy2.count(), 1);
}
QTEST_MAIN(tst_QMediaCaptureSession)
diff --git a/tests/auto/integration/qmediaframeinputsbackend/CMakeLists.txt b/tests/auto/integration/qmediaframeinputsbackend/CMakeLists.txt
new file mode 100644
index 000000000..8d35b1de0
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmediaframeinputsbackend Test:
+#####################################################################
+
+qt_internal_add_test(tst_qmediaframeinputsbackend
+ SOURCES
+ tst_qmediaframeinputsbackend.cpp tst_qmediaframeinputsbackend.h
+ capturesessionfixture.cpp capturesessionfixture.h
+ mediainfo.h
+ framegenerator.cpp framegenerator.h
+ ../shared/testvideosink.h
+ LIBRARIES
+ Qt::Multimedia
+ Qt::MultimediaPrivate
+ Qt::Gui
+ Qt::Widgets
+)
+
+
diff --git a/tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.cpp b/tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.cpp
new file mode 100644
index 000000000..aae03df60
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.cpp
@@ -0,0 +1,88 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "capturesessionfixture.h"
+#include <QtTest/qtest.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace std::chrono;
+
+CaptureSessionFixture::CaptureSessionFixture(StreamType streamType, AutoStop autoStop)
+ : m_streamType{ streamType }
+{
+ m_recorder.setQuality(QMediaRecorder::VeryHighQuality);
+ m_session.setRecorder(&m_recorder);
+
+ if (hasVideo()) {
+ m_session.setVideoFrameInput(&m_videoInput);
+
+ QObject::connect(&m_videoGenerator, &VideoGenerator::frameCreated, //
+ &m_videoInput, &QVideoFrameInput::sendVideoFrame);
+
+ if (autoStop == AutoStop::EmitEmpty) {
+ m_recorder.setAutoStop(true);
+ m_videoGenerator.emitEmptyFrameOnStop();
+ }
+ }
+
+ if (hasAudio()) {
+ m_session.setAudioBufferInput(&m_audioInput);
+
+ QObject::connect(&m_audioGenerator, &AudioGenerator::audioBufferCreated, //
+ &m_audioInput, &QAudioBufferInput::sendAudioBuffer);
+
+ if (autoStop == AutoStop::EmitEmpty) {
+ m_recorder.setAutoStop(true);
+ m_audioGenerator.emitEmptyBufferOnStop();
+ }
+ }
+
+ m_tempFile.open();
+ m_recorder.setOutputLocation(m_tempFile.fileName());
+}
+
+CaptureSessionFixture::~CaptureSessionFixture()
+{
+ QFile::remove(m_recorder.actualLocation().toLocalFile());
+}
+
+void CaptureSessionFixture::connectPullMode()
+{
+ if (hasVideo())
+ QObject::connect(&m_videoInput, &QVideoFrameInput::readyToSendVideoFrame, //
+ &m_videoGenerator, &VideoGenerator::nextFrame);
+
+ if (hasAudio())
+ QObject::connect(&m_audioInput, &QAudioBufferInput::readyToSendAudioBuffer, //
+ &m_audioGenerator, &AudioGenerator::nextBuffer);
+}
+
+bool CaptureSessionFixture::waitForRecorderStopped(milliseconds duration)
+{
+ // StoppedState is emitted when media is finalized.
+ const bool stopped = QTest::qWaitFor(
+ [&] { //
+ return recorderStateChanged.contains(
+ QList<QVariant>{ QMediaRecorder::RecorderState::StoppedState });
+ },
+ duration);
+
+ if (!stopped)
+ return false;
+
+ return m_recorder.recorderState() == QMediaRecorder::StoppedState
+ && m_recorder.error() == QMediaRecorder::NoError;
+}
+
+bool CaptureSessionFixture::hasAudio() const
+{
+ return m_streamType == StreamType::Audio || m_streamType == StreamType::AudioAndVideo;
+}
+
+bool CaptureSessionFixture::hasVideo() const
+{
+ return m_streamType == StreamType::Video || m_streamType == StreamType::AudioAndVideo;
+}
+
+QT_END_NAMESPACE
diff --git a/tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.h b/tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.h
new file mode 100644
index 000000000..f7aa27a65
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/capturesessionfixture.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CAPTURESESSIONFIXTURE_H
+#define CAPTURESESSIONFIXTURE_H
+
+#include "framegenerator.h"
+#include <QtMultimedia/qvideoframeinput.h>
+#include <QtMultimedia/qaudioinput.h>
+#include <QtMultimedia/qmediacapturesession.h>
+#include <QtMultimedia/qmediarecorder.h>
+#include <QtMultimedia/qaudiobufferinput.h>
+#include <QtCore/qtemporaryfile.h>
+
+#include <../shared/testvideosink.h>
+#include <QtTest/qsignalspy.h>
+
+QT_BEGIN_NAMESPACE
+
+enum class StreamType { Audio, Video, AudioAndVideo };
+enum class AutoStop { EmitEmpty, No };
+
+struct CaptureSessionFixture
+{
+ explicit CaptureSessionFixture(StreamType streamType, AutoStop autoStop);
+ ~CaptureSessionFixture();
+
+ void connectPullMode();
+ bool waitForRecorderStopped(milliseconds duration);
+ bool hasAudio() const;
+ bool hasVideo() const;
+
+ VideoGenerator m_videoGenerator;
+ AudioGenerator m_audioGenerator;
+ QVideoFrameInput m_videoInput;
+ QAudioBufferInput m_audioInput;
+ QMediaCaptureSession m_session;
+ QMediaRecorder m_recorder;
+ QTemporaryFile m_tempFile;
+ StreamType m_streamType = StreamType::Video;
+
+ QSignalSpy readyToSendVideoFrame{ &m_videoInput, &QVideoFrameInput::readyToSendVideoFrame };
+ QSignalSpy readyToSendAudioBuffer{ &m_audioInput, &QAudioBufferInput::readyToSendAudioBuffer };
+ QSignalSpy recorderStateChanged{ &m_recorder, &QMediaRecorder::recorderStateChanged };
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tests/auto/integration/qmediaframeinputsbackend/framegenerator.cpp b/tests/auto/integration/qmediaframeinputsbackend/framegenerator.cpp
new file mode 100644
index 000000000..5d844a716
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/framegenerator.cpp
@@ -0,0 +1,148 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "framegenerator.h"
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+void VideoGenerator::setPattern(ImagePattern pattern)
+{
+ m_pattern = pattern;
+}
+
+void VideoGenerator::setFrameCount(int count)
+{
+ m_maxFrameCount = count;
+}
+
+void VideoGenerator::setSize(QSize size)
+{
+ m_size = size;
+}
+
+void VideoGenerator::setFrameRate(double rate)
+{
+ m_frameRate = rate;
+}
+
+void VideoGenerator::setPeriod(milliseconds period)
+{
+ m_period = period;
+}
+
+void VideoGenerator::emitEmptyFrameOnStop()
+{
+ m_emitEmptyFrameOnStop = true;
+}
+
+static void fillColoredSquares(QImage& image)
+{
+ QList<QColor> colors = { Qt::red, Qt::green, Qt::blue, Qt::yellow };
+ const int width = image.width();
+ const int height = image.height();
+
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ const int colorX = i < width / 2 ? 0 : 1;
+ const int colorY = j < height / 2 ? 0 : 1;
+ const int colorIndex = colorX + 2 * colorY;
+ image.setPixel(i, j, colors[colorIndex].rgb());
+ }
+ }
+}
+
+QVideoFrame VideoGenerator::createFrame()
+{
+ QImage image(m_size, QImage::Format_ARGB32);
+ switch (m_pattern) {
+ case ImagePattern::SingleColor:
+ image.fill(colors[m_frameIndex % colors.size()]);
+ break;
+ case ImagePattern::ColoredSquares:
+ fillColoredSquares(image);
+ break;
+ }
+
+ QVideoFrame frame(image);
+
+ if (m_frameRate)
+ frame.setStreamFrameRate(*m_frameRate);
+
+ if (m_period) {
+ frame.setStartTime(duration_cast<microseconds>(*m_period).count() * m_frameIndex);
+ frame.setEndTime(duration_cast<microseconds>(*m_period).count() * (m_frameIndex + 1));
+ }
+
+ return frame;
+}
+
+void VideoGenerator::nextFrame()
+{
+ if (m_frameIndex == m_maxFrameCount) {
+ emit done();
+ if (m_emitEmptyFrameOnStop)
+ emit frameCreated({});
+ return;
+ }
+
+ const QVideoFrame frame = createFrame();
+ emit frameCreated(frame);
+ ++m_frameIndex;
+}
+
+AudioGenerator::AudioGenerator()
+{
+ m_format.setSampleFormat(QAudioFormat::UInt8);
+ m_format.setSampleRate(8000);
+ m_format.setChannelConfig(QAudioFormat::ChannelConfigMono);
+}
+
+void AudioGenerator::setFormat(const QAudioFormat &format)
+{
+ m_format = format;
+}
+
+void AudioGenerator::setBufferCount(int count)
+{
+ m_maxBufferCount = count;
+}
+
+void AudioGenerator::setDuration(microseconds duration)
+{
+ m_duration = duration;
+}
+
+void AudioGenerator::emitEmptyBufferOnStop()
+{
+ m_emitEmptyBufferOnStop = true;
+}
+
+QAudioBuffer AudioGenerator::createAudioBuffer()
+{
+ const microseconds bufferDuration = m_duration / m_maxBufferCount.value_or(1);
+ const qint32 byteCount = m_format.bytesForDuration(bufferDuration.count());
+ const QByteArray data(byteCount, '\0');
+
+ QAudioBuffer buffer(data, m_format);
+ return buffer;
+}
+
+void AudioGenerator::nextBuffer()
+{
+ if (m_bufferIndex == m_maxBufferCount) {
+ emit done();
+ if (m_emitEmptyBufferOnStop)
+ emit audioBufferCreated({});
+ return;
+ }
+
+ const QAudioBuffer buffer = createAudioBuffer();
+
+ emit audioBufferCreated(buffer);
+ ++m_bufferIndex;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_framegenerator.cpp"
diff --git a/tests/auto/integration/qmediaframeinputsbackend/framegenerator.h b/tests/auto/integration/qmediaframeinputsbackend/framegenerator.h
new file mode 100644
index 000000000..dafb00681
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/framegenerator.h
@@ -0,0 +1,82 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef FRAMEGENERATOR_H
+#define FRAMEGENERATOR_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qlist.h>
+#include <QtMultimedia/qvideoframe.h>
+#include <QtMultimedia/qaudiobuffer.h>
+#include <functional>
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+using namespace std::chrono;
+
+enum class ImagePattern
+{
+ SingleColor, // Image filled with a single color
+ ColoredSquares // Colored squares, [red, green; blue, yellow]
+};
+
+class VideoGenerator : public QObject
+{
+ Q_OBJECT
+public:
+ void setPattern(ImagePattern pattern);
+ void setFrameCount(int count);
+ void setSize(QSize size);
+ void setFrameRate(double rate);
+ void setPeriod(milliseconds period);
+ void emitEmptyFrameOnStop();
+ QVideoFrame createFrame();
+
+signals:
+ void done();
+ void frameCreated(const QVideoFrame &frame);
+
+public slots:
+ void nextFrame();
+
+private:
+ QList<QColor> colors = { Qt::red, Qt::green, Qt::blue, Qt::black, Qt::white };
+ ImagePattern m_pattern = ImagePattern::SingleColor;
+ QSize m_size{ 640, 480 };
+ std::optional<int> m_maxFrameCount;
+ int m_frameIndex = 0;
+ std::optional<double> m_frameRate;
+ std::optional<milliseconds> m_period;
+ bool m_emitEmptyFrameOnStop = false;
+};
+
+class AudioGenerator : public QObject
+{
+ Q_OBJECT
+public:
+ AudioGenerator();
+ void setFormat(const QAudioFormat &format);
+ void setBufferCount(int count);
+ void setDuration(microseconds duration);
+ void emitEmptyBufferOnStop();
+ QAudioBuffer createAudioBuffer();
+
+signals:
+ void done();
+ void audioBufferCreated(const QAudioBuffer &buffer);
+
+public slots:
+ void nextBuffer();
+
+private:
+ std::optional<int> m_maxBufferCount;
+ microseconds m_duration = 1s;
+ int m_bufferIndex = 0;
+ QAudioFormat m_format;
+ bool m_emitEmptyBufferOnStop = false;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tests/auto/integration/qmediaframeinputsbackend/mediainfo.h b/tests/auto/integration/qmediaframeinputsbackend/mediainfo.h
new file mode 100644
index 000000000..6c1141c67
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/mediainfo.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MEDIAINFO_H
+#define MEDIAINFO_H
+
+#include <QtTest/QTest>
+#include <QtMultimedia/qmediaplayer.h>
+#include <QtMultimedia/qmediametadata.h>
+#include <QtMultimedia/qaudiooutput.h>
+#include "../shared/testvideosink.h"
+#include <chrono>
+
+QT_USE_NAMESPACE
+
+using namespace std::chrono;
+
+// Extracts media metadata from a input media file
+struct MediaInfo
+{
+ static std::optional<MediaInfo> create(const QUrl &fileLocation)
+ {
+ QMediaPlayer player;
+ const QSignalSpy mediaStatusChanged{ &player, &QMediaPlayer::mediaStatusChanged };
+
+ QAudioOutput audioOutput;
+ player.setAudioOutput(&audioOutput);
+
+ TestVideoSink sink;
+ player.setVideoSink(&sink);
+
+ std::vector<std::array<QColor, 4>> colors;
+ QObject::connect(
+ &sink, &TestVideoSink::videoFrameChangedSync, &sink,
+ [&](const QVideoFrame &frame) { //
+ if (frame.isValid())
+ colors.push_back(sampleQuadrants(frame.toImage()));
+ });
+
+ player.setSource(fileLocation);
+
+ // Loop through all frames to be able to count them
+ player.setPlaybackRate(50); // let's speed it up
+ player.play();
+
+ const bool endReached = QTest::qWaitFor(
+ [&] {
+ return mediaStatusChanged.contains(QList<QVariant>{ QMediaPlayer::EndOfMedia })
+ || mediaStatusChanged.contains(
+ QList<QVariant>{ QMediaPlayer::InvalidMedia });
+ },
+ 10min);
+
+ if (!endReached)
+ return {};
+
+ MediaInfo info{};
+ info.m_frameRate = player.metaData().value(QMediaMetaData::VideoFrameRate).toReal();
+ info.m_size = player.metaData().value(QMediaMetaData::Resolution).toSize();
+
+ info.m_duration = milliseconds{ player.duration() };
+ info.m_frameCount = sink.m_totalFrames - 1;
+ info.m_frameTimes = sink.m_frameTimes;
+ info.m_hasVideo = player.hasVideo();
+ info.m_hasAudio = player.hasAudio();
+ info.m_colors = colors;
+ return info;
+ }
+
+
+
+ static std::array<QColor, 4> sampleQuadrants(const QImage &image)
+ {
+ const int width = image.width();
+ const int height = image.height();
+ return {
+ image.pixel(width / 4, height / 4),
+ image.pixel(3 * width / 4, height / 4),
+ image.pixel(width / 4, 3 * height / 4),
+ image.pixel(3 * width / 4, 3 * height / 4),
+ };
+
+ }
+
+ int m_frameCount = 0;
+ qreal m_frameRate = 0.0f;
+ QSize m_size;
+ milliseconds m_duration;
+ bool m_hasVideo = false;
+ bool m_hasAudio = false;
+ std::vector<std::array<QColor, 4>> m_colors; // Colors in upper left, upper right, bottom left, and bottom right
+
+ std::vector<TestVideoSink::TimePoint> m_frameTimes;
+};
+
+#endif
diff --git a/tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.cpp b/tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.cpp
new file mode 100644
index 000000000..54623c807
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.cpp
@@ -0,0 +1,411 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "capturesessionfixture.h"
+#include "tst_qmediaframeinputsbackend.h"
+
+#include "mediainfo.h"
+#include <QtTest/QtTest>
+#include <qvideoframeinput.h>
+#include <qaudiobufferinput.h>
+#include <qsignalspy.h>
+#include <qmediarecorder.h>
+#include <qmediaplayer.h>
+#include <../shared/testvideosink.h>
+#include <../shared/mediabackendutils.h>
+
+QT_BEGIN_NAMESPACE
+
+void tst_QMediaFrameInputsBackend::initTestCase()
+{
+ QSKIP_GSTREAMER("Not implemented in the gstreamer backend");
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesAudio_whenAudioFramesInputSends_data()
+{
+ QTest::addColumn<int>("bufferCount");
+ QTest::addColumn<QAudioFormat::SampleFormat>("sampleFormat");
+ QTest::addColumn<QAudioFormat::ChannelConfig>("channelConfig");
+ QTest::addColumn<int>("sampleRate");
+ QTest::addColumn<milliseconds>("duration");
+
+#ifndef Q_OS_WINDOWS // sample rate 8000 is not supported. TODO: investigate.
+ QTest::addRow("bufferCount: 20; sampleFormat: Int16; channelConfig: Mono; sampleRate: 8000; "
+ "duration: 1000")
+ << 20 << QAudioFormat::Int16 << QAudioFormat::ChannelConfigMono << 8000 << 1000ms;
+#endif
+ QTest::addRow("bufferCount: 30; sampleFormat: Int32; channelConfig: Stereo; sampleRate: "
+ "12000; duration: 2000")
+ << 30 << QAudioFormat::Int32 << QAudioFormat::ChannelConfigStereo << 12000 << 2000ms;
+
+ // TODO: investigate fails of channels configuration
+ // QTest::addRow("bufferCount: 10; sampleFormat: UInt8; channelConfig: 2Dot1; sampleRate:
+ // 40000; duration: 1500")
+ // << 10 << QAudioFormat::UInt8 << QAudioFormat::ChannelConfig2Dot1 << 40000 << 1500;
+ // QTest::addRow("bufferCount: 10; sampleFormat: Float; channelConfig: 3Dot0; sampleRate:
+ // 50000; duration: 2500")
+ // << 40 << QAudioFormat::Float << QAudioFormat::ChannelConfig3Dot0 << 50000 << 2500;
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesAudio_whenAudioFramesInputSends()
+{
+ QFETCH(const int, bufferCount);
+ QFETCH(const QAudioFormat::SampleFormat, sampleFormat);
+ QFETCH(const QAudioFormat::ChannelConfig, channelConfig);
+ QFETCH(const int, sampleRate);
+ QFETCH(const milliseconds, duration);
+
+ CaptureSessionFixture f{ StreamType::Audio, AutoStop::EmitEmpty };
+ f.connectPullMode();
+
+ QAudioFormat format;
+ format.setSampleFormat(sampleFormat);
+ format.setSampleRate(sampleRate);
+ format.setChannelConfig(channelConfig);
+
+ f.m_audioGenerator.setFormat(format);
+ f.m_audioGenerator.setBufferCount(bufferCount);
+ f.m_audioGenerator.setDuration(duration);
+
+ f.m_recorder.record();
+
+ QVERIFY(f.waitForRecorderStopped(60s));
+
+ auto info = MediaInfo::create(f.m_recorder.actualLocation());
+
+ QVERIFY(info->m_hasAudio);
+ QCOMPARE_GE(info->m_duration, duration - 50ms);
+ QCOMPARE_LE(info->m_duration, duration + 50ms);
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesVideo_whenVideoFramesInputSendsFrames_data()
+{
+ QTest::addColumn<int>("framesNumber");
+ QTest::addColumn<milliseconds>("frameDuration");
+ QTest::addColumn<QSize>("resolution");
+ QTest::addColumn<bool>("setTimeStamp");
+
+ QTest::addRow("framesNumber: 5; frameRate: 2; resolution: 50x80; with time stamps")
+ << 5 << 500ms << QSize(50, 80) << true;
+ QTest::addRow("framesNumber: 20; frameRate: 1; resolution: 200x100; with time stamps")
+ << 20 << 1000ms << QSize(200, 100) << true;
+
+ QTest::addRow("framesNumber: 20; frameRate: 30; resolution: 200x100; with frame rate")
+ << 20 << 250ms << QSize(200, 100) << false;
+ QTest::addRow("framesNumber: 60; frameRate: 4; resolution: 200x100; with frame rate")
+ << 60 << 24ms << QSize(200, 100) << false;
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesVideo_whenVideoFramesInputSendsFrames()
+{
+ QFETCH(const int, framesNumber);
+ QFETCH(const milliseconds, frameDuration);
+ QFETCH(const QSize, resolution);
+ QFETCH(const bool, setTimeStamp);
+
+ CaptureSessionFixture f{ StreamType::Video, AutoStop::EmitEmpty };
+ f.connectPullMode();
+ f.m_videoGenerator.setFrameCount(framesNumber);
+ f.m_videoGenerator.setSize(resolution);
+
+ const qreal frameRate = 1e6 / duration_cast<microseconds>(frameDuration).count();
+ if (setTimeStamp)
+ f.m_videoGenerator.setPeriod(frameDuration);
+ else
+ f.m_videoGenerator.setFrameRate(frameRate);
+
+ f.m_recorder.record();
+
+ QVERIFY(f.waitForRecorderStopped(60s));
+
+ auto info = MediaInfo::create(f.m_recorder.actualLocation());
+
+ QCOMPARE_LT(info->m_frameRate, frameRate * 1.001);
+ QCOMPARE_GT(info->m_frameRate, frameRate * 0.999);
+
+ QCOMPARE_LT(info->m_duration, frameDuration * framesNumber * 1.001);
+ QCOMPARE_GE(info->m_duration, frameDuration * framesNumber * 0.999);
+
+ QCOMPARE(info->m_size, resolution);
+ QCOMPARE_EQ(info->m_frameCount, framesNumber);
+}
+
+struct YUV
+{
+ double Y;
+ double U;
+ double V;
+};
+
+// Poor man's RGB to YUV conversion with BT.709 coefficients
+// from https://en.wikipedia.org/wiki/Y%E2%80%B2UV
+QVector3D RGBToYUV(const QColor &c)
+{
+ const float R = c.redF();
+ const float G = c.greenF();
+ const float B = c.blueF();
+ QVector3D yuv;
+ yuv[0] = 0.2126f * R + 0.7152f * G + 0.0722f * B;
+ yuv[1] = -0.09991f * R - 0.33609f * G + 0.436f * B;
+ yuv[2] = 0.615f * R - 0.55861f * G - 0.05639f * B;
+ return yuv;
+}
+
+// Considers two colors equal if their YUV components are
+// pointing in the same direction and have similar luma (Y)
+bool fuzzyCompare(const QColor &lhs, const QColor& rhs, float tol = 1e-2)
+{
+ const QVector3D lhsYuv = RGBToYUV(lhs);
+ const QVector3D rhsYuv = RGBToYUV(rhs);
+ const float relativeLumaDiff =
+ 0.5f * std::abs((lhsYuv[0] - rhsYuv[0]) / (lhsYuv[0] + rhsYuv[0]));
+ const float colorDiff = QVector3D::crossProduct(lhsYuv, rhsYuv).length();
+ return colorDiff < tol && relativeLumaDiff < tol;
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesVideo_withCorrectColors()
+{
+ CaptureSessionFixture f{ StreamType::Video, AutoStop::EmitEmpty };
+ f.connectPullMode();
+ f.m_videoGenerator.setPattern(ImagePattern::ColoredSquares);
+ f.m_videoGenerator.setFrameCount(3);
+ f.m_recorder.record();
+ QVERIFY(f.waitForRecorderStopped(60s));
+
+ const auto info = MediaInfo::create(f.m_recorder.actualLocation());
+ QCOMPARE_EQ(info->m_colors.size(), 3);
+
+ std::array<QColor, 4> colors = info->m_colors.front();
+ QVERIFY(fuzzyCompare(colors[0], Qt::red));
+ QVERIFY(fuzzyCompare(colors[1], Qt::green));
+ QVERIFY(fuzzyCompare(colors[2], Qt::blue));
+ QVERIFY(fuzzyCompare(colors[3], Qt::yellow));
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesVideo_whenInputFrameShrinksOverTime()
+{
+ CaptureSessionFixture f{ StreamType::Video, AutoStop::EmitEmpty };
+ f.m_recorder.record();
+ f.readyToSendVideoFrame.wait();
+
+ constexpr int startSize = 38;
+ int frameCount = 0;
+ for (int i = 0; i < startSize; i += 2) { // TODO crash in sws_scale if subsequent frames are odd-sized QTBUG-126259
+ ++frameCount;
+ const QSize size{ startSize - i, startSize - i };
+ f.m_videoGenerator.setSize(size);
+ f.m_videoInput.sendVideoFrame(f.m_videoGenerator.createFrame());
+ f.readyToSendVideoFrame.wait();
+ }
+
+ f.m_videoInput.sendVideoFrame({});
+
+ QVERIFY(f.waitForRecorderStopped(60s));
+ auto info = MediaInfo::create(f.m_recorder.actualLocation());
+
+ QCOMPARE_EQ(info->m_frameCount, frameCount);
+
+ // All frames should be resized to the size of the first frame
+ QCOMPARE_EQ(info->m_size, QSize(startSize, startSize));
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesVideo_whenInputFrameGrowsOverTime()
+{
+ CaptureSessionFixture f{ StreamType::Video, AutoStop::EmitEmpty };
+ f.m_recorder.record();
+ f.readyToSendVideoFrame.wait();
+
+ constexpr int startSize = 38;
+ constexpr int maxSize = 256;
+ int frameCount = 0;
+
+ for (int i = 0; i < maxSize - startSize; i += 2) { // TODO crash in sws_scale if subsequent frames are odd-sized QTBUG-126259
+ ++frameCount;
+ const QSize size{ startSize + i, startSize + i };
+ f.m_videoGenerator.setPattern(ImagePattern::ColoredSquares);
+ f.m_videoGenerator.setSize(size);
+ f.m_videoInput.sendVideoFrame(f.m_videoGenerator.createFrame());
+ f.readyToSendVideoFrame.wait();
+ }
+
+ f.m_videoInput.sendVideoFrame({});
+
+ QVERIFY(f.waitForRecorderStopped(60s));
+ auto info = MediaInfo::create(f.m_recorder.actualLocation());
+
+ QCOMPARE_EQ(info->m_frameCount, frameCount);
+
+ // All frames should be resized to the size of the first frame
+ QCOMPARE_EQ(info->m_size, QSize(startSize, startSize));
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderWritesVideo_withSingleFrame()
+{
+ CaptureSessionFixture f{ StreamType::Video, AutoStop::EmitEmpty };
+ f.connectPullMode();
+ f.m_videoGenerator.setFrameCount(1);
+ f.m_videoGenerator.setSize({ 640, 480 });
+ f.m_videoGenerator.setPeriod(1s);
+ f.m_recorder.record();
+ QVERIFY(f.waitForRecorderStopped(60s));
+ auto info = MediaInfo::create(f.m_recorder.actualLocation());
+
+ QCOMPARE_EQ(info->m_frameCount, 1);
+ QCOMPARE_EQ(info->m_duration, 1s);
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderStopsRecording_whenInputsReportedEndOfStream_data()
+{
+ QTest::addColumn<bool>("audioStopsFirst");
+
+ QTest::addRow("audio stops first") << true;
+ QTest::addRow("video stops first") << true;
+}
+
+void tst_QMediaFrameInputsBackend::mediaRecorderStopsRecording_whenInputsReportedEndOfStream()
+{
+ QFETCH(const bool, audioStopsFirst);
+
+ CaptureSessionFixture f{ StreamType::AudioAndVideo, AutoStop::No };
+ f.m_recorder.setAutoStop(true);
+ f.connectPullMode();
+
+ f.m_audioGenerator.setBufferCount(30);
+ f.m_videoGenerator.setFrameCount(30);
+
+ QSignalSpy audioDone{ &f.m_audioGenerator, &AudioGenerator::done };
+ QSignalSpy videoDone{ &f.m_videoGenerator, &VideoGenerator::done };
+
+ f.m_recorder.record();
+
+ audioDone.wait();
+ videoDone.wait();
+
+ if (audioStopsFirst) {
+ f.m_audioInput.sendAudioBuffer({});
+ QVERIFY(!f.waitForRecorderStopped(300ms)); // Should not stop until both streams stopped
+ f.m_videoInput.sendVideoFrame({});
+ } else {
+ f.m_videoInput.sendVideoFrame({});
+ QVERIFY(!f.waitForRecorderStopped(300ms)); // Should not stop until both streams stopped
+ f.m_audioInput.sendAudioBuffer({});
+ }
+
+ QVERIFY(f.waitForRecorderStopped(60s));
+
+ // check if the file has been written
+
+ const std::optional<MediaInfo> mediaInfo = MediaInfo::create(f.m_recorder.actualLocation());
+
+ QVERIFY(mediaInfo);
+ QVERIFY(mediaInfo->m_hasVideo);
+ QVERIFY(mediaInfo->m_hasAudio);
+}
+
+void tst_QMediaFrameInputsBackend::readyToSend_isEmitted_whenRecordingStarts_data()
+{
+ QTest::addColumn<StreamType>("streamType");
+ QTest::addRow("audio") << StreamType::Audio;
+ QTest::addRow("video") << StreamType::Video;
+ QTest::addRow("audioAndVideo") << StreamType::AudioAndVideo;
+}
+
+void tst_QMediaFrameInputsBackend::readyToSend_isEmitted_whenRecordingStarts()
+{
+ QFETCH(StreamType, streamType);
+
+ CaptureSessionFixture f{ streamType, AutoStop::No };
+
+ f.m_recorder.record();
+
+ if (f.hasAudio())
+ QTRY_COMPARE_EQ(f.readyToSendAudioBuffer.size(), 1);
+
+ if (f.hasVideo())
+ QTRY_COMPARE_EQ(f.readyToSendVideoFrame.size(), 1);
+}
+
+void tst_QMediaFrameInputsBackend::readyToSendVideoFrame_isEmitted_whenSendVideoFrameIsCalled()
+{
+ CaptureSessionFixture f{ StreamType::Video, AutoStop::No };
+
+ f.m_recorder.record();
+ QVERIFY(f.readyToSendVideoFrame.wait());
+
+ f.m_videoInput.sendVideoFrame(f.m_videoGenerator.createFrame());
+ QVERIFY(f.readyToSendVideoFrame.wait());
+
+ f.m_videoInput.sendVideoFrame(f.m_videoGenerator.createFrame());
+ QVERIFY(f.readyToSendVideoFrame.wait());
+}
+
+void tst_QMediaFrameInputsBackend::readyToSendAudioBuffer_isEmitted_whenSendAudioBufferIsCalled()
+{
+ CaptureSessionFixture f{ StreamType::Audio, AutoStop::No };
+
+ f.m_recorder.record();
+ QVERIFY(f.readyToSendAudioBuffer.wait());
+
+ f.m_audioInput.sendAudioBuffer(f.m_audioGenerator.createAudioBuffer());
+ QVERIFY(f.readyToSendAudioBuffer.wait());
+
+ f.m_audioInput.sendAudioBuffer(f.m_audioGenerator.createAudioBuffer());
+ QVERIFY(f.readyToSendAudioBuffer.wait());
+}
+
+void tst_QMediaFrameInputsBackend::readyToSendVideoFrame_isEmittedRepeatedly_whenPullModeIsEnabled()
+{
+ CaptureSessionFixture f{ StreamType::Video, AutoStop::EmitEmpty };
+ f.connectPullMode();
+
+ constexpr int expectedSignalCount = 4;
+ f.m_videoGenerator.setFrameCount(expectedSignalCount - 1);
+
+ f.m_recorder.record();
+
+ f.waitForRecorderStopped(60s);
+
+ QCOMPARE_EQ(f.readyToSendVideoFrame.size(), expectedSignalCount);
+}
+
+void tst_QMediaFrameInputsBackend::
+ readyToSendAudioBuffer_isEmittedRepeatedly_whenPullModeIsEnabled()
+{
+ CaptureSessionFixture f{ StreamType::Audio, AutoStop::EmitEmpty };
+ f.connectPullMode();
+
+ constexpr int expectedSignalCount = 4;
+ f.m_audioGenerator.setBufferCount(expectedSignalCount - 1);
+
+ f.m_recorder.record();
+
+ f.waitForRecorderStopped(60s);
+
+ QCOMPARE_EQ(f.readyToSendAudioBuffer.size(), expectedSignalCount);
+}
+
+void tst_QMediaFrameInputsBackend::
+ readyToSendAudioBufferAndVideoFrame_isEmittedRepeatedly_whenPullModeIsEnabled()
+{
+ CaptureSessionFixture f{ StreamType::AudioAndVideo, AutoStop::EmitEmpty };
+ f.connectPullMode();
+
+ constexpr int expectedSignalCount = 4;
+ f.m_audioGenerator.setBufferCount(expectedSignalCount - 1);
+ f.m_videoGenerator.setFrameCount(expectedSignalCount - 1);
+
+ f.m_recorder.record();
+
+ f.waitForRecorderStopped(60s);
+
+ QCOMPARE_EQ(f.readyToSendAudioBuffer.size(), expectedSignalCount);
+ QCOMPARE_EQ(f.readyToSendVideoFrame.size(), expectedSignalCount);
+}
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+QTEST_MAIN(tst_QMediaFrameInputsBackend)
+
+#include "moc_tst_qmediaframeinputsbackend.cpp"
diff --git a/tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.h b/tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.h
new file mode 100644
index 000000000..451e1aceb
--- /dev/null
+++ b/tests/auto/integration/qmediaframeinputsbackend/tst_qmediaframeinputsbackend.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TST_QMEDIAFRAMEINPUTSBACKEND_H
+#define TST_QMEDIAFRAMEINPUTSBACKEND_H
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class tst_QMediaFrameInputsBackend : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void mediaRecorderWritesAudio_whenAudioFramesInputSends_data();
+ void mediaRecorderWritesAudio_whenAudioFramesInputSends();
+
+ void mediaRecorderWritesVideo_whenVideoFramesInputSendsFrames_data();
+ void mediaRecorderWritesVideo_whenVideoFramesInputSendsFrames();
+
+ void mediaRecorderWritesVideo_whenInputFrameShrinksOverTime();
+ void mediaRecorderWritesVideo_whenInputFrameGrowsOverTime();
+
+ void mediaRecorderWritesVideo_withSingleFrame();
+
+ void mediaRecorderWritesVideo_withCorrectColors();
+
+ void mediaRecorderStopsRecording_whenInputsReportedEndOfStream_data();
+ void mediaRecorderStopsRecording_whenInputsReportedEndOfStream();
+
+ void readyToSend_isEmitted_whenRecordingStarts_data();
+ void readyToSend_isEmitted_whenRecordingStarts();
+
+ void readyToSendVideoFrame_isEmitted_whenSendVideoFrameIsCalled();
+ void readyToSendAudioBuffer_isEmitted_whenSendAudioBufferIsCalled();
+
+ void readyToSendVideoFrame_isEmittedRepeatedly_whenPullModeIsEnabled();
+ void readyToSendAudioBuffer_isEmittedRepeatedly_whenPullModeIsEnabled();
+ void readyToSendAudioBufferAndVideoFrame_isEmittedRepeatedly_whenPullModeIsEnabled();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tests/auto/integration/qmediaplayerbackend/BLACKLIST b/tests/auto/integration/qmediaplayerbackend/BLACKLIST
index e107df861..1f24e07a1 100644
--- a/tests/auto/integration/qmediaplayerbackend/BLACKLIST
+++ b/tests/auto/integration/qmediaplayerbackend/BLACKLIST
@@ -1,7 +1,6 @@
# Media player plugin not built at the moment on this platform
opensuse-13.1 64bit
-
[playlist]
redhatenterpriselinuxworkstation-6.6
diff --git a/tests/auto/integration/qmediaplayerbackend/CMakeLists.txt b/tests/auto/integration/qmediaplayerbackend/CMakeLists.txt
index 3848c6099..3a9d25926 100644
--- a/tests/auto/integration/qmediaplayerbackend/CMakeLists.txt
+++ b/tests/auto/integration/qmediaplayerbackend/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qmediaplayerbackend.pro.
#####################################################################
@@ -13,24 +16,24 @@ list(APPEND testdata_resource_files ${test_data_glob})
qt_internal_add_test(tst_qmediaplayerbackend
SOURCES
../shared/mediafileselector.h
+ ../shared/mediabackendutils.h
+ ../shared/testvideosink.h
+ mediaplayerstate.h
+ fake.h
+ fixture.h
+ server.h
tst_qmediaplayerbackend.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
- TESTDATA ${testdata_resource_files}
-)
-
-qt_internal_add_resource(tst_qmediaplayerbackend "testdata"
- PREFIX
- "/"
- FILES
+ Qt::MultimediaQuickPrivate
+ Qt::Qml
+ Qt::Quick
+ Qt::QuickPrivate
+ BUILTIN_TESTDATA
+ TESTDATA
${testdata_resource_files}
-)
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(tst_qmediaplayerbackend CONDITION boot2qt
- DEFINES
- SKIP_OGV_TEST
+ "LazyLoad.qml"
+ INCLUDE_DIRECTORIES
+ ../shared/
)
diff --git a/tests/auto/integration/qmediaplayerbackend/LazyLoad.qml b/tests/auto/integration/qmediaplayerbackend/LazyLoad.qml
new file mode 100644
index 000000000..04af13186
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/LazyLoad.qml
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtMultimedia
+
+Rectangle {
+ id: root
+ width: 600
+ height: 800
+ color: "black"
+
+ Component {
+ id: videoOutputComponent
+
+ Item {
+ objectName: "videoPlayer"
+ property alias mediaPlayer: mediaPlayer
+ property alias videoOutput: videoOutput
+ property alias videoSink: videoOutput.videoSink
+
+ property alias playbackState: mediaPlayer.playbackState
+ property alias error: mediaPlayer.error
+
+
+ MediaPlayer {
+ id: mediaPlayer
+ objectName: "mediaPlayer"
+ source: "qrc:/testdata/colors.mp4"
+ }
+ VideoOutput {
+ id: videoOutput
+ objectName: "videoOutput"
+ anchors.fill: parent
+ }
+ }
+ }
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ sourceComponent: videoOutputComponent
+ anchors.fill: parent
+ active: false
+ onActiveChanged: {
+ if (active) {
+ loader.item.mediaPlayer.videoOutput = loader.item.videoOutput
+ loader.item.mediaPlayer.play()
+ }
+ }
+ }
+}
diff --git a/tests/auto/integration/qmediaplayerbackend/fake.h b/tests/auto/integration/qmediaplayerbackend/fake.h
new file mode 100644
index 000000000..9a68741d0
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/fake.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef FAKE_H
+#define FAKE_H
+
+#include <testvideosink.h>
+
+QT_USE_NAMESPACE
+
+class TestVideoOutput : public QObject
+{
+ Q_OBJECT
+public:
+ TestVideoOutput() = default;
+
+ Q_INVOKABLE QVideoSink *videoSink() { return &m_sink; }
+
+ TestVideoSink m_sink;
+};
+
+inline void setVideoSinkAsyncFramesCounter(QVideoSink &sink, std::atomic_int &counter)
+{
+ QObject::connect(
+ &sink, &QVideoSink::videoFrameChanged, &sink, [&counter]() { ++counter; },
+ Qt::DirectConnection);
+}
+
+#endif // FAKE_H
diff --git a/tests/auto/integration/qmediaplayerbackend/fixture.h b/tests/auto/integration/qmediaplayerbackend/fixture.h
new file mode 100644
index 000000000..883330513
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/fixture.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef FIXTURE_H
+#define FIXTURE_H
+
+#include <qmediaplayer.h>
+#include <qaudiooutput.h>
+#include <qtest.h>
+#include <qsignalspy.h>
+
+#include "fake.h"
+#include "testvideosink.h"
+
+QT_USE_NAMESPACE
+
+struct Fixture : QObject
+{
+ Q_OBJECT
+public:
+ Fixture()
+ : playbackStateChanged(&player, &QMediaPlayer::playbackStateChanged),
+ errorOccurred(&player, &QMediaPlayer::errorOccurred),
+ sourceChanged(&player, &QMediaPlayer::sourceChanged),
+ mediaStatusChanged(&player, &QMediaPlayer::mediaStatusChanged),
+ positionChanged(&player, &QMediaPlayer::positionChanged),
+ durationChanged(&player, &QMediaPlayer::durationChanged),
+ playbackRateChanged(&player, &QMediaPlayer::playbackRateChanged),
+ metadataChanged(&player, &QMediaPlayer::metaDataChanged),
+ volumeChanged(&output, &QAudioOutput::volumeChanged),
+ mutedChanged(&output, &QAudioOutput::mutedChanged),
+ bufferProgressChanged(&player, &QMediaPlayer::bufferProgressChanged),
+ destroyed(&player, &QObject::destroyed)
+ {
+ setVideoSinkAsyncFramesCounter(surface, framesCount);
+
+ player.setAudioOutput(&output);
+ player.setVideoOutput(&surface);
+ }
+
+ void clearSpies()
+ {
+ playbackStateChanged.clear();
+ errorOccurred.clear();
+ sourceChanged.clear();
+ mediaStatusChanged.clear();
+ positionChanged.clear();
+ durationChanged.clear();
+ playbackRateChanged.clear();
+ metadataChanged.clear();
+ volumeChanged.clear();
+ mutedChanged.clear();
+ bufferProgressChanged.clear();
+ destroyed.clear();
+ }
+
+ QMediaPlayer player;
+ QAudioOutput output;
+ TestVideoSink surface;
+ std::atomic_int framesCount = 0;
+
+ QSignalSpy playbackStateChanged;
+ QSignalSpy errorOccurred;
+ QSignalSpy sourceChanged;
+ QSignalSpy mediaStatusChanged;
+ QSignalSpy positionChanged;
+ QSignalSpy durationChanged;
+ QSignalSpy playbackRateChanged;
+ QSignalSpy metadataChanged;
+ QSignalSpy volumeChanged;
+ QSignalSpy mutedChanged;
+ QSignalSpy bufferProgressChanged;
+ QSignalSpy destroyed;
+};
+
+// Helper to create an object that is comparable to a QSignalSpy
+using SignalList = QList<QList<QVariant>>;
+
+struct TestSubtitleSink : QObject
+{
+ Q_OBJECT
+
+public Q_SLOTS:
+ void addSubtitle(QString string)
+ {
+ QMetaObject::invokeMethod(this, [this, string = std::move(string)]() mutable {
+ subtitles.append(std::move(string));
+ });
+ }
+
+public:
+ QStringList subtitles;
+};
+
+#endif // FIXTURE_H
diff --git a/tests/auto/integration/qmediaplayerbackend/mediaplayerstate.h b/tests/auto/integration/qmediaplayerbackend/mediaplayerstate.h
new file mode 100644
index 000000000..d9f2cc875
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/mediaplayerstate.h
@@ -0,0 +1,167 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MEDIAPLAYERSTATE_H
+#define MEDIAPLAYERSTATE_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qurl.h>
+#include <QtMultimedia/qaudiooutput.h>
+#include <QtMultimedia/qmediametadata.h>
+#include <QtMultimedia/qmediaplayer.h>
+#include <QtMultimedia/qmediatimerange.h>
+#include <QtTest/qtestcase.h>
+
+#include <optional>
+
+QT_USE_NAMESPACE
+
+/*!
+ * Helper class that simplifies testing the state of
+ * a media player against an expected state.
+ *
+ * Use the COMPARE_MEDIA_PLAYER_STATE_EQ macro to compare
+ * the media player state against the expected state.
+ *
+ * Individual properties can be ignored by comparison by
+ * assigning the std::nullopt value to the property of the
+ * expected state.
+ */
+struct MediaPlayerState
+{
+ std::optional<QList<QMediaMetaData>> audioTracks;
+ std::optional<QList<QMediaMetaData>> videoTracks;
+ std::optional<QList<QMediaMetaData>> subtitleTracks;
+ std::optional<int> activeAudioTrack;
+ std::optional<int> activeVideoTrack;
+ std::optional<int> activeSubtitleTrack;
+ std::optional<QAudioOutput*> audioOutput;
+ std::optional<QObject*> videoOutput;
+ std::optional<QVideoSink*> videoSink;
+ std::optional<QUrl> source;
+ std::optional<QIODevice const*> sourceDevice;
+ std::optional<QMediaPlayer::PlaybackState> playbackState;
+ std::optional<QMediaPlayer::MediaStatus> mediaStatus;
+ std::optional<qint64> duration;
+ std::optional<qint64> position;
+ std::optional<bool> hasAudio;
+ std::optional<bool> hasVideo;
+ std::optional<float> bufferProgress;
+ std::optional<QMediaTimeRange> bufferedTimeRange;
+ std::optional<bool> isSeekable;
+ std::optional<qreal> playbackRate;
+ std::optional<bool> isPlaying;
+ std::optional<int> loops;
+ std::optional<QMediaPlayer::Error> error;
+ std::optional<bool> isAvailable;
+ std::optional<QMediaMetaData> metaData;
+
+ /*!
+ * Read the state from an existing media player
+ */
+ explicit MediaPlayerState(const QMediaPlayer &player)
+ : audioTracks{ player.audioTracks() },
+ videoTracks{ player.videoTracks() },
+ subtitleTracks{ player.subtitleTracks() },
+ activeAudioTrack{ player.activeAudioTrack() },
+ activeVideoTrack{ player.activeVideoTrack() },
+ activeSubtitleTrack{ player.activeSubtitleTrack() },
+ audioOutput{ player.audioOutput() },
+ videoOutput{ player.videoOutput() },
+ videoSink{ player.videoSink() },
+ source{ player.source() },
+ sourceDevice{ player.sourceDevice() },
+ playbackState{ player.playbackState() },
+ mediaStatus{ player.mediaStatus() },
+ duration{ player.duration() },
+ position{ player.position() },
+ hasAudio{ player.hasAudio() },
+ hasVideo{ player.hasVideo() },
+ bufferProgress{ player.bufferProgress() },
+ bufferedTimeRange{ player.bufferedTimeRange() },
+ isSeekable{ player.isSeekable() },
+ playbackRate{ player.playbackRate() },
+ isPlaying{ player.isPlaying() },
+ loops{ player.loops() },
+ error{ player.error() },
+ isAvailable{ player.isAvailable() },
+ metaData{ player.metaData() }
+ {
+ }
+
+ /*!
+ * Creates the default state of a media player. The default state
+ * is the state the player should have when it is default constructed.
+ */
+ static MediaPlayerState defaultState()
+ {
+ MediaPlayerState state{};
+ state.audioTracks = QList<QMediaMetaData>{};
+ state.videoTracks = QList<QMediaMetaData>{};
+ state.subtitleTracks = QList<QMediaMetaData>{};
+ state.activeAudioTrack = -1;
+ state.activeVideoTrack = -1;
+ state.activeSubtitleTrack = -1;
+ state.audioOutput = nullptr;
+ state.videoOutput = nullptr;
+ state.videoSink = nullptr;
+ state.source = QUrl{};
+ state.sourceDevice = nullptr;
+ state.playbackState = QMediaPlayer::StoppedState;
+ state.mediaStatus = QMediaPlayer::NoMedia;
+ state.duration = 0;
+ state.position = 0;
+ state.hasAudio = false;
+ state.hasVideo = false;
+ state.bufferProgress = 0.0f;
+ state.bufferedTimeRange = QMediaTimeRange{};
+ state.isSeekable = false;
+ state.playbackRate = static_cast<qreal>(1);
+ state.isPlaying = false;
+ state.loops = 1;
+ state.error = QMediaPlayer::NoError;
+ state.isAvailable = true;
+ state.metaData = QMediaMetaData{};
+ return state;
+ }
+
+private:
+ MediaPlayerState() = default;
+
+};
+
+#define COMPARE_EQ_IGNORE_OPTIONAL(actual, expected) \
+ do { \
+ if ((expected).has_value()) { \
+ QCOMPARE_EQ(actual, expected); \
+ } \
+ } while (false)
+
+#define COMPARE_MEDIA_PLAYER_STATE_EQ(actual, expected) \
+ do { \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).audioTracks, (expected).audioTracks); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).videoTracks, (expected).videoTracks); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).subtitleTracks, (expected).subtitleTracks); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).activeAudioTrack, (expected).activeAudioTrack); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).activeVideoTrack, (expected).activeVideoTrack); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).activeSubtitleTrack, (expected).activeSubtitleTrack); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).source, (expected).source); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).sourceDevice, (expected).sourceDevice); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).playbackState, (expected).playbackState); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).mediaStatus, (expected).mediaStatus); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).duration, (expected).duration); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).position, (expected).position); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).hasAudio, (expected).hasAudio); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).hasVideo, (expected).hasVideo); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).bufferProgress, (expected).bufferProgress); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).bufferedTimeRange, (expected).bufferedTimeRange); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).isSeekable, (expected).isSeekable); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).playbackRate, (expected).playbackRate); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).isPlaying, (expected).isPlaying); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).loops, (expected).loops); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).error, (expected).error); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).isAvailable, (expected).isAvailable); \
+ COMPARE_EQ_IGNORE_OPTIONAL((actual).metaData, (expected).metaData); \
+ } while (false)
+
+#endif // MEDIAPLAYERSTATE_H
diff --git a/tests/auto/integration/qmediaplayerbackend/server.h b/tests/auto/integration/qmediaplayerbackend/server.h
new file mode 100644
index 000000000..a6fde1a7a
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/server.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef SERVER_H
+#define SERVER_H
+
+#include <private/qglobal_p.h>
+
+#ifdef QT_FEATURE_network
+
+#include <qstring.h>
+#include <qtcpserver.h>
+#include <qtest.h>
+#include <qurl.h>
+
+QT_USE_NAMESPACE
+
+class UnResponsiveRtspServer : public QObject
+{
+ Q_OBJECT
+public:
+ UnResponsiveRtspServer() : m_server{ new QTcpServer{ this } }
+ {
+ connect(m_server, &QTcpServer::newConnection, this, [&] { m_connected = true; });
+ }
+
+ bool listen() { return m_server->listen(QHostAddress::LocalHost); }
+
+ bool waitForConnection()
+ {
+ return QTest::qWaitFor([this] { return m_connected; });
+ }
+
+ QUrl address() const
+ {
+ return QUrl{ QString{ "rtsp://%1:%2" }
+ .arg(m_server->serverAddress().toString())
+ .arg(m_server->serverPort()) };
+ }
+
+private:
+ QTcpServer *m_server;
+ bool m_connected = false;
+};
+
+#endif // QT_FEATURE_network
+
+#endif // SERVER_H
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/15s.mkv b/tests/auto/integration/qmediaplayerbackend/testdata/15s.mkv
new file mode 100644
index 000000000..80ee0f923
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/15s.mkv
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/3colors_with_sound_1s.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/3colors_with_sound_1s.mp4
new file mode 100644
index 000000000..96ae2e4e3
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/3colors_with_sound_1s.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_jpg_thumbnail.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_jpg_thumbnail.mp4
new file mode 100644
index 000000000..dfeec1546
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_jpg_thumbnail.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_png_thumbnail.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_png_thumbnail.mp4
new file mode 100644
index 000000000..147adf777
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/audio_video_with_png_thumbnail.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/busAv1.webm b/tests/auto/integration/qmediaplayerbackend/testdata/busAv1.webm
new file mode 100644
index 000000000..048d02e8a
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/busAv1.webm
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix.mp4
new file mode 100644
index 000000000..a3661b9d2
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_180_deg_clockwise.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_180_deg_clockwise.mp4
new file mode 100644
index 000000000..9a60850d6
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_180_deg_clockwise.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_270_deg_clockwise.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_270_deg_clockwise.mp4
new file mode 100644
index 000000000..b3ecd486d
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_270_deg_clockwise.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_90_deg_clockwise.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_90_deg_clockwise.mp4
new file mode 100644
index 000000000..dc620d05f
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/color_matrix_90_deg_clockwise.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/duration_issues.webm b/tests/auto/integration/qmediaplayerbackend/testdata/duration_issues.webm
new file mode 100644
index 000000000..87b737949
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/duration_issues.webm
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/h264_avc1_yuv420p10le_tv_bt2020.mov b/tests/auto/integration/qmediaplayerbackend/testdata/h264_avc1_yuv420p10le_tv_bt2020.mov
new file mode 100644
index 000000000..c5a508a1f
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/h264_avc1_yuv420p10le_tv_bt2020.mov
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/multitrack-subtitle-start-at-zero.mkv b/tests/auto/integration/qmediaplayerbackend/testdata/multitrack-subtitle-start-at-zero.mkv
new file mode 100644
index 000000000..1962f00c1
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/multitrack-subtitle-start-at-zero.mkv
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/multitrack.mkv b/tests/auto/integration/qmediaplayerbackend/testdata/multitrack.mkv
new file mode 100644
index 000000000..a3c2e9bb9
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/multitrack.mkv
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/nokia-tune.mp3 b/tests/auto/integration/qmediaplayerbackend/testdata/nokia-tune.mp3
index 2435f65b8..892c2a89e 100644
--- a/tests/auto/integration/qmediaplayerbackend/testdata/nokia-tune.mp3
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/nokia-tune.mp3
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4
new file mode 100644
index 000000000..6b67a3433
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/one_red_frame.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/par_2_3.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/par_2_3.mp4
new file mode 100644
index 000000000..b0d9b3593
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/par_2_3.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/par_3_2.mp4 b/tests/auto/integration/qmediaplayerbackend/testdata/par_3_2.mp4
new file mode 100644
index 000000000..55baed13e
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/par_3_2.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/testdata/subtitletest.mkv b/tests/auto/integration/qmediaplayerbackend/testdata/subtitletest.mkv
new file mode 100644
index 000000000..2051e4df5
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/testdata/subtitletest.mkv
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
index 85d132368..b212b4b63 100644
--- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
+++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
@@ -1,47 +1,73 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
#include "qmediaplayer.h"
+#include "mediaplayerstate.h"
+#include "fake.h"
+#include "fixture.h"
+#include "server.h"
#include <qmediametadata.h>
#include <qaudiobuffer.h>
+#include <qaudiodevice.h>
#include <qvideosink.h>
#include <qvideoframe.h>
#include <qaudiooutput.h>
-
-#include "../shared/mediafileselector.h"
-//TESTED_COMPONENT=src/multimedia
-
+#include <qmediadevices.h>
+#if QT_CONFIG(process)
+#include <qprocess.h>
+#endif
+#include <private/qglobal_p.h>
+#ifdef QT_FEATURE_network
+#include <qtcpserver.h>
+#endif
+#include <qmediatimerange.h>
+#include <private/qplatformvideosink_p.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/private/qquickloader_p.h>
+
+#include "mediafileselector.h"
+#include "mediabackendutils.h"
#include <QtMultimedia/private/qtmultimedia-config_p.h>
+#include "private/qquickvideooutput_p.h"
+
+#include <array>
QT_USE_NAMESPACE
+using namespace Qt::Literals;
+
+namespace {
+static qreal colorDifference(QRgb first, QRgb second)
+{
+ const auto diffVector = QVector3D(qRed(first), qGreen(first), qBlue(first))
+ - QVector3D(qRed(second), qGreen(second), qBlue(second));
+ static const auto normalizationFactor = 1. / (255 * qSqrt(3.));
+ return diffVector.length() * normalizationFactor;
+}
+
+template <typename It>
+It findSimilarColor(It it, It end, QRgb color)
+{
+ return std::min_element(it, end, [color](QRgb first, QRgb second) {
+ return colorDifference(first, color) < colorDifference(second, color);
+ });
+}
+
+template <typename Colors>
+auto findSimilarColorIndex(const Colors &colors, QRgb color)
+{
+ return std::distance(std::begin(colors),
+ findSimilarColor(std::begin(colors), std::end(colors), color));
+}
+}
+
/*
This is the backend conformance test.
@@ -53,19 +79,88 @@ class tst_QMediaPlayerBackend : public QObject
{
Q_OBJECT
public slots:
- void init();
- void cleanup();
void initTestCase();
+ void init() { m_fixture = std::make_unique<Fixture>(); }
+ void cleanup() { m_fixture = nullptr; }
private slots:
- void construction();
- void loadMedia();
- void unloadMedia();
- void loadMediaInLoadingState();
- void playPauseStop();
+ void testMediaFilesAreSupported();
+ void destructor_cancelsPreviousSetSource_whenServerDoesNotRespond();
+ void destructor_emitsOnlyQObjectDestroyedSignal_whenPlayerIsRunning();
+
+ void getters_returnExpectedValues_whenCalledWithDefaultConstructedPlayer_data() const;
+ void getters_returnExpectedValues_whenCalledWithDefaultConstructedPlayer() const;
+
+ void setSource_emitsSourceChanged_whenCalledWithInvalidFile();
+ void setSource_emitsError_whenCalledWithInvalidFile();
+ void setSource_emitsMediaStatusChange_whenCalledWithInvalidFile();
+ void setSource_doesNotEmitPlaybackStateChange_whenCalledWithInvalidFile();
+ void setSource_setsSourceMediaStatusAndError_whenCalledWithInvalidFile();
+ void setSource_initializesExpectedDefaultState();
+ void setSource_initializesExpectedDefaultState_data();
+ void setSource_silentlyCancelsPreviousCall_whenServerDoesNotRespond();
+ void setSource_changesSourceAndMediaStatus_whenCalledWithValidFile();
+ void setSource_updatesExpectedAttributes_whenMediaHasLoaded();
+ void setSource_stopsAndEntersErrorState_whenPlayerWasPlaying();
+ void setSource_loadsAudioTrack_whenCalledWithValidWavFile();
+ void setSource_resetsState_whenCalledWithEmptyUrl();
+ void setSource_resetsState_whenCalledWithEmptyUrl_data();
+ void setSource_loadsNewMedia_whenPreviousMediaWasFullyLoaded();
+ void setSource_loadsCorrectTracks_whenLoadingMediaInSequence();
+ void setSource_remainsInStoppedState_whenPlayerWasStopped();
+ void setSource_entersStoppedState_whenPlayerWasPlaying();
+ void setSource_emitsError_whenSdpFileIsLoaded();
+ void setSource_updatesTrackProperties_data();
+ void setSource_updatesTrackProperties();
+ void setSource_emitsTracksChanged_data();
+ void setSource_emitsTracksChanged();
+
+ void setSourceAndPlay_setCorrectVideoSize_whenVideoHasNonStandardPixelAspectRatio_data();
+ void setSourceAndPlay_setCorrectVideoSize_whenVideoHasNonStandardPixelAspectRatio();
+
+ void pause_doesNotChangePlayerState_whenInvalidFileLoaded();
+ void pause_doesNothing_whenMediaIsNotLoaded();
+ void pause_entersPauseState_whenPlayerWasPlaying();
+ void pause_initializesExpectedDefaultState();
+ void pause_initializesExpectedDefaultState_data();
+ void pause_doesNotAdvancePosition();
+ void pause_playback_resumesFromPausedPosition();
+
+ void play_resetsErrorState_whenCalledWithInvalidFile();
+ void play_resumesPlaying_whenValidMediaIsProvidedAfterInvalidMedia();
+ void play_doesNothing_whenMediaIsNotLoaded();
+ void play_setsPlaybackStateAndMediaStatus_whenValidFileIsLoaded();
+ void play_startsPlaybackAndChangesPosition_whenValidFileIsLoaded();
+ void play_doesNotEnterMediaLoadingState_whenResumingPlayingAfterStop();
+ void playAndSetSource_emitsExpectedSignalsAndStopsPlayback_whenSetSourceWasCalledWithEmptyUrl();
+ void play_createsFramesWithExpectedContentAndIncreasingFrameTime_whenPlayingRtspMediaStream();
+ void play_waitsForLastFrameEnd_whenPlayingVideoWithLongFrames();
+ void play_startsPlayback_withAndWithoutOutputsConnected();
+ void play_startsPlayback_withAndWithoutOutputsConnected_data();
+ void play_playsRtpStream_whenSdpFileIsLoaded();
+ void play_succeedsFromSourceDevice();
+ void play_succeedsFromSourceDevice_data();
+
+ void stop_entersStoppedState_whenPlayerWasPaused();
+ void stop_entersStoppedState_whenPlayerWasPaused_data();
+ void stop_setsPositionToZero_afterPlayingToEndOfMedia();
+
+ void playbackRate_returnsOne_byDefault();
+ void setPlaybackRate_changesPlaybackRateAndEmitsSignal_data();
+ void setPlaybackRate_changesPlaybackRateAndEmitsSignal();
+ void setPlaybackRate_changesPlaybackDuration();
+ void setPlaybackRate_changesPlaybackDuration_data();
+
+ void setVolume_changesVolume_whenVolumeIsInRange();
+ void setVolume_clampsToRange_whenVolumeIsOutsideRange();
+ void setVolume_doesNotChangeMutedState();
+
+ void setMuted_changesMutedState_whenMutedStateChanged();
+ void setMuted_doesNotChangeVolume();
+
void processEOS();
void deleteLaterAtEOS();
- void volumeAndMuted();
+
void volumeAcrossFiles_data();
void volumeAcrossFiles();
void initialVolume();
@@ -73,99 +168,169 @@ private slots:
void seekInStoppedState();
void subsequentPlayback();
void surfaceTest();
-// void multipleSurfaces();
void metadata();
+ void metadata_returnsMetadataWithThumbnail_whenMediaHasThumbnail_data();
+ void metadata_returnsMetadataWithThumbnail_whenMediaHasThumbnail();
+ void metadata_returnsMetadataWithHasHdrContent_whenMediaHasHdrContent_data();
+ void metadata_returnsMetadataWithHasHdrContent_whenMediaHasHdrContent();
void playerStateAtEOS();
void playFromBuffer();
void audioVideoAvailable();
+ void audioVideoAvailable_updatedOnNewMedia();
void isSeekable();
void positionAfterSeek();
- void videoDimensions();
+ void pause_rendersVideoAtCorrectResolution_data();
+ void pause_rendersVideoAtCorrectResolution();
void position();
void multipleMediaPlayback();
+ void multiplePlaybackRateChangingStressTest();
+ void multipleSeekStressTest();
+ void setPlaybackRate_changesActualRateAndFramesRenderingTime_data();
+ void setPlaybackRate_changesActualRateAndFramesRenderingTime();
+ void durationDetectionIssues_data();
+ void durationDetectionIssues();
+ void finiteLoops();
+ void infiniteLoops();
+ void seekOnLoops();
+ void changeLoopsOnTheFly();
+ void seekAfterLoopReset();
+ void changeVideoOutputNoFramesLost();
+ void cleanSinkAndNoMoreFramesAfterStop();
+ void lazyLoadVideo();
+ void videoSinkSignals();
+ void nonAsciiFileName();
+ void setMedia_setsVideoSinkSize_beforePlaying();
+ void play_playsRotatedVideoOutput_whenVideoFileHasOrientationMetadata_data();
+ void play_playsRotatedVideoOutput_whenVideoFileHasOrientationMetadata();
+
+ void setVideoOutput_doesNotStopPlayback_data();
+ void setVideoOutput_doesNotStopPlayback();
+ void setAudioOutput_doesNotStopPlayback_data();
+ void setAudioOutput_doesNotStopPlayback();
+ void swapAudioDevice_doesNotStopPlayback_data();
+ void swapAudioDevice_doesNotStopPlayback();
+
+ void play_readsSubtitle();
+ void multiTrack_validateMetadata();
+ void play_readsSubtitle_fromMultiTrack();
+ void play_readsSubtitle_fromMultiTrack_data();
+
+ void setActiveSubtitleTrack_switchesSubtitles();
+ void setActiveSubtitleTrack_switchesSubtitles_data();
+
+ void setActiveVideoTrack_switchesVideoTrack();
+
+ void disablingAllTracks_doesNotStopPlayback();
+ void disablingAllTracks_beforeTracksChanged_doesNotStopPlayback();
private:
- QUrl selectVideoFile(const QStringList& mediaCandidates);
- bool isWavSupported();
-
- //one second local wav file
- QUrl localWavFile;
- QUrl localWavFile2;
- QUrl localVideoFile;
- QUrl localVideoFile2;
- QUrl videoDimensionTestFile;
- QUrl localCompressedSoundFile;
- QUrl localFileWithMetadata;
-
- bool m_inCISystem;
+ QUrl selectVideoFile(const QStringList &mediaCandidates);
+
+ bool canCreateRtpStream() const;
+#if QT_CONFIG(process)
+ std::unique_ptr<QProcess> createRtpStreamProcess(QString fileName, QString sdpUrl);
+#endif
+ void detectVlcCommand();
+
+ // one second local wav file
+ MaybeUrl m_localWavFile = QUnexpect{};
+ MaybeUrl m_localWavFile2 = QUnexpect{};
+ MaybeUrl m_localVideoFile = QUnexpect{};
+ MaybeUrl m_localVideoFile2 = QUnexpect{};
+ MaybeUrl m_av1File = QUnexpect{};
+ MaybeUrl m_videoDimensionTestFile = QUnexpect{};
+ MaybeUrl m_localCompressedSoundFile = QUnexpect{};
+ MaybeUrl m_localFileWithMetadata = QUnexpect{};
+ MaybeUrl m_localVideoFile3ColorsWithSound = QUnexpect{};
+ MaybeUrl m_videoFileWithJpegThumbnail = QUnexpect{};
+ MaybeUrl m_videoFileWithPngThumbnail = QUnexpect{};
+ MaybeUrl m_oneRedFrameVideo = QUnexpect{};
+ MaybeUrl m_192x108_PAR_2_3_Video = QUnexpect{};
+ MaybeUrl m_192x108_PAR_3_2_Video = QUnexpect{};
+ MaybeUrl m_colorMatrixVideo = QUnexpect{};
+ MaybeUrl m_colorMatrix90degClockwiseVideo = QUnexpect{};
+ MaybeUrl m_colorMatrix180degClockwiseVideo = QUnexpect{};
+ MaybeUrl m_colorMatrix270degClockwiseVideo = QUnexpect{};
+ MaybeUrl m_hdrVideo = QUnexpect{};
+ MaybeUrl m_15sVideo = QUnexpect{};
+ MaybeUrl m_subtitleVideo = QUnexpect{};
+ MaybeUrl m_multitrackVideo = QUnexpect{};
+ MaybeUrl m_multitrackSubtitleStartsAtZeroVideo = QUnexpect{};
+
+ MediaFileSelector m_mediaSelector;
+
+ const std::array<QRgb, 3> m_video3Colors = { { 0xFF0000, 0x00FF00, 0x0000FF } };
+ QString m_vlcCommand;
+
+ std::unique_ptr<Fixture> m_fixture;
};
-/*
- This is a simple video surface which records all presented frames.
-*/
-class TestVideoSink : public QVideoSink
+static bool commandExists(const QString &command)
{
- Q_OBJECT
-public:
- explicit TestVideoSink(bool storeFrames = true)
- : m_storeFrames(storeFrames)
- {
- connect(this, &QVideoSink::videoFrameChanged, this, &TestVideoSink::addVideoFrame);
- }
-public Q_SLOTS:
- void addVideoFrame(const QVideoFrame &frame) {
- if (m_storeFrames)
- m_frameList.append(frame);
- ++m_totalFrames;
- }
+#if defined(Q_OS_WINDOWS)
+ static constexpr QChar separator = ';';
+#else
+ static constexpr QChar separator = ':';
+#endif
+ static const QStringList pathDirs = qEnvironmentVariable("PATH").split(separator);
+ return std::any_of(pathDirs.cbegin(), pathDirs.cend(), [&command](const QString &dir) {
+ QString fullPath = QDir(dir).filePath(command);
+ return QFile::exists(fullPath);
+ });
+}
-public:
- QList<QVideoFrame> m_frameList;
- int m_totalFrames = 0; // used instead of the list when frames are not stored
+static std::unique_ptr<QTemporaryFile> copyResourceToTemporaryFile(QString resource,
+ QString filePattern)
+{
+ QFile resourceFile(resource);
+ if (!resourceFile.open(QIODeviceBase::ReadOnly))
+ return nullptr;
-private:
- bool m_storeFrames;
-};
+ auto temporaryFile = std::make_unique<QTemporaryFile>(filePattern);
+ if (!temporaryFile->open())
+ return nullptr;
-void tst_QMediaPlayerBackend::init()
-{
+ QByteArray bytes = resourceFile.readAll();
+ QDataStream stream(temporaryFile.get());
+ stream.writeRawData(bytes.data(), bytes.length());
+
+ temporaryFile->close();
+
+ return temporaryFile;
}
-QUrl tst_QMediaPlayerBackend::selectVideoFile(const QStringList& mediaCandidates)
+void tst_QMediaPlayerBackend::detectVlcCommand()
{
- // select supported video format
- QMediaPlayer player;
- TestVideoSink *surface = new TestVideoSink;
- player.setVideoOutput(surface);
+ m_vlcCommand = qEnvironmentVariable("QT_VLC_COMMAND");
- QSignalSpy errorSpy(&player, SIGNAL(error(QMediaPlayer::Error)));
+ if (!m_vlcCommand.isEmpty())
+ return;
- for (const QString &s : mediaCandidates) {
- QFileInfo videoFile(s);
- if (!videoFile.exists())
- continue;
- QUrl media = QUrl(QUrl::fromLocalFile(videoFile.absoluteFilePath()));
- player.setSource(media);
- player.pause();
+#if defined(Q_OS_WINDOWS)
+ m_vlcCommand = "vlc.exe";
+#else
+ m_vlcCommand = "vlc";
+#endif
+ if (commandExists(m_vlcCommand))
+ return;
- for (int i = 0; i < 2000 && surface->m_frameList.isEmpty() && errorSpy.isEmpty(); i+=50) {
- QTest::qWait(50);
- }
+ m_vlcCommand.clear();
- if (!surface->m_frameList.isEmpty() && errorSpy.isEmpty()) {
- return media;
- }
- errorSpy.clear();
- }
+#if defined(Q_OS_MACOS)
+ m_vlcCommand = "/Applications/VLC.app/Contents/MacOS/VLC";
+#elif defined(Q_OS_WINDOWS)
+ m_vlcCommand = "C:/Program Files/VideoLAN/VLC/vlc.exe";
+#endif
- return QUrl();
+ if (!QFile::exists(m_vlcCommand))
+ m_vlcCommand.clear();
}
-bool tst_QMediaPlayerBackend::isWavSupported()
+bool tst_QMediaPlayerBackend::canCreateRtpStream() const
{
- return !localWavFile.isEmpty();
+ return !m_vlcCommand.isEmpty();
}
void tst_QMediaPlayerBackend::initTestCase()
@@ -174,412 +339,1731 @@ void tst_QMediaPlayerBackend::initTestCase()
if (!player.isAvailable())
QSKIP("Media player service is not available");
- localWavFile = MediaFileSelector::selectMediaFile(QStringList() << "qrc:/testdata/test.wav");
- localWavFile2 = MediaFileSelector::selectMediaFile(QStringList() << "qrc:/testdata/_test.wav");
+ qRegisterMetaType<MaybeUrl>();
+
+ m_localWavFile = m_mediaSelector.select("qrc:/testdata/test.wav");
+ m_localWavFile2 = m_mediaSelector.select("qrc:/testdata/_test.wav");
+
+ m_localVideoFile =
+ m_mediaSelector.select("qrc:/testdata/colors.mp4", "qrc:/testdata/colors.ogv");
+
+ m_localVideoFile3ColorsWithSound =
+ m_mediaSelector.select("qrc:/testdata/3colors_with_sound_1s.mp4");
+
+ m_videoFileWithJpegThumbnail =
+ m_mediaSelector.select("qrc:/testdata/audio_video_with_jpg_thumbnail.mp4");
+
+ m_videoFileWithPngThumbnail =
+ m_mediaSelector.select("qrc:/testdata/audio_video_with_png_thumbnail.mp4");
+
+#ifndef Q_OS_MACOS // QTBUG-119711 Add support for AV1 decoding with the FFmpeg backend in online installer
+ m_av1File = m_mediaSelector.select("qrc:/testdata/busAv1.webm");
+#endif
+
+ m_localVideoFile2 =
+ m_mediaSelector.select("qrc:/testdata/BigBuckBunny.mp4", "qrc:/testdata/busMpeg4.mp4");
- QStringList mediaCandidates;
- mediaCandidates << "qrc:/testdata/colors.mp4";
- mediaCandidates << "qrc:/testdata/colors.ogv";
- localVideoFile = MediaFileSelector::selectMediaFile(mediaCandidates);
+ m_videoDimensionTestFile = m_mediaSelector.select("qrc:/testdata/BigBuckBunny.mp4");
- mediaCandidates.clear();
- mediaCandidates << "qrc:/testdata/BigBuckBunny.mp4";
- mediaCandidates << "qrc:/testdata/busMpeg4.mp4";
- localVideoFile2 = MediaFileSelector::selectMediaFile(mediaCandidates);
+ m_localCompressedSoundFile =
+ m_mediaSelector.select("qrc:/testdata/nokia-tune.mp3", "qrc:/testdata/nokia-tune.mkv");
- mediaCandidates.clear();
- mediaCandidates << "qrc:/testdata/BigBuckBunny.mp4";
- videoDimensionTestFile = MediaFileSelector::selectMediaFile(mediaCandidates);
+ m_localFileWithMetadata = m_mediaSelector.select("qrc:/testdata/nokia-tune.mp3");
- mediaCandidates.clear();
- mediaCandidates << "qrc:/testdata/nokia-tune.mp3";
- mediaCandidates << "qrc:/testdata/nokia-tune.mkv";
- localCompressedSoundFile = MediaFileSelector::selectMediaFile(mediaCandidates);
+ m_oneRedFrameVideo = m_mediaSelector.select("qrc:/testdata/one_red_frame.mp4");
- localFileWithMetadata =
- MediaFileSelector::selectMediaFile(QStringList() << "qrc:/testdata/nokia-tune.mp3");
+ m_192x108_PAR_2_3_Video = m_mediaSelector.select("qrc:/testdata/par_2_3.mp4");
+ m_192x108_PAR_3_2_Video = m_mediaSelector.select("qrc:/testdata/par_3_2.mp4");
- qgetenv("QT_TEST_CI").toInt(&m_inCISystem,10);
+ m_colorMatrixVideo = m_mediaSelector.select("qrc:/testdata/color_matrix.mp4");
+ m_colorMatrix90degClockwiseVideo =
+ m_mediaSelector.select("qrc:/testdata/color_matrix_90_deg_clockwise.mp4");
+ m_colorMatrix180degClockwiseVideo =
+ m_mediaSelector.select("qrc:/testdata/color_matrix_180_deg_clockwise.mp4");
+ m_colorMatrix270degClockwiseVideo =
+ m_mediaSelector.select("qrc:/testdata/color_matrix_270_deg_clockwise.mp4");
+
+ m_hdrVideo = m_mediaSelector.select("qrc:/testdata/h264_avc1_yuv420p10le_tv_bt2020.mov");
+ m_15sVideo = m_mediaSelector.select("qrc:/testdata/15s.mkv");
+ m_subtitleVideo = m_mediaSelector.select("qrc:/testdata/subtitletest.mkv");
+ m_multitrackVideo = m_mediaSelector.select("qrc:/testdata/multitrack.mkv");
+ m_multitrackSubtitleStartsAtZeroVideo =
+ m_mediaSelector.select("qrc:/testdata/multitrack-subtitle-start-at-zero.mkv");
+
+ detectVlcCommand();
}
-void tst_QMediaPlayerBackend::cleanup()
+void tst_QMediaPlayerBackend::testMediaFilesAreSupported()
{
+ const auto mediaSelectionErrors = m_mediaSelector.dumpErrors();
+ if (!mediaSelectionErrors.isEmpty())
+ qDebug().noquote() << "Dump media selection errors:\n" << mediaSelectionErrors;
+
+ // TODO: probalbly, we should check errors anyway; TBD.
+ QCOMPARE(m_mediaSelector.failedSelectionsCount(), 0);
}
-void tst_QMediaPlayerBackend::construction()
+void tst_QMediaPlayerBackend::destructor_cancelsPreviousSetSource_whenServerDoesNotRespond()
{
- QMediaPlayer player;
- QTRY_VERIFY(player.isAvailable());
+#ifdef QT_FEATURE_network
+ UnResponsiveRtspServer server;
+ QVERIFY(server.listen());
+
+ auto player = std::make_unique<QMediaPlayer>();
+ player->setSource(server.address());
+
+ QVERIFY(server.waitForConnection());
+
+ // Cancel connection (should be fast, but can't be reliably verified
+ // in a test. For now we just verify that we don't crash.
+ player = nullptr;
+#else
+ QSKIP("Test requires network feature");
+#endif
}
-void tst_QMediaPlayerBackend::loadMedia()
+void tst_QMediaPlayerBackend::destructor_emitsOnlyQObjectDestroyedSignal_whenPlayerIsRunning()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ // Arrange
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ m_fixture->player.play();
+
+ // Wait for started
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+
+ m_fixture->clearSpies();
+
+ // Act
+ m_fixture->player.~QMediaPlayer();
+ new (&m_fixture->player) QMediaPlayer;
+
+ // Assert
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 0);
+ QCOMPARE(m_fixture->errorOccurred.size(), 0);
+ QCOMPARE(m_fixture->sourceChanged.size(), 0);
+ QCOMPARE(m_fixture->mediaStatusChanged.size(), 0);
+ QCOMPARE(m_fixture->positionChanged.size(), 0);
+ QCOMPARE(m_fixture->durationChanged.size(), 0);
+ QCOMPARE(m_fixture->metadataChanged.size(), 0);
+ QCOMPARE(m_fixture->volumeChanged.size(), 0);
+ QCOMPARE(m_fixture->mutedChanged.size(), 0);
+ QCOMPARE(m_fixture->bufferProgressChanged.size(), 0);
+ QCOMPARE(m_fixture->destroyed.size(), 1);
+}
+
+void tst_QMediaPlayerBackend::
+ getters_returnExpectedValues_whenCalledWithDefaultConstructedPlayer_data() const
+{
+ QTest::addColumn<bool>("hasAudioOutput");
+ QTest::addColumn<bool>("hasVideoOutput");
+ QTest::addColumn<bool>("hasVideoSink");
+
+ QTest::newRow("noOutput") << false << false << false;
+ QTest::newRow("withAudioOutput") << true << false << false;
+ QTest::newRow("withVideoOutput") << false << true << false;
+ QTest::newRow("withVideoSink") << false << false << true;
+ QTest::newRow("withAllOutputs") << true << true << true;
+}
+
+void tst_QMediaPlayerBackend::getters_returnExpectedValues_whenCalledWithDefaultConstructedPlayer()
+ const
+{
+ QFETCH(const bool, hasAudioOutput);
+ QFETCH(const bool, hasVideoOutput);
+ QFETCH(const bool, hasVideoSink);
+
+ QAudioOutput audioOutput;
+ TestVideoOutput videoOutput;
QMediaPlayer player;
- QAudioOutput output;
- player.setAudioOutput(&output);
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia);
+ if (hasAudioOutput)
+ player.setAudioOutput(&audioOutput);
- QSignalSpy stateSpy(&player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
- QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
- QSignalSpy mediaSpy(&player, SIGNAL(sourceChanged(QUrl)));
+ if (hasVideoOutput)
+ player.setVideoOutput(&videoOutput);
- player.setSource(localWavFile);
+ if (hasVideoSink)
+ player.setVideoSink(videoOutput.videoSink());
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
+ MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ expectedState.audioOutput = hasAudioOutput ? &audioOutput : nullptr;
+ expectedState.videoOutput = (hasVideoOutput && !hasVideoSink) ? &videoOutput : nullptr;
+ expectedState.videoSink = (hasVideoSink || hasVideoOutput) ? videoOutput.videoSink() : nullptr;
- QVERIFY(player.mediaStatus() != QMediaPlayer::NoMedia);
- QVERIFY(player.mediaStatus() != QMediaPlayer::InvalidMedia);
- QVERIFY(player.source() == localWavFile);
+ const MediaPlayerState actualState{ player };
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+}
- QCOMPARE(stateSpy.count(), 0);
- QVERIFY(statusSpy.count() > 0);
- QCOMPARE(mediaSpy.count(), 1);
- QCOMPARE(mediaSpy.last()[0].value<QUrl>(), localWavFile);
+void tst_QMediaPlayerBackend::setSource_emitsSourceChanged_whenCalledWithInvalidFile()
+{
+ m_fixture->player.setSource({ "Some not existing media" });
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QCOMPARE_EQ(m_fixture->sourceChanged, SignalList({ { QUrl("Some not existing media") } }));
+}
+
+void tst_QMediaPlayerBackend::setSource_emitsError_whenCalledWithInvalidFile()
+{
+ m_fixture->player.setSource({ "Some not existing media" });
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
- QVERIFY(player.hasAudio());
- QVERIFY(!player.hasVideo());
+ QCOMPARE_EQ(m_fixture->errorOccurred[0][0], QMediaPlayer::ResourceError);
}
-void tst_QMediaPlayerBackend::unloadMedia()
+void tst_QMediaPlayerBackend::setSource_emitsMediaStatusChange_whenCalledWithInvalidFile()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ m_fixture->player.setSource({ "Some not existing media" });
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
- QMediaPlayer player;
- QAudioOutput output;
- player.setAudioOutput(&output);
+ QCOMPARE_EQ(m_fixture->mediaStatusChanged,
+ SignalList({ { QMediaPlayer::LoadingMedia }, { QMediaPlayer::InvalidMedia } }));
+}
- QSignalSpy stateSpy(&player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
- QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
- QSignalSpy mediaSpy(&player, SIGNAL(sourceChanged(QUrl)));
- QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64)));
- QSignalSpy durationSpy(&player, SIGNAL(durationChanged(qint64)));
+void tst_QMediaPlayerBackend::setSource_doesNotEmitPlaybackStateChange_whenCalledWithInvalidFile()
+{
+ m_fixture->player.setSource({ "Some not existing media" });
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
- player.setSource(localWavFile);
+ QVERIFY(m_fixture->playbackStateChanged.empty());
+}
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+void tst_QMediaPlayerBackend::setSource_setsSourceMediaStatusAndError_whenCalledWithInvalidFile()
+{
+ const QUrl invalidFile{ "Some not existing media" };
+
+ m_fixture->player.setSource(invalidFile);
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
+
+ MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ expectedState.source = invalidFile;
+ expectedState.mediaStatus = QMediaPlayer::InvalidMedia;
+ expectedState.error = QMediaPlayer::ResourceError;
+
+ const MediaPlayerState actualState{ m_fixture->player };
+
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+}
+
+void tst_QMediaPlayerBackend::setSource_initializesExpectedDefaultState()
+{
+ QFETCH(MaybeUrl, url);
+ CHECK_SELECTED_URL(url);
+
+ QMediaPlayer &player = m_fixture->player;
+ player.setSource(*url);
+
+ MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ expectedState.source = *url;
+ expectedState.mediaStatus = QMediaPlayer::LoadingMedia;
+
+ if (isGStreamerPlatform()) {
+ // gstreamer initializes the tracks
+ expectedState.audioTracks = std::nullopt;
+ expectedState.videoTracks = std::nullopt;
+ expectedState.activeAudioTrack = std::nullopt;
+ expectedState.activeVideoTrack = std::nullopt;
+ expectedState.hasAudio = std::nullopt;
+ expectedState.hasVideo = std::nullopt;
+
+ expectedState.isSeekable = true;
+ }
+
+ const MediaPlayerState actualState{ m_fixture->player };
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+}
+
+void tst_QMediaPlayerBackend::setSource_initializesExpectedDefaultState_data()
+{
+ QTest::addColumn<MaybeUrl>("url");
+
+ QTest::addRow("with wave file") << m_localWavFile;
+ QTest::addRow("with video file") << m_localVideoFile;
+ QTest::addRow("with av1 file") << m_av1File;
+ QTest::addRow("with compressed sound file") << m_localCompressedSoundFile;
+}
+
+void tst_QMediaPlayerBackend::setSource_silentlyCancelsPreviousCall_whenServerDoesNotRespond()
+{
+#ifdef QT_FEATURE_network
+ CHECK_SELECTED_URL(m_localVideoFile);
+
+ UnResponsiveRtspServer server;
+
+ QVERIFY(server.listen());
+
+ m_fixture->player.setSource(server.address());
+ QVERIFY(server.waitForConnection());
+
+ m_fixture->player.setSource(*m_localVideoFile);
+
+ // Cancellation can not be reliably verified due to relatively short timeout,
+ // but we can verify that the player is in the correct state.
+ QTRY_COMPARE_EQ(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ // Cancellation is silent
+ QVERIFY(m_fixture->errorOccurred.empty());
+
+ // Media status is emitted as if only one file was loaded
+ const SignalList expectedMediaStatus = { { QMediaPlayer::LoadingMedia },
+ { QMediaPlayer::LoadedMedia } };
+ QCOMPARE_EQ(m_fixture->mediaStatusChanged, expectedMediaStatus);
+
+ // Two media source changed signals should be emitted still
+ const SignalList expectedSource = { { server.address() }, { *m_localVideoFile } };
+ QCOMPARE_EQ(m_fixture->sourceChanged, expectedSource);
- QVERIFY(player.position() == 0);
-#ifdef Q_OS_QNX
- // QNX mm-renderer only updates the duration when 'play' is triggered
- QVERIFY(player.duration() == 0);
#else
- QVERIFY(player.duration() > 0);
+ QSKIP("Test requires network feature");
#endif
+}
- player.play();
+void tst_QMediaPlayerBackend::setSource_changesSourceAndMediaStatus_whenCalledWithValidFile()
+{
+ CHECK_SELECTED_URL(m_localVideoFile);
- QTRY_VERIFY(player.position() > 0);
- QVERIFY(player.duration() > 0);
+ m_fixture->player.setSource(*m_localVideoFile);
- stateSpy.clear();
- statusSpy.clear();
- mediaSpy.clear();
- positionSpy.clear();
- durationSpy.clear();
+ QCOMPARE_EQ(m_fixture->mediaStatusChanged, SignalList({ { QMediaPlayer::LoadingMedia } }));
- player.setSource(QUrl());
+ MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ expectedState.source = *m_localVideoFile;
+ expectedState.mediaStatus = QMediaPlayer::LoadingMedia;
- QVERIFY(player.position() <= 0);
- QVERIFY(player.duration() <= 0);
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia);
- QCOMPARE(player.source(), QUrl());
+ if (isGStreamerPlatform()) // gstreamer synchronously identifies file streams as seekable
+ expectedState.isSeekable = true;
+
+ MediaPlayerState actualState{ m_fixture->player };
- QVERIFY(!statusSpy.isEmpty());
- QVERIFY(!mediaSpy.isEmpty());
+ QSKIP_GSTREAMER("QTBUG-124005: spurious failures");
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
}
-void tst_QMediaPlayerBackend::loadMediaInLoadingState()
+void tst_QMediaPlayerBackend::setSource_updatesExpectedAttributes_whenMediaHasLoaded()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ CHECK_SELECTED_URL(m_localVideoFile);
+
+ m_fixture->player.setSource(*m_localVideoFile);
+
+ QTRY_COMPARE_EQ(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ MediaPlayerState expectedState = MediaPlayerState::defaultState();
+
+ // Modify all attributes that are supposed to change with this media file
+ // All other state variables are verified to be unchanged.
+ expectedState.source = *m_localVideoFile;
+ expectedState.mediaStatus = QMediaPlayer::LoadedMedia;
+ expectedState.audioTracks = std::nullopt; // Don't compare
+ expectedState.videoTracks = std::nullopt; // Don't compare
+ expectedState.activeAudioTrack = 0;
+ expectedState.activeVideoTrack = 0;
+
+ if (isGStreamerPlatform())
+ expectedState.duration = 15019;
+ else if (isDarwinPlatform())
+ expectedState.duration = 15000;
+ else
+ expectedState.duration = 15018;
+ expectedState.hasAudio = true;
+ expectedState.hasVideo = true;
+ expectedState.isSeekable = true;
+ expectedState.metaData = std::nullopt; // Don't compare
+
+ if (isGStreamerPlatform())
+ expectedState.bufferProgress = std::nullopt; // QTBUG-124633: can change before play()
+
+ MediaPlayerState actualState{ m_fixture->player };
+
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+}
+
+void tst_QMediaPlayerBackend::setSource_stopsAndEntersErrorState_whenPlayerWasPlaying()
+{
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ // Arrange
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ m_fixture->player.play();
+ QTRY_VERIFY(m_fixture->framesCount > 0);
+ QCOMPARE(m_fixture->errorOccurred.size(), 0);
+
+ // Act
+ m_fixture->player.setSource(QUrl("Some not existing media"));
+
+ // Assert
+ const int savedFramesCount = m_fixture->framesCount;
+
+ QCOMPARE(m_fixture->player.source(), QUrl("Some not existing media"));
+
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::InvalidMedia);
+ QTRY_COMPARE(m_fixture->player.error(), QMediaPlayer::ResourceError);
+
+ QVERIFY(!m_fixture->surface.videoFrame().isValid());
+
+ QCOMPARE(m_fixture->errorOccurred.size(), 1);
+
+ QTest::qWait(20);
+ QCOMPARE(m_fixture->framesCount, savedFramesCount);
+}
+
+void tst_QMediaPlayerBackend::setSource_loadsAudioTrack_whenCalledWithValidWavFile()
+{
+ CHECK_SELECTED_URL(m_localWavFile);
+
+ m_fixture->player.setSource(*m_localWavFile);
+
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+
+ QVERIFY(m_fixture->player.mediaStatus() != QMediaPlayer::NoMedia);
+ QVERIFY(m_fixture->player.mediaStatus() != QMediaPlayer::InvalidMedia);
+ QVERIFY(m_fixture->player.source() == *m_localWavFile);
+
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 0);
+ QVERIFY(m_fixture->mediaStatusChanged.size() > 0);
+ QCOMPARE(m_fixture->sourceChanged.size(), 1);
+ QCOMPARE(m_fixture->sourceChanged.last()[0].value<QUrl>(), *m_localWavFile);
+
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ QVERIFY(m_fixture->player.hasAudio());
+ QVERIFY(!m_fixture->player.hasVideo());
+}
+
+void tst_QMediaPlayerBackend::setSource_resetsState_whenCalledWithEmptyUrl()
+{
+ QFETCH(MaybeUrl, url);
+ CHECK_SELECTED_URL(url);
+
+ QMediaPlayer &player = m_fixture->player;
+
+ // Load valid media and start playing
+ player.setSource(*url);
- QMediaPlayer player;
- QAudioOutput output;
- player.setAudioOutput(&output);
- player.setSource(localWavFile2);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadingMedia);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
- // Sets new media while old has not been finished.
- player.setSource(localWavFile);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadingMedia);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ QCOMPARE(player.position(), 0);
+
+ if (isQNXPlatform())
+ // QNX mm-renderer updates the duration when 'play' is triggered
+ QCOMPARE(player.duration(), 0);
+ else
+ QCOMPARE_GT(player.duration(), 0);
+
player.play();
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
- player.setSource(localWavFile2);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadingMedia);
+ QTRY_COMPARE_GT(player.position(), 0);
+ if (isGStreamerPlatform())
+ QTRY_COMPARE_GT(player.duration(), 0); // duration update is asynchronous
+ else
+ QCOMPARE_GT(player.duration(), 0);
+
+ // Set empty URL and verify that state is fully reset to default
+ m_fixture->clearSpies();
+
+ m_fixture->player.setSource(QUrl());
+
+ QVERIFY(!m_fixture->mediaStatusChanged.isEmpty());
+ QVERIFY(!m_fixture->sourceChanged.isEmpty());
+
+ MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ if (isGStreamerPlatform()) // QTBUG-124005: no buffer progress update
+ expectedState.bufferProgress = std::nullopt;
+ const MediaPlayerState actualState{ player };
+
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
}
-void tst_QMediaPlayerBackend::playPauseStop()
+void tst_QMediaPlayerBackend::setSource_resetsState_whenCalledWithEmptyUrl_data()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ QTest::addColumn<MaybeUrl>("url");
- QMediaPlayer player;
- QAudioOutput output;
- player.setAudioOutput(&output);
+ QTest::addRow("with wave file") << m_localWavFile;
+ QTest::addRow("with video file") << m_localVideoFile;
+}
- QSignalSpy stateSpy(&player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
- QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
- QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64)));
- QSignalSpy errorSpy(&player, SIGNAL(errorOccurred(QMediaPlayer::Error, const QString&)));
+void tst_QMediaPlayerBackend::setSource_loadsNewMedia_whenPreviousMediaWasFullyLoaded()
+{
+ CHECK_SELECTED_URL(m_localWavFile);
+ CHECK_SELECTED_URL(m_localWavFile2);
+
+ // Load media and wait for it to completely load
+ m_fixture->player.setSource(*m_localWavFile2);
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadingMedia);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ // Load another media file, play it, and wait for it to enter playing state
+ m_fixture->player.setSource(*m_localWavFile);
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadingMedia);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ m_fixture->player.play();
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+
+ // Load first file again, and wait for it to start loading
+ m_fixture->player.setSource(*m_localWavFile2);
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadingMedia);
+}
- // Check play() without a media
- player.play();
+void tst_QMediaPlayerBackend::setSource_loadsCorrectTracks_whenLoadingMediaInSequence()
+{
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+ CHECK_SELECTED_URL(m_localWavFile2);
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia);
- QCOMPARE(player.error(), QMediaPlayer::NoError);
- QCOMPARE(player.position(), 0);
- QCOMPARE(stateSpy.count(), 0);
- QCOMPARE(statusSpy.count(), 0);
- QCOMPARE(positionSpy.count(), 0);
- QCOMPARE(errorSpy.count(), 0);
+ // Load audio/video file, play it, and verify that both tracks are loaded
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ m_fixture->player.play();
+ QTRY_COMPARE_EQ(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+ QVERIFY(m_fixture->surface.waitForFrame().isValid());
+ QVERIFY(m_fixture->player.hasAudio());
+ QVERIFY(m_fixture->player.hasVideo());
- // Check pause() without a media
- player.pause();
+ m_fixture->clearSpies();
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia);
- QCOMPARE(player.error(), QMediaPlayer::NoError);
- QCOMPARE(player.position(), 0);
- QCOMPARE(stateSpy.count(), 0);
- QCOMPARE(statusSpy.count(), 0);
- QCOMPARE(positionSpy.count(), 0);
- QCOMPARE(errorSpy.count(), 0);
+ // Load an audio file, and verify that only audio track is loaded
+ m_fixture->player.setSource(*m_localWavFile2);
- // The rest is with a valid media
+ QTRY_COMPARE_EQ(m_fixture->player.mediaStatus(), QMediaPlayer::MediaStatus::LoadedMedia);
- player.setSource(localWavFile);
+ QCOMPARE(m_fixture->player.source(), *m_localWavFile2);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 1);
+ QCOMPARE(m_fixture->errorOccurred.size(), 0);
+ QVERIFY(m_fixture->player.hasAudio());
+ QVERIFY(!m_fixture->player.hasVideo());
+ QVERIFY(!m_fixture->surface.videoFrame().isValid());
- QCOMPARE(player.position(), qint64(0));
+ m_fixture->player.play();
- player.play();
+ // Load video only file, and verify that only video track is loaded
+ m_fixture->player.setSource(*m_localVideoFile2);
- QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
+ QTRY_COMPARE_EQ(m_fixture->player.mediaStatus(), QMediaPlayer::MediaStatus::LoadedMedia);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QVERIFY(m_fixture->player.hasVideo());
+ QVERIFY(!m_fixture->player.hasAudio());
+ QCOMPARE(m_fixture->errorOccurred.size(), 0);
+}
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PlayingState);
- QTRY_VERIFY(statusSpy.count() > 0 &&
- statusSpy.last()[0].value<QMediaPlayer::MediaStatus>() == QMediaPlayer::BufferedMedia);
+void tst_QMediaPlayerBackend::setSource_remainsInStoppedState_whenPlayerWasStopped()
+{
+ CHECK_SELECTED_URL(m_localWavFile);
+ CHECK_SELECTED_URL(m_localWavFile2);
+
+ // Arrange
+ m_fixture->player.setSource(*m_localWavFile);
+ m_fixture->player.play();
+ QTRY_VERIFY(m_fixture->player.position() > 100);
+ m_fixture->player.stop();
+ m_fixture->clearSpies();
+
+ // Act
+ m_fixture->player.setSource(*m_localWavFile2);
+
+ // Assert
+ QTRY_VERIFY(m_fixture->mediaStatusChanged.size() > 0);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QCOMPARE_EQ(m_fixture->mediaStatusChanged,
+ SignalList({ { QMediaPlayer::LoadingMedia }, { QMediaPlayer::LoadedMedia } }));
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QVERIFY(m_fixture->playbackStateChanged.empty());
+}
- QTRY_VERIFY(player.position() > 100);
- QVERIFY(player.duration() > 0);
- QTRY_VERIFY(positionSpy.count() > 0);
- QTRY_VERIFY(positionSpy.last()[0].value<qint64>() > 0);
+void tst_QMediaPlayerBackend::setSource_entersStoppedState_whenPlayerWasPlaying()
+{
+ CHECK_SELECTED_URL(m_localWavFile);
+ CHECK_SELECTED_URL(m_localWavFile2);
+
+ // Arrange
+ m_fixture->player.setSource(*m_localWavFile2);
+ m_fixture->clearSpies();
+ m_fixture->player.play();
+ QTRY_VERIFY(m_fixture->player.position() > 100);
+
+ // Act
+ m_fixture->player.setSource(*m_localWavFile);
+
+ // Assert
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QTRY_COMPARE(m_fixture->mediaStatusChanged,
+ SignalList({
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::BufferingMedia },
+ { QMediaPlayer::BufferedMedia },
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::LoadingMedia },
+ { QMediaPlayer::LoadedMedia },
+ }));
+
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QTRY_COMPARE(m_fixture->playbackStateChanged,
+ SignalList({ { QMediaPlayer::PlayingState }, { QMediaPlayer::StoppedState } }));
+
+ QTRY_VERIFY(!m_fixture->positionChanged.empty()
+ && m_fixture->positionChanged.last()[0].value<qint64>() == 0);
+
+ QCOMPARE(m_fixture->player.position(), 0);
+}
- stateSpy.clear();
- statusSpy.clear();
- positionSpy.clear();
+void tst_QMediaPlayerBackend::setSource_emitsError_whenSdpFileIsLoaded()
+{
+#if !QT_CONFIG(process)
+ QSKIP("This test requires QProcess support");
+#else
+ // NOTE: This test checks that playing rtp streams using local .sdp file as a source is blocked
+ // by default. For when the user wants to override these defaults, see
+ // play_playsRtpStream_whenSdpFileIsLoaded
- qint64 positionBeforePause = player.position();
- player.pause();
+ if (!isFFMPEGPlatform())
+ QSKIP("This test is only for FFmpeg backend");
- QCOMPARE(player.playbackState(), QMediaPlayer::PausedState);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
+ // Create stream
+ if (!canCreateRtpStream())
+ QSKIP("Rtp stream cannot be created");
+
+ // Make sure the default whitelist is used
+ qunsetenv("QT_FFMPEG_PROTOCOL_WHITELIST");
+
+ auto temporaryFile = copyResourceToTemporaryFile(":/testdata/colors.mp4", "colors.XXXXXX.mp4");
+ QVERIFY(temporaryFile);
+
+ // Pass a "file:" URL to VLC in order to generate an .sdp file
+ const QUrl sdpUrl = QUrl::fromLocalFile(QFileInfo("test.sdp").absoluteFilePath());
+
+ auto process = createRtpStreamProcess(temporaryFile->fileName(), sdpUrl.toString());
+ QVERIFY2(process, "Cannot start rtp process");
+
+ auto processCloser = qScopeGuard([&process, &sdpUrl]() {
+ // End stream
+ process->close();
+
+ // Remove .sdp file created by VLC
+ QFile(sdpUrl.toLocalFile()).remove();
+ });
+
+ m_fixture->player.setSource(sdpUrl);
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
+#endif // QT_CONFIG(process)
+}
+
+void tst_QMediaPlayerBackend::setSource_updatesTrackProperties_data()
+{
+ QTest::addColumn<MaybeUrl>("url");
+ QTest::addColumn<int>("numberOfVideoTracks");
+ QTest::addColumn<int>("numberOfAudioTracks");
+ QTest::addColumn<int>("numberOfSubtitleTracks");
+
+ QTest::addRow("video file with audio") << m_localVideoFile3ColorsWithSound << 1 << 1 << 0;
+ QTest::addRow("video file without audio") << m_colorMatrixVideo << 1 << 0 << 0;
+ QTest::addRow("uncompressed audio file") << m_localWavFile << 0 << 1 << 0;
+ QTest::addRow("compressed audio file") << m_localCompressedSoundFile << 0 << 1 << 0;
+ QTest::addRow("video with subtitle") << m_subtitleVideo << 1 << 1 << 1;
+ QTest::addRow("video with multiple streams") << m_multitrackVideo << 2 << 2 << 2;
+}
+
+void tst_QMediaPlayerBackend::setSource_updatesTrackProperties()
+{
+ QFETCH(MaybeUrl, url);
+ QFETCH(int, numberOfVideoTracks);
+ QFETCH(int, numberOfAudioTracks);
+ QFETCH(int, numberOfSubtitleTracks);
+
+ QMediaPlayer &player = m_fixture->player;
+
+ CHECK_SELECTED_URL(url);
+
+ player.setSource(*url);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PausedState);
+ QTRY_COMPARE(player.videoTracks().size(), numberOfVideoTracks);
+ QTRY_COMPARE(player.audioTracks().size(), numberOfAudioTracks);
+ QTRY_COMPARE(player.subtitleTracks().size(), numberOfSubtitleTracks);
+}
+
+void tst_QMediaPlayerBackend::setSource_emitsTracksChanged_data()
+{
+ QTest::addColumn<MaybeUrl>("url");
+ QTest::addColumn<int>("numberOfVideoTracks");
+ QTest::addColumn<int>("numberOfAudioTracks");
+ QTest::addColumn<int>("numberOfSubtitleTracks");
+
+ QTest::addRow("video file with audio") << m_localVideoFile3ColorsWithSound << 1 << 1 << 0;
+ QTest::addRow("video file without audio") << m_colorMatrixVideo << 1 << 0 << 0;
+ QTest::addRow("uncompressed audio file") << m_localWavFile << 0 << 1 << 0;
+ QTest::addRow("compressed audio file") << m_localCompressedSoundFile << 0 << 1 << 0;
+ QTest::addRow("video with subtitle") << m_subtitleVideo << 1 << 1 << 1;
+ QTest::addRow("video with multiple streams") << m_multitrackVideo << 2 << 2 << 2;
+}
+
+void tst_QMediaPlayerBackend::setSource_emitsTracksChanged()
+{
+ QFETCH(MaybeUrl, url);
+ QFETCH(int, numberOfVideoTracks);
+ QFETCH(int, numberOfAudioTracks);
+ QFETCH(int, numberOfSubtitleTracks);
+
+ QMediaPlayer &player = m_fixture->player;
+
+ CHECK_SELECTED_URL(url);
+
+ QSignalSpy tracksChanged(&player, &QMediaPlayer::tracksChanged);
+ player.setSource(*url);
+
+ QVERIFY(tracksChanged.wait());
+
+ QCOMPARE(player.videoTracks().size(), numberOfVideoTracks);
+ QCOMPARE(player.audioTracks().size(), numberOfAudioTracks);
+ QCOMPARE(player.subtitleTracks().size(), numberOfSubtitleTracks);
+}
+
+void tst_QMediaPlayerBackend::
+ setSourceAndPlay_setCorrectVideoSize_whenVideoHasNonStandardPixelAspectRatio_data()
+{
+ QTest::addColumn<MaybeUrl>("url");
+ QTest::addColumn<QSize>("expectedVideoSize");
+
+ QTest::addRow("Horizontal expanding (par=3/2)")
+ << m_192x108_PAR_3_2_Video << QSize(192 * 3 / 2, 108);
+
+ if (isGStreamerPlatform())
+ // QTBUG-125249: gstreamer tries "to keep the input height (because of interlacing)"
+ QTest::addRow("Horizontal shrinking (par=2/3)")
+ << m_192x108_PAR_2_3_Video << QSize(192 * 2 / 3, 108);
+ else
+ QTest::addRow("Vertical expanding (par=2/3)")
+ << m_192x108_PAR_2_3_Video << QSize(192, 108 * 3 / 2);
+}
+
+void tst_QMediaPlayerBackend::
+ setSourceAndPlay_setCorrectVideoSize_whenVideoHasNonStandardPixelAspectRatio()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("SKIP initTestCase on CI, because of QTBUG-126428");
+#endif
+ if (isGStreamerPlatform() && isCI())
+ QSKIP("QTBUG-124005: Fails with gstreamer on CI");
+
+ QFETCH(MaybeUrl, url);
+ QFETCH(QSize, expectedVideoSize);
+
+ CHECK_SELECTED_URL(url);
+
+ m_fixture->player.setSource(*url);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QCOMPARE(m_fixture->player.metaData().value(QMediaMetaData::Resolution), QSize(192, 108));
+
+ QCOMPARE(m_fixture->surface.videoSize(), expectedVideoSize);
+
+ m_fixture->player.play();
+
+ auto frame = m_fixture->surface.waitForFrame();
+ QVERIFY(frame.isValid());
+ QCOMPARE(frame.size(), expectedVideoSize);
+ QCOMPARE(frame.surfaceFormat().frameSize(), expectedVideoSize);
+ QCOMPARE(frame.surfaceFormat().viewport(), QRect(QPoint(), expectedVideoSize));
+
+#ifdef Q_OS_ANDROID
+ QSKIP("frame.toImage will return null image because of QTBUG-108446");
+#endif
+
+ auto image = frame.toImage();
+ QCOMPARE(frame.size(), expectedVideoSize);
+
+ // clang-format off
+
+ // Video schema:
+ //
+ // 192
+ // *---------------------*
+ // | White | |
+ // | | |
+ // |----------/ | 108
+ // | Red |
+ // | |
+ // *---------------------*
+
+ // clang-format on
+
+ // check the proper scaling
+ const std::vector<QRgb> colors = { 0xFFFFFF, 0xFF0000, 0xFF00, 0xFF, 0x0 };
+
+ const auto pixelsOffset = 4;
+ const auto halfSize = expectedVideoSize / 2;
+
+ QCOMPARE(findSimilarColorIndex(colors, image.pixel(0, 0)), 0);
+ QCOMPARE(findSimilarColorIndex(colors, image.pixel(halfSize.width() - pixelsOffset, 0)), 0);
+ QCOMPARE(findSimilarColorIndex(colors, image.pixel(0, halfSize.height() - pixelsOffset)), 0);
+ QCOMPARE(findSimilarColorIndex(colors,
+ image.pixel(halfSize.width() - pixelsOffset,
+ halfSize.height() - pixelsOffset)),
+ 0);
+
+ QCOMPARE(findSimilarColorIndex(colors, image.pixel(halfSize.width() + pixelsOffset, 0)), 1);
+ QCOMPARE(findSimilarColorIndex(colors, image.pixel(0, halfSize.height() + pixelsOffset)), 1);
+ QCOMPARE(findSimilarColorIndex(colors,
+ image.pixel(halfSize.width() + pixelsOffset,
+ halfSize.height() + pixelsOffset)),
+ 1);
+}
+
+void tst_QMediaPlayerBackend::pause_doesNotChangePlayerState_whenInvalidFileLoaded()
+{
+ m_fixture->player.setSource({ "Some not existing media" });
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
+
+ const MediaPlayerState expectedState{ m_fixture->player };
+
+ m_fixture->player.pause();
+
+ const MediaPlayerState actualState{ m_fixture->player };
+
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+}
+
+void tst_QMediaPlayerBackend::pause_doesNothing_whenMediaIsNotLoaded()
+{
+ m_fixture->player.pause();
+
+ const MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ const MediaPlayerState actualState{ m_fixture->player };
+
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+
+ QVERIFY(m_fixture->playbackStateChanged.empty());
+ QVERIFY(m_fixture->mediaStatusChanged.empty());
+ QVERIFY(m_fixture->positionChanged.empty());
+ QVERIFY(m_fixture->errorOccurred.empty());
+}
+
+void tst_QMediaPlayerBackend::pause_entersPauseState_whenPlayerWasPlaying()
+{
+ CHECK_SELECTED_URL(m_localWavFile);
+
+ // Arrange
+ m_fixture->player.setSource(*m_localWavFile);
+ m_fixture->player.play();
+ QTRY_COMPARE_GT(m_fixture->player.position(), 100);
+ m_fixture->clearSpies();
+ const qint64 positionBeforePause = m_fixture->player.position();
+
+ // Act
+ m_fixture->player.pause();
+
+ // Assert
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::PausedState);
+ QCOMPARE_EQ(m_fixture->playbackStateChanged, SignalList({ { QMediaPlayer::PausedState } }));
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::BufferedMedia);
+
+ QTRY_COMPARE_LT(qAbs(m_fixture->player.position() - positionBeforePause), 200);
QTest::qWait(500);
- QTRY_VERIFY(qAbs(player.position() - positionBeforePause) < 150);
+ QTRY_COMPARE_LT(qAbs(m_fixture->player.position() - positionBeforePause), 200);
+}
- stateSpy.clear();
- statusSpy.clear();
+void tst_QMediaPlayerBackend::pause_initializesExpectedDefaultState()
+{
+ QFETCH(MaybeUrl, url);
+ QFETCH(bool, hasVideo);
+ QFETCH(bool, hasAudio);
+ CHECK_SELECTED_URL(url);
- player.stop();
+ if (isFFMPEGPlatform() && url->path().contains("Av1"))
+ QSKIP("QTBUG-119711: ffmpeg's binaries on CI do not support av1");
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QMediaPlayer &player = m_fixture->player;
+ player.setSource(*url);
+ player.pause();
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
- //it's allowed to emit statusChanged() signal async
- QTRY_COMPARE(statusSpy.count(), 1);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::LoadedMedia);
+ QTRY_COMPARE(player.playbackState(), QMediaPlayer::PausedState);
- //ensure the position is reset to 0 at stop and positionChanged(0) is emitted
- QTRY_COMPARE(player.position(), qint64(0));
- QCOMPARE(positionSpy.last()[0].value<qint64>(), qint64(0));
- QVERIFY(player.duration() > 0);
+ MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ expectedState.source = *url;
+ expectedState.playbackState = QMediaPlayer::PausedState;
+ expectedState.isSeekable = true;
- stateSpy.clear();
- statusSpy.clear();
- positionSpy.clear();
+ expectedState.mediaStatus = std::nullopt;
+ expectedState.duration = std::nullopt;
+ expectedState.bufferProgress = std::nullopt;
- player.play();
+ expectedState.audioTracks = std::nullopt;
+ expectedState.videoTracks = std::nullopt;
+ expectedState.metaData = std::nullopt;
- QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PlayingState);
- QCOMPARE(statusSpy.count(), 1); // Should not go through Loading again when play -> stop -> play
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::BufferedMedia);
+ if (hasVideo) {
+ expectedState.activeVideoTrack = 0;
+ expectedState.hasVideo = std::nullopt;
+ }
- player.stop();
- stateSpy.clear();
- statusSpy.clear();
- positionSpy.clear();
+ if (hasAudio) {
+ expectedState.activeAudioTrack = 0;
+ expectedState.hasAudio = std::nullopt;
+ }
- player.setSource(localWavFile2);
+ const MediaPlayerState actualState{ player };
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
- QTRY_VERIFY(statusSpy.count() > 0);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::LoadedMedia);
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.count(), 0);
+ QVERIFY(actualState.mediaStatus == QMediaPlayer::BufferingMedia
+ || actualState.mediaStatus == QMediaPlayer::BufferedMedia);
+
+ if (hasVideo)
+ QCOMPARE(actualState.videoTracks->size(), 1);
+ if (hasAudio)
+ QCOMPARE(actualState.audioTracks->size(), 1);
+
+ QEXPECT_FAIL_GSTREAMER("", "GStreamer doesn't update bufferProgress while paused", Continue);
+
+ QTRY_COMPARE_GT(actualState.bufferProgress, 0);
+}
+
+void tst_QMediaPlayerBackend::pause_initializesExpectedDefaultState_data()
+{
+ QTest::addColumn<MaybeUrl>("url");
+ QTest::addColumn<bool>("hasVideo");
+ QTest::addColumn<bool>("hasAudio");
+
+ QTest::addRow("with wave file") << m_localWavFile << false << true;
+ QTest::addRow("with video file") << m_localVideoFile << true << true;
+ QTest::addRow("with av1 file") << m_av1File << true << false;
+ QTest::addRow("with compressed sound file") << m_localCompressedSoundFile << false << true;
+}
+
+void tst_QMediaPlayerBackend::pause_doesNotAdvancePosition()
+{
+ using namespace std::chrono_literals;
+
+ CHECK_SELECTED_URL(m_localVideoFile);
+
+ QMediaPlayer &player = m_fixture->player;
+ player.setSource(*m_localVideoFile);
+
+ player.pause();
+
+ QTest::qWait(1s);
+
+ QTRY_COMPARE_EQ(player.position(), 0);
+}
+
+void tst_QMediaPlayerBackend::pause_playback_resumesFromPausedPosition()
+{
+ using namespace std::chrono_literals;
+
+ CHECK_SELECTED_URL(m_localVideoFile);
+
+ QMediaPlayer &player = m_fixture->player;
+ player.setSource(*m_localVideoFile);
player.play();
- QTRY_VERIFY(player.position() > 100);
+ QTRY_COMPARE_GT(player.position(), 100);
- player.setSource(localWavFile);
+ player.pause();
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::LoadedMedia);
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
- QCOMPARE(player.position(), 0);
- QCOMPARE(positionSpy.last()[0].value<qint64>(), 0);
+ qint64 pausePos = player.position();
+ QTest::qWait(1s);
- stateSpy.clear();
- statusSpy.clear();
- positionSpy.clear();
+ QCOMPARE_EQ(player.position(), pausePos);
player.play();
- QTRY_VERIFY(player.position() > 100);
+ // Make sure the media player does not make up for the lost time
+ m_fixture->positionChanged.wait();
+ m_fixture->positionChanged.wait();
- player.setSource(QUrl());
+ QCOMPARE_LT(player.position(), pausePos + 500);
+}
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::NoMedia);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::NoMedia);
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
- QCOMPARE(player.position(), 0);
- QCOMPARE(positionSpy.last()[0].value<qint64>(), 0);
- QCOMPARE(player.duration(), 0);
+void tst_QMediaPlayerBackend::play_resetsErrorState_whenCalledWithInvalidFile()
+{
+ m_fixture->player.setSource({ "Some not existing media" });
+ QTRY_COMPARE_EQ(m_fixture->player.error(), QMediaPlayer::ResourceError);
+
+ MediaPlayerState expectedState{ m_fixture->player };
+
+ m_fixture->player.play();
+
+ expectedState.error = QMediaPlayer::NoError;
+ COMPARE_MEDIA_PLAYER_STATE_EQ(MediaPlayerState{ m_fixture->player }, expectedState);
+
+ QTest::qWait(150); // wait a bit and check position is not changed
+
+ COMPARE_MEDIA_PLAYER_STATE_EQ(MediaPlayerState{ m_fixture->player }, expectedState);
+ QCOMPARE(m_fixture->surface.m_totalFrames, 0);
}
+void tst_QMediaPlayerBackend::play_resumesPlaying_whenValidMediaIsProvidedAfterInvalidMedia()
+{
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ // Arrange
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ m_fixture->player.play();
+ QTRY_VERIFY(m_fixture->framesCount > 0);
+ m_fixture->player.setSource(QUrl("Some not existing media"));
+ QTRY_COMPARE(m_fixture->player.error(), QMediaPlayer::ResourceError);
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+
+ // Act
+ m_fixture->player.play();
+
+ // Assert
+ QTRY_VERIFY(m_fixture->framesCount > 0);
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+ QCOMPARE_EQ(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+ QCOMPARE(m_fixture->player.error(), QMediaPlayer::NoError);
+}
-void tst_QMediaPlayerBackend::processEOS()
+void tst_QMediaPlayerBackend::play_doesNothing_whenMediaIsNotLoaded()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ m_fixture->player.play();
+
+ const MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ const MediaPlayerState actualState{ m_fixture->player };
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+
+ QVERIFY(m_fixture->playbackStateChanged.empty());
+ QVERIFY(m_fixture->mediaStatusChanged.empty());
+ QVERIFY(m_fixture->positionChanged.empty());
+ QVERIFY(m_fixture->errorOccurred.empty());
+}
+
+void tst_QMediaPlayerBackend::play_setsPlaybackStateAndMediaStatus_whenValidFileIsLoaded()
+{
+ CHECK_SELECTED_URL(m_localVideoFile);
+
+ m_fixture->player.setSource(*m_localVideoFile);
+ m_fixture->player.play();
+
+ QTRY_COMPARE_EQ(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+
+ QCOMPARE(m_fixture->playbackStateChanged, SignalList({ { QMediaPlayer::PlayingState } }));
+
+ auto expectedMediaStatus = SignalList{
+ { QMediaPlayer::LoadingMedia },
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::BufferingMedia },
+ { QMediaPlayer::BufferedMedia },
+ };
+
+ QTRY_COMPARE_EQ(m_fixture->mediaStatusChanged.first(4), expectedMediaStatus);
+
+ QTRY_COMPARE_GT(m_fixture->bufferProgressChanged.size(), 0);
+ QTRY_COMPARE_NE(m_fixture->bufferProgressChanged.front().front(), 0.f);
+ QTRY_COMPARE(m_fixture->bufferProgressChanged.back().front(), 1.f);
+}
+
+void tst_QMediaPlayerBackend::play_startsPlaybackAndChangesPosition_whenValidFileIsLoaded()
+{
+ CHECK_SELECTED_URL(m_localVideoFile);
+
+ m_fixture->player.setSource(*m_localVideoFile);
+ m_fixture->player.play();
+
+ QTRY_VERIFY(m_fixture->player.position() > 100);
+ QTRY_VERIFY(!m_fixture->durationChanged.empty());
+ QTRY_VERIFY(!m_fixture->positionChanged.empty());
+ QTRY_VERIFY(m_fixture->positionChanged.last()[0].value<qint64>() > 100);
+}
+
+void tst_QMediaPlayerBackend::play_doesNotEnterMediaLoadingState_whenResumingPlayingAfterStop()
+{
+ CHECK_SELECTED_URL(m_localWavFile);
+
+ // Arrange: go through a play->pause->stop sequence
+ m_fixture->player.setSource(*m_localWavFile);
+ m_fixture->player.play();
+ QTRY_VERIFY(m_fixture->player.position() > 100);
+ m_fixture->player.pause();
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::BufferedMedia);
+ m_fixture->player.stop();
+ m_fixture->clearSpies();
+
+ // Act
+ m_fixture->player.play();
+
+ // Assert
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+ QTRY_VERIFY(m_fixture->playbackStateChanged.contains({ QMediaPlayer::PlayingState }));
+
+ // Note: Should not go through Loading again when play -> stop -> play
+ if (!isGStreamerPlatform()) {
+ QCOMPARE_EQ(m_fixture->mediaStatusChanged,
+ SignalList({
+ { QMediaPlayer::BufferingMedia },
+ { QMediaPlayer::BufferedMedia },
+ }));
+ } else {
+ QTRY_COMPARE_EQ(m_fixture->mediaStatusChanged,
+ // gstreamer may see EndOfMedia
+ SignalList({
+ { QMediaPlayer::BufferingMedia },
+ { QMediaPlayer::BufferedMedia },
+ { QMediaPlayer::EndOfMedia },
+ }));
+ }
+}
+
+void tst_QMediaPlayerBackend::playAndSetSource_emitsExpectedSignalsAndStopsPlayback_whenSetSourceWasCalledWithEmptyUrl()
+{
+ CHECK_SELECTED_URL(m_localWavFile2);
+
+ // Arrange
+ m_fixture->player.setSource(*m_localWavFile2);
+ m_fixture->clearSpies();
+
+ // Act
+ m_fixture->player.play();
+ QTRY_VERIFY(m_fixture->player.position() > 100);
+ m_fixture->player.setSource(QUrl());
+
+ // Assert
+ const MediaPlayerState expectedState = MediaPlayerState::defaultState();
+ const MediaPlayerState actualState{ m_fixture->player };
+ COMPARE_MEDIA_PLAYER_STATE_EQ(actualState, expectedState);
+
+ QList allowedSignalSequences = {
+ SignalList{
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::BufferingMedia },
+ { QMediaPlayer::BufferedMedia },
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::NoMedia },
+ },
+ SignalList{
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::BufferingMedia },
+ { QMediaPlayer::BufferedMedia },
+ { QMediaPlayer::EndOfMedia }, // EndOfMedia can be reached before setSource({})
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::NoMedia },
+ },
+ };
+
+ QTRY_VERIFY(allowedSignalSequences.contains(m_fixture->mediaStatusChanged));
+
+ QTRY_COMPARE_EQ(m_fixture->playbackStateChanged,
+ SignalList({ { QMediaPlayer::PlayingState }, { QMediaPlayer::StoppedState } }));
+
+ QTRY_VERIFY(m_fixture->positionChanged.size() > 0);
+ QCOMPARE(m_fixture->positionChanged.last()[0].value<qint64>(), 0);
+}
+
+void tst_QMediaPlayerBackend::
+ play_createsFramesWithExpectedContentAndIncreasingFrameTime_whenPlayingRtspMediaStream()
+{
+#if !QT_CONFIG(process)
+ QSKIP("This test requires QProcess support");
+#else
+ if (!canCreateRtpStream())
+ QSKIP("Rtsp stream cannot be created");
+
+ QSKIP_GSTREAMER("GStreamer tests fail");
+
+ auto temporaryFile = copyResourceToTemporaryFile(":/testdata/colors.mp4", "colors.XXXXXX.mp4");
+ QVERIFY(temporaryFile);
+
+ const QString streamUrl = "rtsp://localhost:8083/stream";
+
+ auto process = createRtpStreamProcess(temporaryFile->fileName(), streamUrl);
+ QVERIFY2(process, "Cannot start rtsp process");
+
+ auto processCloser = qScopeGuard([&process]() { process->close(); });
+
+ TestVideoSink surface(false);
QMediaPlayer player;
- QAudioOutput output;
- player.setAudioOutput(&output);
- QSignalSpy stateSpy(&player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
- QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
- QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64)));
+ QSignalSpy errorSpy(&player, &QMediaPlayer::errorOccurred);
+
+ player.setVideoSink(&surface);
+ // Ignore audio output to check timings accuratelly
+ // player.setAudioOutput(&output);
- player.setSource(localWavFile);
+ player.setSource(streamUrl);
player.play();
- player.setPosition(900);
- //wait up to 5 seconds for EOS
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QTRY_COMPARE(player.playbackState(), QMediaPlayer::PlayingState);
+
+ const auto colors = { qRgb(0, 0, 0xFF), qRgb(0xFF, 0, 0), qRgb(0, 0xFE, 0) };
+ const auto colorInterval = 5000;
+
+ for (auto pos : { colorInterval / 2, colorInterval + 100 }) {
+ qDebug() << "Waiting for position:" << pos;
+
+ QTRY_COMPARE_GT(player.position(), pos);
+
+ auto frame1 = surface.waitForFrame();
+ QVERIFY(frame1.isValid());
+ QCOMPARE(frame1.size(), QSize(213, 120));
+
+ QCOMPARE_GT(frame1.startTime(), pos * 1000);
+
+ auto frameTime = frame1.startTime();
+ const auto coloIndex = frameTime / (colorInterval * 1000);
+ QCOMPARE_LT(coloIndex, 2);
+
+ const auto image1 = frame1.toImage();
+ QVERIFY(!image1.isNull());
+ QCOMPARE(findSimilarColorIndex(colors, image1.pixel(1, 1)), coloIndex);
+ QCOMPARE(findSimilarColorIndex(colors, image1.pixel(100, 100)), coloIndex);
+
+ auto frame2 = surface.waitForFrame();
+ QVERIFY(frame2.isValid());
+ QCOMPARE_GT(frame2.startTime(), frame1.startTime());
+ }
+
+ player.stop();
- QVERIFY(statusSpy.count() > 0);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::EndOfMedia);
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.count(), 2);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
+ QCOMPARE(errorSpy.size(), 0);
+#endif //QT_CONFIG(process)
+}
- //at EOS the position stays at the end of file
- QCOMPARE(player.position(), player.duration());
- QTRY_VERIFY(positionSpy.count() > 0);
- QTRY_COMPARE(positionSpy.last()[0].value<qint64>(), player.duration());
+void tst_QMediaPlayerBackend::play_waitsForLastFrameEnd_whenPlayingVideoWithLongFrames()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("SKIP initTestCase on CI, because of QTBUG-126428");
+#endif
+ if (isCI() && isGStreamerPlatform())
+ QSKIP_GSTREAMER("QTBUG-124005: spurious failures with gstreamer");
- stateSpy.clear();
- statusSpy.clear();
- positionSpy.clear();
+ CHECK_SELECTED_URL(m_oneRedFrameVideo);
+
+ m_fixture->surface.setStoreFrames(true);
+
+ m_fixture->player.setSource(*m_oneRedFrameVideo);
+ m_fixture->player.play();
+
+ QTRY_COMPARE_GT(m_fixture->surface.m_totalFrames, 0);
+ QVERIFY(m_fixture->surface.m_frameList.front().isValid());
+
+ QElapsedTimer timer;
+ timer.start();
+
+ QTRY_COMPARE_GT(m_fixture->surface.m_totalFrames, 1);
+ const auto elapsed = timer.elapsed();
+
+ if (!isGStreamerPlatform()) {
+ // QTBUG-124005: GStreamer timing seems to be off
+
+ // 1000 is expected
+ QCOMPARE_GT(elapsed, 850);
+ QCOMPARE_LT(elapsed, 1400);
+ }
+
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(m_fixture->surface.m_totalFrames, 2);
+ QVERIFY(!m_fixture->surface.m_frameList.back().isValid());
+}
+
+void tst_QMediaPlayerBackend::play_startsPlayback_withAndWithoutOutputsConnected()
+{
+ QFETCH(const bool, audioConnected);
+ QFETCH(const bool, videoConnected);
+
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ if (!videoConnected && !audioConnected)
+ QSKIP_FFMPEG("FFMPEG backend playback fails when no output is connected");
+
+ // Arrange
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ if (!audioConnected)
+ m_fixture->player.setAudioOutput(nullptr);
+
+ if (!videoConnected)
+ m_fixture->player.setVideoOutput(nullptr);
+
+ m_fixture->clearSpies();
+
+ // Act
+ m_fixture->player.play();
+
+ // Assert
+ QTRY_VERIFY(!m_fixture->mediaStatusChanged.empty()
+ && m_fixture->mediaStatusChanged.back()
+ == QList<QVariant>{ QMediaPlayer::EndOfMedia });
+
+ QTRY_COMPARE_EQ(m_fixture->playbackStateChanged,
+ SignalList({
+ { QMediaPlayer::PlayingState },
+ { QMediaPlayer::StoppedState },
+ }));
+}
+
+void tst_QMediaPlayerBackend::play_startsPlayback_withAndWithoutOutputsConnected_data()
+{
+ QTest::addColumn<bool>("videoConnected");
+ QTest::addColumn<bool>("audioConnected");
+
+ QTest::addRow("all connected") << true << true;
+ QTest::addRow("video connected") << true << false;
+ QTest::addRow("audio connected") << false << true;
+ QTest::addRow("no output connected") << false << false;
+}
+
+void tst_QMediaPlayerBackend::play_playsRtpStream_whenSdpFileIsLoaded()
+{
+#if !QT_CONFIG(process)
+ QSKIP("This test requires QProcess support");
+#else
+ if (!isFFMPEGPlatform())
+ QSKIP("This test is only for FFmpeg backend");
+
+ // Create stream
+ if (!canCreateRtpStream())
+ QSKIP("Rtp stream cannot be created");
+
+ auto temporaryFile = copyResourceToTemporaryFile(":/testdata/colors.mp4", "colors.XXXXXX.mp4");
+ QVERIFY(temporaryFile);
+
+ // Pass a "file:" URL to VLC in order to generate an .sdp file
+ const QUrl sdpUrl = QUrl::fromLocalFile(QFileInfo("test.sdp").absoluteFilePath());
+
+ auto process = createRtpStreamProcess(temporaryFile->fileName(), sdpUrl.toString());
+ QVERIFY2(process, "Cannot start rtp process");
+
+ // Set reasonable protocol whitelist that includes rtp and udp
+ qputenv("QT_FFMPEG_PROTOCOL_WHITELIST", "file,crypto,data,rtp,udp");
+
+ auto processCloser = qScopeGuard([&process, &sdpUrl]() {
+ // End stream
+ process->close();
+
+ // Remove .sdp file created by VLC
+ QFile(sdpUrl.toLocalFile()).remove();
+
+ // Unset environment variable
+ qunsetenv("QT_FFMPEG_PROTOCOL_WHITELIST");
+ });
+
+ m_fixture->player.setSource(sdpUrl);
+
+ // Play
+ m_fixture->player.play();
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+#endif // QT_CONFIG(process)
+}
+
+void tst_QMediaPlayerBackend::play_succeedsFromSourceDevice()
+{
+ QFETCH(const MaybeUrl, mediaUrl);
+ QFETCH(bool, streamOutlivesPlayer);
+
+ CHECK_SELECTED_URL(mediaUrl);
+
+ auto *stream = new QFile(u":"_s + mediaUrl->path());
+
+ QVERIFY(stream->open(QFile::ReadOnly));
+
+ QMediaPlayer &player = m_fixture->player;
+
+ player.setSourceDevice(stream);
player.play();
+ QTRY_COMPARE_GT(player.position(), 100);
- //position is reset to start
- QTRY_VERIFY(player.position() < 100);
- QTRY_VERIFY(positionSpy.count() > 0);
- QCOMPARE(positionSpy.first()[0].value<qint64>(), 0);
+ if (streamOutlivesPlayer)
+ stream->setParent(&player);
+ else
+ delete stream;
+}
- QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
+void tst_QMediaPlayerBackend::play_succeedsFromSourceDevice_data()
+{
+ QTest::addColumn<MaybeUrl>("mediaUrl");
+ QTest::addColumn<bool>("streamOutlivesPlayer");
+
+ QTest::addRow("audio file") << m_localWavFile << true;
+ QTest::addRow("video file") << m_localVideoFile << true;
+
+ // QMediaPlayer crashes when we delete the stream during playback
+ constexpr bool validateStreamDestructionDuringPlayback = false;
+ if constexpr (validateStreamDestructionDuringPlayback) {
+ QTest::addRow("audio file, stream destroyed during playback") << m_localWavFile << false;
+ QTest::addRow("video file, stream destroyed during playback") << m_localVideoFile << false;
+ }
+}
+
+void tst_QMediaPlayerBackend::stop_entersStoppedState_whenPlayerWasPaused()
+{
+ QFETCH(const MaybeUrl, mediaUrl);
+
+ CHECK_SELECTED_URL(mediaUrl);
+ QMediaPlayer &player = m_fixture->player;
+
+ // Arrange
+ player.setSource(*mediaUrl);
+ player.play();
+ QTRY_COMPARE_GT(player.position(), 100);
+ player.pause();
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
+ m_fixture->clearSpies();
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PlayingState);
- QVERIFY(statusSpy.count() > 0);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::BufferedMedia);
+ if (!isGStreamerPlatform()) // Gstreamer may see EOS already
+ QCOMPARE_GT(player.position(), 100);
- positionSpy.clear();
- QTRY_VERIFY(player.position() > 100);
- QTRY_VERIFY(positionSpy.count() > 0);
- QVERIFY(positionSpy.last()[0].value<qint64>() > 100);
- player.setPosition(900);
- //wait up to 5 seconds for EOS
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
- QVERIFY(statusSpy.count() > 0);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::EndOfMedia);
+ // Act
+ player.stop();
+
+ // Assert
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.count(), 2);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
+ QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ QCOMPARE(m_fixture->playbackStateChanged, SignalList({ { QMediaPlayer::StoppedState } }));
+ // it's allowed to emit statusChanged() signal async
+ QTRY_COMPARE(m_fixture->mediaStatusChanged, SignalList({ { QMediaPlayer::LoadedMedia } }));
+
+ if (isGStreamerPlatform() && *mediaUrl == *m_localWavFile) {
+ // QTBUG-124517: for some media types gstreamer does not emit buffer progress messages
+ } else {
+ QCOMPARE(m_fixture->bufferProgressChanged, SignalList({ { 0.f } }));
+ }
+
+ QTRY_COMPARE(m_fixture->player.position(), qint64(0));
+
+ QTRY_VERIFY(!m_fixture->positionChanged.empty());
+ QCOMPARE(m_fixture->positionChanged.last()[0].value<qint64>(), qint64(0));
+ QVERIFY(player.duration() > 0);
+}
+
+void tst_QMediaPlayerBackend::stop_entersStoppedState_whenPlayerWasPaused_data()
+{
+ QTest::addColumn<MaybeUrl>("mediaUrl");
+
+ QTest::addRow("audio file") << m_localWavFile;
+ QTest::addRow("video file") << m_localVideoFile;
+}
+
+void tst_QMediaPlayerBackend::stop_setsPositionToZero_afterPlayingToEndOfMedia()
+{
+ // Arrange
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ m_fixture->player.play();
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+
+ // Act
+ m_fixture->player.stop();
+
+ // Assert
+ QCOMPARE(m_fixture->player.position(), qint64(0));
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+
+ m_fixture->player.play();
+
+ if (isGStreamerPlatform())
+ QSKIP_GSTREAMER("QTBUG-124005: spurious failures with gstreamer");
+
+ QVERIFY(m_fixture->surface.waitForFrame().isValid());
+}
+
+
+void tst_QMediaPlayerBackend::playbackRate_returnsOne_byDefault()
+{
+ QCOMPARE_EQ(m_fixture->player.playbackRate(), static_cast<qreal>(1.0f));
+}
+
+void tst_QMediaPlayerBackend::setPlaybackRate_changesPlaybackRateAndEmitsSignal_data()
+{
+ QTest::addColumn<float>("initialPlaybackRate");
+ QTest::addColumn<float>("targetPlaybackRate");
+ QTest::addColumn<float>("expectedPlaybackRate");
+ QTest::addColumn<bool>("signalExpected");
+
+ QTest::addRow("Increase") << 1.0f << 2.0f << 2.0f << true;
+ QTest::addRow("Decrease") << 1.0f << 0.5f << 0.5f << true;
+ QTest::addRow("Keep") << 0.5f << 0.5f << 0.5f << false;
+
+ bool backendSupportsNegativePlayback =
+ isWindowsPlatform() || isDarwinPlatform() || isGStreamerPlatform();
+
+ if (backendSupportsNegativePlayback) {
+ QTest::addRow("DecreaseBelowZero") << 0.5f << -0.5f << -0.5f << true;
+ QTest::addRow("KeepDecreasingBelowZero") << -0.5f << -0.6f << -0.6f << true;
+ } else {
+ QTest::addRow("DecreaseBelowZero") << 0.5f << -0.5f << 0.0f << true;
+ QTest::addRow("KeepDecreasingBelowZero") << -0.5f << -0.6f << 0.0f << false;
+ }
+}
+
+void tst_QMediaPlayerBackend::setPlaybackRate_changesPlaybackRateAndEmitsSignal()
+{
+ QFETCH(const float, initialPlaybackRate);
+ QFETCH(const float, targetPlaybackRate);
+ QFETCH(const float, expectedPlaybackRate);
+ QFETCH(const bool, signalExpected);
+
+ // Arrange
+ m_fixture->player.setPlaybackRate(initialPlaybackRate);
+ m_fixture->clearSpies();
+
+ // Act
+ m_fixture->player.setPlaybackRate(targetPlaybackRate);
+
+ // Assert
+ if (signalExpected)
+ QCOMPARE_EQ(m_fixture->playbackRateChanged, SignalList({ { expectedPlaybackRate } }));
+ else
+ QVERIFY(m_fixture->playbackRateChanged.empty());
+
+ QCOMPARE_EQ(m_fixture->player.playbackRate(), expectedPlaybackRate);
+}
+
+void tst_QMediaPlayerBackend::setPlaybackRate_changesPlaybackDuration()
+{
+ using namespace std::chrono;
+ using namespace std::chrono_literals;
+
+ CHECK_SELECTED_URL(m_15sVideo);
+
+ // speeding up a 15s file by 3 should result in a duration of 5s
+ // auto minDuration = 3s;
+ // auto maxDuration = 7s;
+ // auto playbackRate = 3.0;
+
+ // speeding up a 15s file by 5 should result in a duration of 3s
+ auto minDuration = 2s;
+ auto maxDuration = 4s;
+ auto playbackRate = 5.0;
+
+ QFETCH(const QLatin1String, testMode);
+
+ QMediaPlayer &player = m_fixture->player;
+
+ if (testMode == "SetRateBeforeSetSource"_L1)
+ player.setPlaybackRate(playbackRate);
+
+ player.setSource(*m_15sVideo);
+
+ QTRY_COMPARE_EQ(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ auto begin = steady_clock::now();
+
+ if (testMode == "SetRateBeforePlay"_L1) {
+ QSKIP_GSTREAMER("FIXME: SetRateBeforeSetSource is currently broken");
+ player.setPlaybackRate(playbackRate);
+ }
+
+ player.play();
+
+ if (testMode == "SetRateAfterPlay"_L1)
+ player.setPlaybackRate(playbackRate);
+
+ if (testMode == "SetRateAfterPlaybackStarted"_L1) {
+ QTRY_COMPARE_GT(player.position(), 50);
+ player.setPlaybackRate(playbackRate);
+ }
+
+ QCOMPARE(player.playbackRate(), playbackRate);
+
+ QTRY_COMPARE_EQ_WITH_TIMEOUT(player.playbackState(), QMediaPlayer::StoppedState, 20s);
+
+ auto end = steady_clock::now();
+ auto duration = end - begin;
+
+ if (false)
+ qDebug() << round<milliseconds>(duration);
+
+ QCOMPARE_LT(duration, maxDuration);
+ QCOMPARE_GT(duration, minDuration);
+}
- //position stays at the end of file
- QCOMPARE(player.position(), player.duration());
- QTRY_VERIFY(positionSpy.count() > 0);
- QTRY_COMPARE(positionSpy.last()[0].value<qint64>(), player.duration());
+void tst_QMediaPlayerBackend::setPlaybackRate_changesPlaybackDuration_data()
+{
+ QTest::addColumn<QLatin1String>("testMode");
+
+ QTest::addRow("SetRateBeforeSetSource") << "SetRateBeforeSetSource"_L1;
+ QTest::addRow("SetRateBeforePlay") << "SetRateBeforePlay"_L1;
+ QTest::addRow("SetRateAfterPlay") << "SetRateAfterPlay"_L1;
+ QTest::addRow("SetRateAfterPlaybackStarted") << "SetRateAfterPlaybackStarted"_L1;
+}
+
+void tst_QMediaPlayerBackend::setVolume_changesVolume_whenVolumeIsInRange()
+{
+ m_fixture->output.setVolume(0.0f);
+ QCOMPARE_EQ(m_fixture->output.volume(), 0.0f);
+ QCOMPARE(m_fixture->volumeChanged, SignalList({ { 0.0f } }));
+
+ m_fixture->output.setVolume(0.5f);
+ QCOMPARE_EQ(m_fixture->output.volume(), 0.5f);
+ QCOMPARE(m_fixture->volumeChanged, SignalList({ { 0.0f }, { 0.5f } }));
+
+ m_fixture->output.setVolume(1.0f);
+ QCOMPARE_EQ(m_fixture->output.volume(), 1.0f);
+ QCOMPARE(m_fixture->volumeChanged, SignalList({ { 0.0f }, { 0.5f }, { 1.0f } }));
+}
+
+void tst_QMediaPlayerBackend::setVolume_clampsToRange_whenVolumeIsOutsideRange()
+{
+ m_fixture->output.setVolume(-0.1f);
+ QCOMPARE_EQ(m_fixture->output.volume(), 0.0f);
+ QCOMPARE(m_fixture->volumeChanged, SignalList({ { 0.0f } }));
+
+ m_fixture->output.setVolume(1.1f);
+ QCOMPARE_EQ(m_fixture->output.volume(), 1.0f);
+ QCOMPARE(m_fixture->volumeChanged, SignalList({ { 0.0f }, { 1.0f } }));
+}
+
+void tst_QMediaPlayerBackend::setVolume_doesNotChangeMutedState()
+{
+ m_fixture->output.setMuted(true);
+ m_fixture->output.setVolume(0.5f);
+ QVERIFY(m_fixture->output.isMuted());
+
+ m_fixture->output.setMuted(false);
+ m_fixture->output.setVolume(0.0f);
+ QVERIFY(!m_fixture->output.isMuted());
+}
+
+void tst_QMediaPlayerBackend::setMuted_changesMutedState_whenMutedStateChanged()
+{
+ m_fixture->output.setMuted(true);
+ QVERIFY(m_fixture->output.isMuted());
+ QCOMPARE(m_fixture->mutedChanged, SignalList({ { true } }));
+
+ // No new events emitted when muted state did not change
+ m_fixture->output.setMuted(true);
+ QCOMPARE(m_fixture->mutedChanged, SignalList({ { true } }));
+
+ m_fixture->output.setMuted(false);
+ QVERIFY(!m_fixture->output.isMuted());
+ QCOMPARE(m_fixture->mutedChanged, SignalList({ { true }, { false } }));
+
+ // No new events emitted when muted state did not change
+ m_fixture->output.setMuted(false);
+ QCOMPARE(m_fixture->mutedChanged, SignalList({ { true }, { false } }));
+}
+
+void tst_QMediaPlayerBackend::setMuted_doesNotChangeVolume()
+{
+ m_fixture->output.setVolume(0.5f);
+
+ m_fixture->output.setMuted(true);
+ QCOMPARE_EQ(m_fixture->output.volume(), 0.5f);
+
+ m_fixture->output.setMuted(false);
+ QCOMPARE_EQ(m_fixture->output.volume(), 0.5f);
+}
+
+void tst_QMediaPlayerBackend::processEOS()
+{
+ QSKIP_GSTREAMER("QTBUG-124005: spurious failure with gstreamer");
+
+ if (!isGStreamerPlatform()) {
+ // QTBUG-124517: for some media types, including wav files, gstreamer does not emit buffer
+ // progress messages
+ CHECK_SELECTED_URL(m_localWavFile);
+ m_fixture->player.setSource(*m_localWavFile);
+ } else {
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ }
+
+ m_fixture->player.play();
+ m_fixture->player.setPosition(900);
+
+ //wait up to 5 seconds for EOS
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+
+ QVERIFY(m_fixture->mediaStatusChanged.size() > 0);
+ QCOMPARE(m_fixture->mediaStatusChanged.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 2);
+ QCOMPARE(m_fixture->playbackStateChanged.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
+
+ //at EOS the position stays at the end of file
+ QCOMPARE(m_fixture->player.position(), m_fixture->player.duration());
+ QTRY_VERIFY(m_fixture->positionChanged.size() > 0);
+ QTRY_COMPARE(m_fixture->positionChanged.last()[0].value<qint64>(), m_fixture->player.duration());
+
+ m_fixture->playbackStateChanged.clear();
+ m_fixture->mediaStatusChanged.clear();
+ m_fixture->positionChanged.clear();
+
+ m_fixture->player.play();
+
+ //position is reset to start
+ QTRY_COMPARE_LT(m_fixture->player.position(), 500);
+ QTRY_VERIFY(m_fixture->positionChanged.size() > 0);
+ QCOMPARE(m_fixture->positionChanged.first()[0].value<qint64>(), 0);
+
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 1);
+ QCOMPARE(m_fixture->playbackStateChanged.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PlayingState);
+ QVERIFY(m_fixture->mediaStatusChanged.size() > 0);
+ QCOMPARE(m_fixture->mediaStatusChanged.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::BufferedMedia);
+
+ m_fixture->positionChanged.clear();
+ QTRY_VERIFY(m_fixture->player.position() > 100);
+ QTRY_VERIFY(m_fixture->positionChanged.size() > 0 && m_fixture->positionChanged.last()[0].value<qint64>() > 100);
+ m_fixture->player.setPosition(900);
+ //wait up to 5 seconds for EOS
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QVERIFY(m_fixture->mediaStatusChanged.size() > 0);
+ QCOMPARE(m_fixture->mediaStatusChanged.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 2);
+ QCOMPARE(m_fixture->playbackStateChanged.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
+
+ QCOMPARE_GT(m_fixture->bufferProgressChanged.size(), 1);
+ QCOMPARE(m_fixture->bufferProgressChanged.back().front(), 0.f);
+
+ // position stays at the end of file
+ QCOMPARE(m_fixture->player.position(), m_fixture->player.duration());
+ QTRY_VERIFY(m_fixture->positionChanged.size() > 0);
+ QTRY_COMPARE(m_fixture->positionChanged.last()[0].value<qint64>(), m_fixture->player.duration());
//after setPosition EndOfMedia status should be reset to Loaded
- stateSpy.clear();
- statusSpy.clear();
- player.setPosition(500);
+ m_fixture->playbackStateChanged.clear();
+ m_fixture->mediaStatusChanged.clear();
+ m_fixture->player.setPosition(500);
//this transition can be async, so allow backend to perform it
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
- QCOMPARE(stateSpy.count(), 0);
- QTRY_VERIFY(statusSpy.count() > 0 &&
- statusSpy.last()[0].value<QMediaPlayer::MediaStatus>() == QMediaPlayer::LoadedMedia);
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 0);
+ QTRY_VERIFY(m_fixture->mediaStatusChanged.size() > 0 &&
+ m_fixture->mediaStatusChanged.last()[0].value<QMediaPlayer::MediaStatus>() == QMediaPlayer::LoadedMedia);
- player.play();
- player.setPosition(900);
+ m_fixture->player.play();
+ m_fixture->player.setPosition(900);
//wait up to 5 seconds for EOS
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
- QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(player.position(), player.duration());
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(m_fixture->player.position(), m_fixture->player.duration());
- stateSpy.clear();
- statusSpy.clear();
- positionSpy.clear();
+ m_fixture->playbackStateChanged.clear();
+ m_fixture->mediaStatusChanged.clear();
+ m_fixture->positionChanged.clear();
// pause() should reset position to beginning and status to Buffered
- player.pause();
+ m_fixture->player.pause();
- QTRY_COMPARE(player.position(), 0);
- QTRY_VERIFY(positionSpy.count() > 0);
- QTRY_COMPARE(positionSpy.first()[0].value<qint64>(), 0);
+ QTRY_COMPARE(m_fixture->player.position(), 0);
+ QTRY_VERIFY(m_fixture->positionChanged.size() > 0);
+ QTRY_COMPARE(m_fixture->positionChanged.first()[0].value<qint64>(), 0);
- QCOMPARE(player.playbackState(), QMediaPlayer::PausedState);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::PausedState);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::BufferedMedia);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PausedState);
- QVERIFY(statusSpy.count() > 0);
- QCOMPARE(statusSpy.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::BufferedMedia);
+ QCOMPARE(m_fixture->playbackStateChanged.size(), 1);
+ QCOMPARE(m_fixture->playbackStateChanged.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PausedState);
+ QVERIFY(m_fixture->mediaStatusChanged.size() > 0);
+ QCOMPARE(m_fixture->mediaStatusChanged.last()[0].value<QMediaPlayer::MediaStatus>(), QMediaPlayer::BufferedMedia);
}
// Helper class for tst_QMediaPlayerBackend::deleteLaterAtEOS()
@@ -603,7 +2087,7 @@ private slots:
void onMediaStatusChanged(QMediaPlayer::MediaStatus status)
{
if (status == QMediaPlayer::EndOfMedia) {
- player-> deleteLater();
+ player->deleteLater();
player = nullptr;
}
}
@@ -616,78 +2100,28 @@ private:
// QTBUG-24927 - deleteLater() called to QMediaPlayer from its signal handler does not work as expected
void tst_QMediaPlayerBackend::deleteLaterAtEOS()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ CHECK_SELECTED_URL(m_localWavFile);
QPointer<QMediaPlayer> player(new QMediaPlayer);
QAudioOutput output;
player->setAudioOutput(&output);
player->setPosition(800); // don't wait as long for EOS
DeleteLaterAtEos deleter(player);
- player->setSource(localWavFile);
+ player->setSource(*m_localWavFile);
// Create an event loop for verifying deleteLater behavior instead of using
// QTRY_VERIFY or QTest::qWait. QTest::qWait makes extra effort to process
// DeferredDelete events during the wait, which interferes with this test.
QEventLoop loop;
- QTimer::singleShot(0, &deleter, SLOT(play()));
- QTimer::singleShot(5000, &loop, SLOT(quit()));
- connect(player.data(), SIGNAL(destroyed()), &loop, SLOT(quit()));
+ QTimer::singleShot(0, &deleter, &DeleteLaterAtEos::play);
+ QTimer::singleShot(5000, &loop, &QEventLoop::quit);
+ connect(player.data(), &QObject::destroyed, &loop, &QEventLoop::quit);
loop.exec();
// Verify that the player was destroyed within the event loop.
// This check will fail without the fix for QTBUG-24927.
QVERIFY(player.isNull());
}
-void tst_QMediaPlayerBackend::volumeAndMuted()
-{
- //volume and muted properties should be independent
- QMediaPlayer player;
- QAudioOutput output;
- player.setAudioOutput(&output);
- QCOMPARE(output.volume(), 1.);
- QVERIFY(!output.isMuted());
-
- player.setSource(localWavFile);
- player.pause();
-
- QCOMPARE(output.volume(), 1.);
- QVERIFY(!output.isMuted());
-
- QSignalSpy volumeSpy(&output, SIGNAL(volumeChanged(float)));
- QSignalSpy mutedSpy(&output, SIGNAL(mutedChanged(bool)));
-
- //setting volume to 0 should not trigger muted
- output.setVolume(0);
- QTRY_COMPARE(output.volume(), 0);
- QVERIFY(!output.isMuted());
- QCOMPARE(volumeSpy.count(), 1);
- QCOMPARE(volumeSpy.last()[0].toFloat(), output.volume());
- QCOMPARE(mutedSpy.count(), 0);
-
- output.setVolume(0.5);
- QTRY_COMPARE(output.volume(), 0.5);
- QVERIFY(!output.isMuted());
- QCOMPARE(volumeSpy.count(), 2);
- QCOMPARE(volumeSpy.last()[0].toFloat(), output.volume());
- QCOMPARE(mutedSpy.count(), 0);
-
- output.setMuted(true);
- QTRY_VERIFY(output.isMuted());
- QVERIFY(output.volume() > 0);
- QCOMPARE(volumeSpy.count(), 2);
- QCOMPARE(mutedSpy.count(), 1);
- QCOMPARE(mutedSpy.last()[0].toBool(), output.isMuted());
-
- output.setMuted(false);
- QTRY_VERIFY(!output.isMuted());
- QVERIFY(output.volume() > 0);
- QCOMPARE(volumeSpy.count(), 2);
- QCOMPARE(mutedSpy.count(), 2);
- QCOMPARE(mutedSpy.last()[0].toBool(), output.isMuted());
-
-}
-
void tst_QMediaPlayerBackend::volumeAcrossFiles_data()
{
QTest::addColumn<int>("volume");
@@ -703,12 +2137,15 @@ void tst_QMediaPlayerBackend::volumeAcrossFiles_data()
void tst_QMediaPlayerBackend::volumeAcrossFiles()
{
+ CHECK_SELECTED_URL(m_localWavFile);
+
QFETCH(int, volume);
QFETCH(bool, muted);
float vol = volume/100.;
- QMediaPlayer player;
QAudioOutput output;
+ QMediaPlayer player;
+
player.setAudioOutput(&output);
//volume and muted should not be preserved between player instances
@@ -721,7 +2158,7 @@ void tst_QMediaPlayerBackend::volumeAcrossFiles()
QTRY_COMPARE(output.volume(), vol);
QTRY_COMPARE(output.isMuted(), muted);
- player.setSource(localWavFile);
+ player.setSource(*m_localWavFile);
QCOMPARE(output.volume(), vol);
QCOMPARE(output.isMuted(), muted);
@@ -737,7 +2174,7 @@ void tst_QMediaPlayerBackend::volumeAcrossFiles()
QTRY_COMPARE(output.volume(), vol);
QCOMPARE(output.isMuted(), muted);
- player.setSource(localWavFile);
+ player.setSource(*m_localWavFile);
player.pause();
QTRY_COMPARE(output.volume(), vol);
@@ -746,15 +2183,14 @@ void tst_QMediaPlayerBackend::volumeAcrossFiles()
void tst_QMediaPlayerBackend::initialVolume()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ CHECK_SELECTED_URL(m_localWavFile);
{
- QMediaPlayer player;
QAudioOutput output;
+ QMediaPlayer player;
player.setAudioOutput(&output);
output.setVolume(1);
- player.setSource(localWavFile);
+ player.setSource(*m_localWavFile);
QCOMPARE(output.volume(), 1);
player.play();
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
@@ -762,10 +2198,10 @@ void tst_QMediaPlayerBackend::initialVolume()
}
{
- QMediaPlayer player;
QAudioOutput output;
+ QMediaPlayer player;
player.setAudioOutput(&output);
- player.setSource(localWavFile);
+ player.setSource(*m_localWavFile);
QCOMPARE(output.volume(), 1);
player.play();
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
@@ -775,22 +2211,25 @@ void tst_QMediaPlayerBackend::initialVolume()
void tst_QMediaPlayerBackend::seekPauseSeek()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+#ifdef Q_OS_ANDROID
+ QSKIP("frame.toImage will return null image because of QTBUG-108446");
+#endif
+ CHECK_SELECTED_URL(m_localVideoFile);
- QMediaPlayer player;
+ TestVideoSink surface(true);
QAudioOutput output;
+ QMediaPlayer player;
+
player.setAudioOutput(&output);
- QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64)));
+ QSignalSpy positionSpy(&player, &QMediaPlayer::positionChanged);
- TestVideoSink *surface = new TestVideoSink;
- player.setVideoOutput(surface);
+ player.setVideoOutput(&surface);
- player.setSource(localVideoFile);
+ player.setSource(*m_localVideoFile);
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
- QVERIFY(surface->m_frameList.isEmpty()); // frame must not appear until we call pause() or play()
+ QVERIFY(surface.m_frameList.isEmpty()); // frame must not appear until we call pause() or play()
positionSpy.clear();
qint64 position = 7000;
@@ -799,21 +2238,22 @@ void tst_QMediaPlayerBackend::seekPauseSeek()
QTRY_COMPARE(player.position(), position);
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
QTest::qWait(250); // wait a bit to ensure the frame is not rendered
- QVERIFY(surface->m_frameList.isEmpty()); // still no frame, we must call pause() or play() to see a frame
+ QVERIFY(surface.m_frameList
+ .isEmpty()); // still no frame, we must call pause() or play() to see a frame
player.pause();
QTRY_COMPARE(player.playbackState(), QMediaPlayer::PausedState); // it might take some time for the operation to be completed
- QTRY_VERIFY(!surface->m_frameList.isEmpty()); // we must see a frame at position 7000 here
+ QTRY_VERIFY(!surface.m_frameList.isEmpty()); // we must see a frame at position 7000 here
// Make sure that the frame has a timestamp before testing - not all backends provides this
- if (!surface->m_frameList.back().isValid() || surface->m_frameList.back().startTime() < 0)
+ if (!surface.m_frameList.back().isValid() || surface.m_frameList.back().startTime() < 0)
QSKIP("No timestamp");
{
- QVideoFrame frame = surface->m_frameList.back();
+ QVideoFrame frame = surface.m_frameList.back();
const qint64 elapsed = (frame.startTime() / 1000) - position; // frame.startTime() is microsecond, position is milliseconds.
QVERIFY2(qAbs(elapsed) < (qint64)500, QByteArray::number(elapsed).constData());
- QCOMPARE(frame.width(), 160);
+ QCOMPARE(frame.width(), 213);
QCOMPARE(frame.height(), 120);
// create QImage for QVideoFrame to verify RGB pixel colors
@@ -824,19 +2264,19 @@ void tst_QMediaPlayerBackend::seekPauseSeek()
QVERIFY(qBlue(image.pixel(0, 0)) < 20);
}
- surface->m_frameList.clear();
+ surface.m_frameList.clear();
positionSpy.clear();
position = 12000;
player.setPosition(position);
QTRY_VERIFY(!positionSpy.isEmpty() && qAbs(player.position() - position) < (qint64)500);
QCOMPARE(player.playbackState(), QMediaPlayer::PausedState);
- QTRY_VERIFY(!surface->m_frameList.isEmpty());
+ QTRY_VERIFY(!surface.m_frameList.isEmpty());
{
- QVideoFrame frame = surface->m_frameList.back();
+ QVideoFrame frame = surface.m_frameList.back();
const qint64 elapsed = (frame.startTime() / 1000) - position;
QVERIFY2(qAbs(elapsed) < (qint64)500, QByteArray::number(elapsed).constData());
- QCOMPARE(frame.width(), 160);
+ QCOMPARE(frame.width(), 213);
QCOMPARE(frame.height(), 120);
QImage image = frame.toImage();
@@ -849,19 +2289,19 @@ void tst_QMediaPlayerBackend::seekPauseSeek()
void tst_QMediaPlayerBackend::seekInStoppedState()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ CHECK_SELECTED_URL(m_localVideoFile);
- QMediaPlayer player;
+ TestVideoSink surface(false);
QAudioOutput output;
+ QMediaPlayer player;
+
player.setAudioOutput(&output);
- TestVideoSink surface(false);
player.setVideoOutput(&surface);
- QSignalSpy stateSpy(&player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
- QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64)));
+ QSignalSpy stateSpy(&player, &QMediaPlayer::playbackStateChanged);
+ QSignalSpy positionSpy(&player, &QMediaPlayer::positionChanged);
- player.setSource(localVideoFile);
+ player.setSource(*m_localVideoFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
QCOMPARE(player.position(), 0);
@@ -874,11 +2314,11 @@ void tst_QMediaPlayerBackend::seekInStoppedState()
player.setPosition(position);
QTRY_VERIFY(qAbs(player.position() - position) < qint64(200));
- QTRY_VERIFY(positionSpy.count() > 0);
+ QTRY_VERIFY(positionSpy.size() > 0);
QVERIFY(qAbs(positionSpy.last()[0].value<qint64>() - position) < qint64(200));
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.count(), 0);
+ QCOMPARE(stateSpy.size(), 0);
QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
@@ -888,12 +2328,11 @@ void tst_QMediaPlayerBackend::seekInStoppedState()
QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
QTRY_VERIFY(player.position() > position);
- QCOMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
QTest::qWait(100);
// Check that it never played from the beginning
QVERIFY(player.position() > position);
- for (int i = 0; i < positionSpy.count(); ++i)
+ for (int i = 0; i < positionSpy.size(); ++i)
QVERIFY(positionSpy.at(i)[0].value<qint64>() > (position - 200));
// ------
@@ -910,11 +2349,11 @@ void tst_QMediaPlayerBackend::seekInStoppedState()
player.setPosition(position);
QTRY_VERIFY(qAbs(player.position() - position) < qint64(200));
- QTRY_VERIFY(positionSpy.count() > 0);
+ QTRY_VERIFY(positionSpy.size() > 0);
QVERIFY(qAbs(positionSpy.last()[0].value<qint64>() - position) < qint64(200));
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.count(), 0);
+ QCOMPARE(stateSpy.size(), 0);
QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
@@ -923,13 +2362,12 @@ void tst_QMediaPlayerBackend::seekInStoppedState()
player.play();
QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
QVERIFY(qAbs(player.position() - position) < qint64(200));
QTest::qWait(500);
// Check that it never played from the beginning
QVERIFY(player.position() > (position - 200));
- for (int i = 0; i < positionSpy.count(); ++i)
+ for (int i = 0; i < positionSpy.size(); ++i)
QVERIFY(positionSpy.at(i)[0].value<qint64>() > (position - 200));
// ------
@@ -946,16 +2384,17 @@ void tst_QMediaPlayerBackend::seekInStoppedState()
player.setPosition(position);
QTRY_VERIFY(qAbs(player.position() - position) < qint64(200));
- QTRY_VERIFY(positionSpy.count() > 0);
+ QTRY_VERIFY(positionSpy.size() > 0);
QVERIFY(qAbs(positionSpy.last()[0].value<qint64>() - position) < qint64(200));
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(stateSpy.count(), 0);
+ QCOMPARE(stateSpy.size(), 0);
QCOMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
player.play();
QTRY_COMPARE(player.playbackState(), QMediaPlayer::PlayingState);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::BufferedMedia);
+ QTRY_VERIFY(player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || player.mediaStatus() == QMediaPlayer::EndOfMedia);
positionSpy.clear();
QTRY_VERIFY(player.position() > (position - 200));
@@ -963,19 +2402,20 @@ void tst_QMediaPlayerBackend::seekInStoppedState()
QTest::qWait(500);
// Check that it never played from the beginning
QVERIFY(player.position() > (position - 200));
- for (int i = 0; i < positionSpy.count(); ++i)
+ for (int i = 0; i < positionSpy.size(); ++i)
QVERIFY(positionSpy.at(i)[0].value<qint64>() > (position - 200));
}
void tst_QMediaPlayerBackend::subsequentPlayback()
{
- if (localCompressedSoundFile.isEmpty())
- QSKIP("Sound format is not supported");
+ QSKIP_GSTREAMER("QTBUG-124005: spurious seek failures with gstreamer");
+
+ CHECK_SELECTED_URL(m_localCompressedSoundFile);
- QMediaPlayer player;
QAudioOutput output;
+ QMediaPlayer player;
player.setAudioOutput(&output);
- player.setSource(localCompressedSoundFile);
+ player.setSource(*m_localCompressedSoundFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
QTRY_VERIFY(player.isSeekable());
player.setPosition(5000);
@@ -983,7 +2423,7 @@ void tst_QMediaPlayerBackend::subsequentPlayback()
QCOMPARE(player.error(), QMediaPlayer::NoError);
QTRY_COMPARE(player.playbackState(), QMediaPlayer::PlayingState);
- QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QTRY_COMPARE_WITH_TIMEOUT(player.mediaStatus(), QMediaPlayer::EndOfMedia, 10s);
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
// Could differ by up to 1 compressed frame length
QVERIFY(qAbs(player.position() - player.duration()) < 100);
@@ -991,7 +2431,7 @@ void tst_QMediaPlayerBackend::subsequentPlayback()
player.play();
QTRY_COMPARE(player.playbackState(), QMediaPlayer::PlayingState);
- QTRY_VERIFY(player.position() > 1000);
+ QTRY_COMPARE_GT(player.position(), 1000);
player.pause();
QCOMPARE(player.playbackState(), QMediaPlayer::PausedState);
// make sure position does not "jump" closer to the end of the file
@@ -1001,26 +2441,26 @@ void tst_QMediaPlayerBackend::subsequentPlayback()
QTRY_COMPARE(player.position(), qint64(0));
player.play();
QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
- QTRY_VERIFY(player.position() > 1000);
+ QTRY_COMPARE_GT(player.position(), 1000);
player.pause();
QCOMPARE(player.playbackState(), QMediaPlayer::PausedState);
- QVERIFY(player.position() > 1000);
+ QCOMPARE_GT(player.position(), 1000);
}
void tst_QMediaPlayerBackend::multipleMediaPlayback()
{
- if (localVideoFile.isEmpty() || localVideoFile2.isEmpty())
- QSKIP("Video format is not supported");
+ CHECK_SELECTED_URL(m_localVideoFile);
+ CHECK_SELECTED_URL(m_localVideoFile2);
+ QAudioOutput output;
TestVideoSink surface(false);
QMediaPlayer player;
- QAudioOutput output;
player.setVideoOutput(&surface);
player.setAudioOutput(&output);
- player.setSource(localVideoFile);
+ player.setSource(*m_localVideoFile);
- QCOMPARE(player.source(), localVideoFile);
+ QCOMPARE(player.source(), *m_localVideoFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
player.setPosition(0);
@@ -1028,14 +2468,15 @@ void tst_QMediaPlayerBackend::multipleMediaPlayback()
QCOMPARE(player.error(), QMediaPlayer::NoError);
QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
+ QVERIFY(player.isSeekable());
QTRY_VERIFY(player.position() > 0);
- QCOMPARE(player.source(), localVideoFile);
+ QCOMPARE(player.source(), *m_localVideoFile);
player.stop();
- player.setSource(localVideoFile2);
+ player.setSource(*m_localVideoFile2);
- QCOMPARE(player.source(), localVideoFile2);
+ QCOMPARE(player.source(), *m_localVideoFile2);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
QTRY_VERIFY(player.isSeekable());
@@ -1045,95 +2486,437 @@ void tst_QMediaPlayerBackend::multipleMediaPlayback()
QCOMPARE(player.error(), QMediaPlayer::NoError);
QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
QTRY_VERIFY(player.position() > 0);
- QCOMPARE(player.source(), localVideoFile2);
+ QCOMPARE(player.source(), *m_localVideoFile2);
player.stop();
QTRY_COMPARE(player.playbackState(), QMediaPlayer::StoppedState);
}
-void tst_QMediaPlayerBackend::surfaceTest()
+void tst_QMediaPlayerBackend::multiplePlaybackRateChangingStressTest()
{
- // 25 fps video file
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ if (isCI()) {
+ if (isDarwinPlatform())
+ QSKIP("SKIP on macOS CI since multiple fake drawing on macOS CI platform causes UB. To "
+ "be investigated.");
+
+ if (isGStreamerPlatform())
+ QSKIP_GSTREAMER("QTBUG-124005: spurious failures with gstreamer");
+ }
TestVideoSink surface(false);
- QMediaPlayer player;
QAudioOutput output;
+ QMediaPlayer player;
+
player.setAudioOutput(&output);
player.setVideoOutput(&surface);
- player.setSource(localVideoFile);
+
+ player.setSource(*m_localVideoFile3ColorsWithSound);
+
player.play();
- QTRY_VERIFY(player.position() >= 1000);
- QVERIFY2(surface.m_totalFrames >= 25, qPrintable(QString("Expected >= 25, got %1").arg(surface.m_totalFrames)));
+
+ surface.waitForFrame();
+
+ QSignalSpy spy(&player, &QMediaPlayer::playbackStateChanged);
+
+ using namespace std::chrono_literals;
+ using namespace std::chrono;
+
+ constexpr milliseconds expectedVideoDuration = 3000ms;
+ constexpr milliseconds waitingInterval = 200ms;
+ constexpr milliseconds maxDuration = expectedVideoDuration + 2000ms;
+ constexpr milliseconds minDuration = expectedVideoDuration - 100ms;
+ constexpr milliseconds maxFrameDelay = 2000ms;
+
+ surface.m_elapsedTimer.start();
+
+ nanoseconds duration = 0ns;
+
+ auto waitForPlaybackStateChange = [&]() {
+ QElapsedTimer timer;
+ timer.start();
+
+ QScopeGuard addDuration([&]() {
+ duration += duration_cast<nanoseconds>(timer.durationElapsed() * player.playbackRate());
+ });
+ return spy.wait(waitingInterval);
+ };
+
+ for (int i = 0; !waitForPlaybackStateChange(); ++i) {
+ player.setPlaybackRate(0.5 * (i % 4 + 1));
+
+ QCOMPARE_LE(duration, maxDuration);
+
+ QVERIFY2(surface.m_elapsedTimer.durationElapsed() < maxFrameDelay,
+ "If the delay is more than 2s, we consider the video playing is hanging.");
+
+ /* Some debug code for windows. Use the code instead of the check above to debug the bug.
+ * https://bugreports.qt.io/browse/QTBUG-105940.
+ * TODO: fix hanging on windows and remove.
+ if ( surface.m_elapsedTimer.elapsed() > maxFrameDelay ) {
+ qDebug() << "pause/play";
+ player.pause();
+ player.play();
+ surface.m_elapsedTimer.restart();
+ spy.clear();
+ }*/
+ }
+
+ QCOMPARE_GT(duration, minDuration);
+
+ QCOMPARE(spy.size(), 1);
+ QCOMPARE(spy.at(0).size(), 1);
+ QCOMPARE(spy.at(0).at(0).value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
+
+ QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
}
-#if 0
-void tst_QMediaPlayerBackend::multipleSurfaces()
+void tst_QMediaPlayerBackend::multipleSeekStressTest()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ QSKIP_GSTREAMER("QTBUG-124005: spurious test failures with gstreamer");
- QVideoSink surface1;
- QVideoSink surface2;
+#ifdef Q_OS_ANDROID
+ QSKIP("frame.toImage will return null image because of QTBUG-108446");
+#endif
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+ TestVideoSink surface(false);
+ QAudioOutput output;
QMediaPlayer player;
- player.setVideoOutput(QList<QVideoSink *>() << &surface1 << &surface2);
- player.setSource(localVideoFile);
+
+ player.setAudioOutput(&output);
+ player.setVideoOutput(&surface);
+
+ player.setSource(*m_localVideoFile3ColorsWithSound);
+
player.play();
- QTRY_VERIFY(player.position() >= 1000);
-// QVERIFY2(surface1.m_totalFrames >= 25, qPrintable(QString("Expected >= 25, got %1").arg(surface1.m_totalFrames)));
-// QVERIFY2(surface2.m_totalFrames >= 25, qPrintable(QString("Expected >= 25, got %1").arg(surface2.m_totalFrames)));
-// QCOMPARE(surface1.m_totalFrames, surface2.m_totalFrames);
+
+ auto waitAndCheckFrame = [&](qint64 pos, QString checkInfo) {
+ auto errorPrintingGuard = qScopeGuard([&]() {
+ qDebug() << "Error:" << checkInfo;
+ qDebug() << "Position:" << pos;
+ });
+
+ auto frame = surface.waitForFrame();
+ QVERIFY(frame.isValid());
+
+ const auto trackTime = pos * 1000;
+
+ // in theory, previous frame might be received, in this case we wait for a new one that is
+ // expected to be relevant
+ if (frame.endTime() < trackTime || frame.startTime() > trackTime) {
+ frame = surface.waitForFrame();
+ QVERIFY(frame.isValid());
+ }
+
+ QCOMPARE_GE(frame.startTime(), trackTime - 200'000);
+ QCOMPARE_LE(frame.endTime(), trackTime + 200'000);
+
+ auto frameImage = frame.toImage();
+ const auto actualColor = frameImage.pixel(1, 1);
+
+ const auto actualColorIndex = findSimilarColorIndex(m_video3Colors, actualColor);
+
+ const auto expectedColorIndex = pos / 1000;
+
+ QCOMPARE(actualColorIndex, expectedColorIndex);
+
+ errorPrintingGuard.dismiss();
+ };
+
+ auto seekAndCheck = [&](qint64 pos) {
+ QSignalSpy positionSpy(&player, &QMediaPlayer::positionChanged);
+ player.setPosition(pos);
+
+ QTRY_VERIFY(positionSpy.size() >= 1);
+ int setPosition = positionSpy.first().first().toInt();
+ QCOMPARE_GT(setPosition, pos - 100);
+ QCOMPARE_LT(setPosition, pos + 100);
+ };
+
+ constexpr qint64 posInterval = 10;
+
+ {
+ for (qint64 pos = posInterval; pos <= 2200; pos += posInterval)
+ seekAndCheck(pos);
+
+ waitAndCheckFrame(2200, "emulate fast moving of a seek slider forward");
+
+ QCOMPARE_NE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
+ }
+
+ {
+ for (qint64 pos = 2100; pos >= 800; pos -= posInterval)
+ seekAndCheck(pos);
+
+ waitAndCheckFrame(800, "emulate fast moving of a seek slider backward");
+
+ QCOMPARE_NE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(player.playbackState(), QMediaPlayer::PlayingState);
+ }
+
+ {
+ player.pause();
+
+ for (qint64 pos = 500; pos <= 1100; pos += posInterval)
+ seekAndCheck(pos);
+
+ waitAndCheckFrame(1100, "emulate fast moving of a seek slider forward on paused state");
+
+ QCOMPARE_NE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ QCOMPARE(player.playbackState(), QMediaPlayer::PausedState);
+ }
+}
+
+void tst_QMediaPlayerBackend::setPlaybackRate_changesActualRateAndFramesRenderingTime_data()
+{
+ QTest::addColumn<bool>("withAudio");
+ QTest::addColumn<int>("positionDeviationMs");
+
+ QTest::newRow("Without audio") << false << 170;
+
+ // set greater positionDeviationMs for case with audio due to possible synchronization.
+ QTest::newRow("With audio") << true << 200;
}
+
+void tst_QMediaPlayerBackend::setPlaybackRate_changesActualRateAndFramesRenderingTime()
+{
+ QSKIP_GSTREAMER("QTBUG-124005: timing issues");
+
+ QFETCH(bool, withAudio);
+ QFETCH(int, positionDeviationMs);
+
+#ifdef Q_OS_ANDROID
+ QSKIP("frame.toImage will return null image because of QTBUG-108446");
#endif
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
-void tst_QMediaPlayerBackend::metadata()
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("SKIP on macOS CI since multiple fake drawing on macOS CI platform causes UB. To be "
+ "investigated: QTBUG-111744");
+#endif
+ m_fixture->player.setAudioOutput(
+ withAudio ? &m_fixture->output
+ : nullptr); // TODO: mock audio output and check sound by frequency
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+
+ auto checkColorAndPosition = [&](qint64 expectedPosition, QString errorTag) {
+ constexpr qint64 intervalTime = 1000;
+
+ const int colorIndex = expectedPosition / intervalTime;
+ const auto expectedColor = m_video3Colors[colorIndex];
+ const auto actualPosition = m_fixture->player.position();
+
+ auto frame = m_fixture->surface.videoFrame();
+ auto image = frame.toImage();
+ QVERIFY(!image.isNull());
+
+ const auto actualColor = image.pixel(1, 1);
+
+ auto errorPrintingGuard = qScopeGuard([&]() {
+ qDebug() << "Error Tag:" << errorTag;
+ qDebug() << " Actual Color:" << QColor(actualColor)
+ << " Expected Color:" << QColor(expectedColor);
+ qDebug() << " Most probable actual color index:"
+ << findSimilarColorIndex(m_video3Colors, actualColor)
+ << "Expected color index:" << colorIndex;
+ qDebug() << " Actual position:" << actualPosition;
+ qDebug() << " Frame start time:" << frame.startTime();
+ });
+
+ // TODO: investigate why frames sometimes are not delivered in time on windows
+ constexpr qreal maxColorDifference = 0.18;
+ QVERIFY(m_fixture->player.isPlaying());
+ QCOMPARE_LE(colorDifference(actualColor, expectedColor), maxColorDifference);
+ QCOMPARE_GT(actualPosition, expectedPosition - positionDeviationMs);
+ QCOMPARE_LT(actualPosition, expectedPosition + positionDeviationMs);
+
+ const auto framePosition = frame.startTime() / 1000;
+
+ QCOMPARE_GT(framePosition, expectedPosition - positionDeviationMs);
+ QCOMPARE_LT(framePosition, expectedPosition + positionDeviationMs);
+ QCOMPARE_LT(qAbs(framePosition - actualPosition), positionDeviationMs);
+
+ errorPrintingGuard.dismiss();
+ };
+
+ m_fixture->player.play();
+
+ m_fixture->surface.waitForFrame();
+
+ auto waitUntil = [&](qint64 targetPosition) {
+ const auto position = m_fixture->player.position();
+
+ const auto waitingIntervalMs =
+ static_cast<int>((targetPosition - position) / m_fixture->player.playbackRate());
+
+ if (targetPosition > position)
+ QTest::qWait(waitingIntervalMs);
+
+ qDebug() << "Test waiting:" << waitingIntervalMs << "ms, Position:" << position << "=>"
+ << m_fixture->player.position() << "Expected target position:" << targetPosition
+ << "playbackRate:" << m_fixture->player.playbackRate();
+ };
+
+ waitUntil(400);
+ checkColorAndPosition(400, "Check default playback rate");
+
+ m_fixture->player.setPlaybackRate(2.);
+
+ waitUntil(1400);
+ checkColorAndPosition(1400, "Check 2.0 playback rate");
+
+ m_fixture->player.setPlaybackRate(0.5);
+
+ waitUntil(1800);
+ checkColorAndPosition(1800, "Check 0.5 playback rate");
+
+ m_fixture->player.setPlaybackRate(0.321);
+
+ m_fixture->player.stop();
+}
+
+void tst_QMediaPlayerBackend::surfaceTest()
{
- if (localFileWithMetadata.isEmpty())
- QSKIP("No supported media file");
+ QSKIP_GSTREAMER("QTBUG-124005: spurious failure, probably asynchronous event delivery");
+
+ CHECK_SELECTED_URL(m_localVideoFile);
+ // 25 fps video file
- QMediaPlayer player;
QAudioOutput output;
+ TestVideoSink surface(false);
+ QMediaPlayer player;
player.setAudioOutput(&output);
+ player.setVideoOutput(&surface);
+ player.setSource(*m_localVideoFile);
+ player.play();
+ QTRY_VERIFY(player.position() >= 1000);
+ QVERIFY2(surface.m_totalFrames >= 25, qPrintable(QStringLiteral("Expected >= 25, got %1").arg(surface.m_totalFrames)));
+}
- QSignalSpy metadataChangedSpy(&player, SIGNAL(metaDataChanged()));
+void tst_QMediaPlayerBackend::metadata()
+{
+ // QTBUG-124380: gstreamer reports CoverArtImage instead of ThumbnailImage
+ QMediaMetaData::Key thumbnailKey =
+ isGStreamerPlatform() ? QMediaMetaData::CoverArtImage : QMediaMetaData::ThumbnailImage;
- player.setSource(localFileWithMetadata);
+ CHECK_SELECTED_URL(m_localFileWithMetadata);
- QTRY_VERIFY(metadataChangedSpy.count() > 0);
+ m_fixture->player.setSource(*m_localFileWithMetadata);
- QCOMPARE(player.metaData().value(QMediaMetaData::Title).toString(), QStringLiteral("Nokia Tune"));
- QCOMPARE(player.metaData().value(QMediaMetaData::ContributingArtist).toString(), QStringLiteral("TestArtist"));
- QCOMPARE(player.metaData().value(QMediaMetaData::AlbumTitle).toString(), QStringLiteral("TestAlbum"));
+ QTRY_VERIFY(m_fixture->metadataChanged.size() > 0);
- metadataChangedSpy.clear();
+ const QMediaMetaData metadata = m_fixture->player.metaData();
+ QCOMPARE(metadata.value(QMediaMetaData::Title).toString(), QStringLiteral("Nokia Tune"));
+ QCOMPARE(metadata.value(QMediaMetaData::ContributingArtist).toString(), QStringLiteral("TestArtist"));
+ QCOMPARE(metadata.value(QMediaMetaData::AlbumTitle).toString(), QStringLiteral("TestAlbum"));
+ QCOMPARE(metadata.value(QMediaMetaData::Duration), QVariant(7704));
+ QVERIFY(!metadata.value(thumbnailKey).value<QImage>().isNull());
+ m_fixture->clearSpies();
- player.setSource(QUrl());
+ m_fixture->player.setSource(QUrl());
- QCOMPARE(metadataChangedSpy.count(), 1);
- QVERIFY(player.metaData().isEmpty());
+ QCOMPARE(m_fixture->metadataChanged.size(), 1);
+ QVERIFY(m_fixture->player.metaData().isEmpty());
+}
+
+void tst_QMediaPlayerBackend::metadata_returnsMetadataWithThumbnail_whenMediaHasThumbnail_data()
+{
+ QTest::addColumn<MaybeUrl>("mediaUrl");
+ QTest::addColumn<bool>("hasThumbnail");
+ QTest::addColumn<QSize>("expectedSize");
+ QTest::addColumn<QColor>("expectedColor");
+
+ QTest::addRow("jpeg thumbnail") << m_videoFileWithJpegThumbnail << true << QSize{ 20, 28 } << QColor(35, 177, 77);
+ QTest::addRow("png thumbnail") << m_videoFileWithPngThumbnail << true << QSize{ 20, 28 } << QColor(35, 177, 77);
+ QTest::addRow("no thumbnail") << m_localVideoFile3ColorsWithSound << false << QSize{ 0, 0 } << QColor(0, 0, 0);
+}
+
+void tst_QMediaPlayerBackend::metadata_returnsMetadataWithThumbnail_whenMediaHasThumbnail()
+{
+ // QTBUG-124380: gstreamer reports CoverArtImage instead of ThumbnailImage
+ QMediaMetaData::Key key =
+ isGStreamerPlatform() ? QMediaMetaData::CoverArtImage : QMediaMetaData::ThumbnailImage;
+
+ // Arrange
+ QFETCH(const MaybeUrl, mediaUrl);
+ QFETCH(const bool, hasThumbnail);
+ QFETCH(const QSize, expectedSize);
+ QFETCH(const QColor, expectedColor);
+
+ CHECK_SELECTED_URL(mediaUrl);
+
+ m_fixture->player.setSource(*mediaUrl);
+ QTRY_VERIFY(!m_fixture->metadataChanged.empty());
+
+ // Act
+ const QMediaMetaData metadata = m_fixture->player.metaData();
+ const QImage thumbnail = metadata.value(key).value<QImage>();
+
+ // Assert
+ QCOMPARE_EQ(!thumbnail.isNull(), hasThumbnail);
+ QCOMPARE_EQ(thumbnail.size(), expectedSize);
+
+ if (hasThumbnail) {
+ const QPoint center{ expectedSize.width() / 2, expectedSize.height() / 2 };
+ const auto centerColor = thumbnail.pixelColor(center);
+
+ constexpr int maxChannelDiff = 5;
+ QCOMPARE_LT(std::abs(centerColor.red() - expectedColor.red()), maxChannelDiff);
+ QCOMPARE_LT(std::abs(centerColor.green() - expectedColor.green()), maxChannelDiff);
+ QCOMPARE_LT(std::abs(centerColor.blue() - expectedColor.blue()), maxChannelDiff);
+ }
+}
+
+void tst_QMediaPlayerBackend::metadata_returnsMetadataWithHasHdrContent_whenMediaHasHdrContent_data()
+{
+ QTest::addColumn<MaybeUrl>("mediaUrl");
+ QTest::addColumn<bool>("hasHdrContent");
+
+ QTest::addRow("SDR Video") << m_localVideoFile << false;
+ QTest::addRow("HDR Video") << m_hdrVideo << true;
+}
+
+void tst_QMediaPlayerBackend::metadata_returnsMetadataWithHasHdrContent_whenMediaHasHdrContent()
+{
+ QFETCH(const MaybeUrl, mediaUrl);
+ QFETCH(const bool, hasHdrContent);
+
+ if (!isFFMPEGPlatform() && !isDarwinPlatform())
+ QSKIP("This test is only for FFmpeg and Darwin backends");
+
+ m_fixture->player.setSource(*mediaUrl);
+ QTRY_VERIFY(!m_fixture->metadataChanged.empty());
+
+ const QMediaMetaData metadata = m_fixture->player.videoTracks().front();
+ const bool hdrContent = metadata.value(QMediaMetaData::HasHdrContent).value<bool>();
+
+ QCOMPARE_EQ(hasHdrContent, hdrContent);
}
void tst_QMediaPlayerBackend::playerStateAtEOS()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ CHECK_SELECTED_URL(m_localWavFile);
- QMediaPlayer player;
QAudioOutput output;
+ QMediaPlayer player;
player.setAudioOutput(&output);
bool endOfMediaReceived = false;
- connect(&player, &QMediaPlayer::mediaStatusChanged, [&](QMediaPlayer::MediaStatus status) {
+ connect(&player, &QMediaPlayer::mediaStatusChanged,
+ this, [&](QMediaPlayer::MediaStatus status) {
if (status == QMediaPlayer::EndOfMedia) {
QCOMPARE(player.playbackState(), QMediaPlayer::StoppedState);
endOfMediaReceived = true;
}
});
- player.setSource(localWavFile);
+ player.setSource(*m_localWavFile);
player.play();
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
@@ -1142,74 +2925,106 @@ void tst_QMediaPlayerBackend::playerStateAtEOS()
void tst_QMediaPlayerBackend::playFromBuffer()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ QSKIP_GSTREAMER("QTBUG-124005: spurious failure, probably asynchronous event delivery");
+
+ CHECK_SELECTED_URL(m_localVideoFile);
TestVideoSink surface(false);
QMediaPlayer player;
player.setVideoOutput(&surface);
- QFile file(localVideoFile.toLocalFile());
- if (!file.open(QIODevice::ReadOnly))
- QSKIP("Could not open file");
- player.setSourceDevice(&file, localVideoFile);
+ QFile file(u":"_s + m_localVideoFile->toEncoded(QUrl::RemoveScheme));
+ QVERIFY(file.open(QIODevice::ReadOnly));
+
+ player.setSourceDevice(&file, *m_localVideoFile);
player.play();
QTRY_VERIFY(player.position() >= 1000);
- QVERIFY2(surface.m_totalFrames >= 25, qPrintable(QString("Expected >= 25, got %1").arg(surface.m_totalFrames)));
+ QVERIFY2(surface.m_totalFrames >= 25, qPrintable(QStringLiteral("Expected >= 25, got %1").arg(surface.m_totalFrames)));
}
void tst_QMediaPlayerBackend::audioVideoAvailable()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ CHECK_SELECTED_URL(m_localVideoFile);
TestVideoSink surface(false);
QAudioOutput output;
QMediaPlayer player;
- QSignalSpy hasVideoSpy(&player, SIGNAL(hasVideoChanged(bool)));
- QSignalSpy hasAudioSpy(&player, SIGNAL(hasAudioChanged(bool)));
+ QSignalSpy hasVideoSpy(&player, &QMediaPlayer::hasVideoChanged);
+ QSignalSpy hasAudioSpy(&player, &QMediaPlayer::hasAudioChanged);
player.setVideoOutput(&surface);
player.setAudioOutput(&output);
- player.setSource(localVideoFile);
+ player.setSource(*m_localVideoFile);
QTRY_VERIFY(player.hasVideo());
QTRY_VERIFY(player.hasAudio());
- QCOMPARE(hasVideoSpy.count(), 1);
- QCOMPARE(hasAudioSpy.count(), 1);
+ QCOMPARE(hasVideoSpy.size(), 1);
+ QCOMPARE(hasAudioSpy.size(), 1);
player.setSource(QUrl());
QTRY_VERIFY(!player.hasVideo());
QTRY_VERIFY(!player.hasAudio());
- QCOMPARE(hasVideoSpy.count(), 2);
- QCOMPARE(hasAudioSpy.count(), 2);
+ QCOMPARE(hasVideoSpy.size(), 2);
+ QCOMPARE(hasAudioSpy.size(), 2);
+}
+
+void tst_QMediaPlayerBackend::audioVideoAvailable_updatedOnNewMedia()
+{
+ CHECK_SELECTED_URL(m_localVideoFile);
+ CHECK_SELECTED_URL(m_localWavFile);
+
+ TestVideoSink surface(false);
+ QAudioOutput output;
+ QMediaPlayer player;
+ QSignalSpy hasVideoSpy(&player, &QMediaPlayer::hasVideoChanged);
+ QSignalSpy hasAudioSpy(&player, &QMediaPlayer::hasAudioChanged);
+ player.setVideoOutput(&surface);
+ player.setAudioOutput(&output);
+ player.setSource(*m_localVideoFile);
+ QTRY_VERIFY(player.hasVideo());
+ QTRY_VERIFY(player.hasAudio());
+ QCOMPARE(hasVideoSpy.size(), 1);
+ QCOMPARE(hasAudioSpy.size(), 1);
+
+ hasVideoSpy.clear();
+ hasAudioSpy.clear();
+
+ player.setSource(*m_localWavFile);
+
+ auto expectedHasVideoSignals = SignalList{
+ { false },
+ };
+ QTRY_COMPARE(hasVideoSpy, expectedHasVideoSignals);
+
+ if (isGStreamerPlatform()) {
+ // GStreamer unsets hasAudio/hasVideo on new URIs
+ auto expectedHasAudioSignals = SignalList{
+ { false },
+ { true },
+ };
+ QTRY_COMPARE(hasAudioSpy, expectedHasAudioSignals);
+ } else {
+ QCOMPARE(hasAudioSpy.size(), 0);
+ }
}
void tst_QMediaPlayerBackend::isSeekable()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ CHECK_SELECTED_URL(m_localVideoFile);
TestVideoSink surface(false);
QMediaPlayer player;
player.setVideoOutput(&surface);
-#ifdef Q_OS_ANDROID
- QEXPECT_FAIL("", "On Android isSeekable() is always set to true due to QTBUG-96952", Continue);
-#endif
QVERIFY(!player.isSeekable());
- player.setSource(localVideoFile);
+ player.setSource(*m_localVideoFile);
QTRY_VERIFY(player.isSeekable());
}
void tst_QMediaPlayerBackend::positionAfterSeek()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ CHECK_SELECTED_URL(m_localVideoFile);
TestVideoSink surface(false);
QMediaPlayer player;
player.setVideoOutput(&surface);
-#ifdef Q_OS_ANDROID
- QEXPECT_FAIL("", "On Android isSeekable() is always set to true due to QTBUG-96952", Continue);
-#endif
QVERIFY(!player.isSeekable());
- player.setSource(localVideoFile);
+ player.setSource(*m_localVideoFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
player.pause();
player.setPosition(500);
@@ -1224,41 +3039,59 @@ void tst_QMediaPlayerBackend::positionAfterSeek()
QTRY_VERIFY(player.position() < 700);
}
-void tst_QMediaPlayerBackend::videoDimensions()
+void tst_QMediaPlayerBackend::pause_rendersVideoAtCorrectResolution_data()
+{
+ QTest::addColumn<MaybeUrl>("mediaFile");
+ QTest::addColumn<int>("width");
+ QTest::addColumn<int>("height");
+
+ QTest::addRow("mp4") << m_videoDimensionTestFile << 540 << 320;
+ QTest::addRow("av1") << m_av1File << 160 * 143 / 80 << 160;
+}
+
+void tst_QMediaPlayerBackend::pause_rendersVideoAtCorrectResolution()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+#ifdef Q_OS_ANDROID
+ QSKIP("SKIP initTestCase on CI, because of QTBUG-126428");
+#endif
+ QFETCH(const MaybeUrl, mediaFile);
+ QFETCH(const int, width);
+ QFETCH(const int, height);
+ CHECK_SELECTED_URL(mediaFile);
+ // Arrange
TestVideoSink surface(true);
QMediaPlayer player;
player.setVideoOutput(&surface);
-#ifdef Q_OS_ANDROID
- QEXPECT_FAIL("", "On Android isSeekable() is always set to true due to QTBUG-96952", Continue);
-#endif
QVERIFY(!player.isSeekable());
- player.setSource(videoDimensionTestFile);
+ player.setSource(*mediaFile);
QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ // Act
player.pause();
+
+ if (isCI() && isFFMPEGPlatform())
+ QEXPECT_FAIL("av1", "QTBUG-119711: AV1 decoding requires HW support in the FFMPEG backend",
+ Abort);
+
QTRY_COMPARE(surface.m_totalFrames, 1);
- QCOMPARE(surface.m_frameList.last().width(), 540);
- QCOMPARE(surface.videoSize().width(), 540);
- QCOMPARE(surface.m_frameList.last().height(), 320);
- QCOMPARE(surface.videoSize().height(), 320);
+
+ // Assert
+ QCOMPARE(surface.m_frameList.last().width(), width);
+ QCOMPARE(surface.videoSize().width(), width);
+ QCOMPARE(surface.m_frameList.last().height(), height);
+ QCOMPARE(surface.videoSize().height(), height);
}
void tst_QMediaPlayerBackend::position()
{
- if (localVideoFile.isEmpty())
- QSKIP("No supported video file");
+ CHECK_SELECTED_URL(m_localVideoFile);
TestVideoSink surface(true);
QMediaPlayer player;
player.setVideoOutput(&surface);
-#ifdef Q_OS_ANDROID
- QEXPECT_FAIL("", "On Android isSeekable() is always set to true due to QTBUG-96952", Continue);
-#endif
QVERIFY(!player.isSeekable());
- player.setSource(localVideoFile);
+ player.setSource(*m_localVideoFile);
QTRY_VERIFY(player.isSeekable());
player.play();
@@ -1276,6 +3109,1141 @@ void tst_QMediaPlayerBackend::position()
QVERIFY(player.position() < 550);
}
+void tst_QMediaPlayerBackend::durationDetectionIssues_data()
+{
+ QTest::addColumn<QString>("mediaFile");
+ QTest::addColumn<qint64>("expectedDuration");
+ QTest::addColumn<int>("expectedVideoTrackCount");
+ QTest::addColumn<qint64>("expectedVideoTrackDuration");
+ QTest::addColumn<int>("expectedAudioTrackCount");
+ QTest::addColumn<QVariant>("expectedAudioTrackDuration");
+
+ // clang-format off
+
+ QTest::newRow("stream-duration-in-metadata")
+ << QString{ "qrc:/testdata/duration_issues.webm" }
+ << 400ll // Total media duration
+ << 1 // Number of video tracks in file
+ << 400ll // Video stream duration
+ << 0 // Number of audio tracks in file
+ << QVariant{}; // Audio stream duration (unused)
+
+ QTest::newRow("no-stream-duration-in-metadata")
+ << QString{ "qrc:/testdata/nokia-tune.mkv" }
+ << 7531ll // Total media duration
+ << 0 // Number of video tracks in file
+ << 0ll // Video stream duration (unused)
+ << 1 // Number of audio tracks in file
+ << QVariant{}; // Audio stream duration (not present on file)
+
+ // clang-format on
+}
+
+void tst_QMediaPlayerBackend::durationDetectionIssues()
+{
+ if (isGStreamerPlatform() && isCI())
+ QSKIP("QTBUG-124005: Fails with gstreamer on CI");
+
+ QFETCH(QString, mediaFile);
+ QFETCH(qint64, expectedDuration);
+ QFETCH(int, expectedVideoTrackCount);
+ QFETCH(qint64, expectedVideoTrackDuration);
+ QFETCH(int, expectedAudioTrackCount);
+ QFETCH(QVariant, expectedAudioTrackDuration);
+
+ // ffmpeg detects stream an incorrect stream duration, so we take
+ // the correct duration from the metadata
+
+ TestVideoSink surface(false);
+ QAudioOutput output;
+ QMediaPlayer player;
+
+ QSignalSpy durationSpy(&player, &QMediaPlayer::durationChanged);
+
+ player.setVideoOutput(&surface);
+ player.setAudioOutput(&output);
+ player.setSource(mediaFile);
+
+ QTRY_COMPARE_EQ(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ // Duration event received
+ QCOMPARE(durationSpy.size(), 1);
+ QCOMPARE(durationSpy.front().front(), expectedDuration);
+
+ // Duration property
+ QCOMPARE(player.duration(), expectedDuration);
+ QCOMPARE(player.metaData().value(QMediaMetaData::Duration), expectedDuration);
+
+ // Track duration properties
+ const auto videoTracks = player.videoTracks();
+ QCOMPARE(videoTracks.size(), expectedVideoTrackCount);
+
+ if (expectedVideoTrackCount != 0)
+ QCOMPARE(videoTracks.front().value(QMediaMetaData::Duration), expectedVideoTrackDuration);
+
+ const auto audioTracks = player.audioTracks();
+ QCOMPARE(audioTracks.size(), expectedAudioTrackCount);
+
+ if (expectedAudioTrackCount != 0)
+ QCOMPARE(audioTracks.front().value(QMediaMetaData::Duration), expectedAudioTrackDuration);
+}
+
+struct LoopIteration {
+ qint64 startPos;
+ qint64 endPos;
+ qint64 posCount;
+};
+// Creates a vector of LoopIterations, containing start- and end position
+// and the number of position changes per video loop iteration.
+static std::vector<LoopIteration> loopIterations(const QSignalSpy &positionSpy)
+{
+ std::vector<LoopIteration> result;
+ // Loops through all positions emitted by QMediaPlayer::positionChanged
+ for (auto &params : positionSpy) {
+ const auto pos = params.front().value<qint64>();
+
+ // Adds new LoopIteration struct to result if position is lower than previous position
+ if (result.empty() || pos < result.back().endPos) {
+ result.push_back(LoopIteration{pos, pos, 1});
+ }
+ // Updates end position of the current LoopIteration if position is higher than previous position
+ else {
+ result.back().posCount++;
+ result.back().endPos = pos;
+ }
+ }
+ return result;
+}
+
+void tst_QMediaPlayerBackend::finiteLoops()
+{
+ QSKIP_GSTREAMER("QTBUG-123056(?): spuriously failures of the gstreamer backend");
+
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("The test accidently gets crashed on macOS CI, not reproduced locally. To be "
+ "investigated: QTBUG-111744");
+#endif
+
+ QCOMPARE(m_fixture->player.loops(), 1);
+ m_fixture->player.setLoops(3);
+ QCOMPARE(m_fixture->player.loops(), 3);
+
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+ m_fixture->player.setPlaybackRate(5);
+ QCOMPARE(m_fixture->player.loops(), 3);
+
+ m_fixture->player.play();
+ m_fixture->surface.waitForFrame();
+
+ // check pause doesn't affect looping
+ {
+ QTest::qWait(static_cast<int>(m_fixture->player.duration() * 3
+ * 0.6 /*relative pos*/ / m_fixture->player.playbackRate()));
+ m_fixture->player.pause();
+ m_fixture->player.play();
+ }
+
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+
+ // Check for expected number of loop iterations and startPos, endPos and posCount per iteration
+ std::vector<LoopIteration> iterations = loopIterations(m_fixture->positionChanged);
+ QCOMPARE(iterations.size(), 3u);
+ QCOMPARE_GT(iterations[0].startPos, 0);
+ QCOMPARE(iterations[0].endPos, m_fixture->player.duration());
+ QCOMPARE(iterations[1].startPos, 0);
+ QCOMPARE(iterations[1].endPos, m_fixture->player.duration());
+ QCOMPARE(iterations[2].startPos, 0);
+ QCOMPARE(iterations[2].endPos, m_fixture->player.duration());
+ if (isFFMPEGPlatform()) {
+ QCOMPARE_GT(iterations[0].posCount, 10);
+ QCOMPARE_GT(iterations[1].posCount, 10);
+ QCOMPARE_GT(iterations[2].posCount, 10);
+ }
+
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+
+ // Check that loop counter is reset when playback is restarted.
+ {
+ m_fixture->positionChanged.clear();
+ m_fixture->player.play();
+ m_fixture->player.setPlaybackRate(10);
+ m_fixture->surface.waitForFrame();
+
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(loopIterations(m_fixture->positionChanged).size(), 3u);
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ }
+}
+
+void tst_QMediaPlayerBackend::infiniteLoops()
+{
+ QSKIP_GSTREAMER("QTBUG-123056(?): spuriously failures of the gstreamer backend");
+
+ CHECK_SELECTED_URL(m_localVideoFile2);
+
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("The test accidently gets crashed on macOS CI, not reproduced locally. To be "
+ "investigated: QTBUG-111744");
+#endif
+
+ m_fixture->player.setLoops(QMediaPlayer::Infinite);
+ QCOMPARE(m_fixture->player.loops(), QMediaPlayer::Infinite);
+
+ // select some small file
+ m_fixture->player.setSource(*m_localVideoFile2);
+ m_fixture->player.setPlaybackRate(20);
+
+ m_fixture->player.play();
+ m_fixture->surface.waitForFrame();
+
+ for (int i = 0; i < 2; ++i) {
+ m_fixture->positionChanged.clear();
+
+ QTest::qWait(
+ std::max(static_cast<int>(m_fixture->player.duration()
+ / m_fixture->player.playbackRate() * 4),
+ 300 /*ensure some minimum waiting time to reduce threading flakiness*/));
+ QVERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferingMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia);
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+
+ const auto iterations = loopIterations(m_fixture->positionChanged);
+ QVERIFY(!iterations.empty());
+ QCOMPARE(iterations.front().endPos, m_fixture->player.duration());
+ }
+
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+
+ m_fixture->player.stop(); // QMediaPlayer::stop stops whether or not looping is infinite
+ QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+
+ QCOMPARE(m_fixture->mediaStatusChanged,
+ SignalList({ { QMediaPlayer::LoadingMedia },
+ { QMediaPlayer::LoadedMedia },
+ { QMediaPlayer::BufferingMedia },
+ { QMediaPlayer::BufferedMedia },
+ { QMediaPlayer::LoadedMedia } }));
+}
+
+void tst_QMediaPlayerBackend::seekOnLoops()
+{
+ QSKIP_GSTREAMER("QTBUG-123056(?): spuriously failures of the gstreamer backend");
+
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("The test accidently gets crashed on macOS CI, not reproduced locally. To be "
+ "investigated: QTBUG-111744");
+#endif
+
+ m_fixture->player.setLoops(3);
+ m_fixture->player.setPlaybackRate(2);
+
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+
+ m_fixture->player.play();
+ m_fixture->surface.waitForFrame();
+
+ // seek in the 1st loop
+ m_fixture->player.setPosition(m_fixture->player.duration() * 4 / 5);
+
+ // wait for the 2nd loop and seek
+ m_fixture->surface.waitForFrame();
+ QTRY_VERIFY(m_fixture->player.position() < m_fixture->player.duration() / 2);
+ m_fixture->player.setPosition(m_fixture->player.duration() * 8 / 9);
+
+ // wait for the 3rd loop and seek
+ m_fixture->surface.waitForFrame();
+ QTRY_VERIFY(m_fixture->player.position() < m_fixture->player.duration() / 2);
+ m_fixture->player.setPosition(m_fixture->player.duration() * 4 / 5);
+
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+
+ auto iterations = loopIterations(m_fixture->positionChanged);
+
+ QCOMPARE(iterations.size(), 3u);
+ QCOMPARE_GT(iterations[0].startPos, 0);
+ QCOMPARE(iterations[0].endPos, m_fixture->player.duration());
+ QCOMPARE_GT(iterations[0].posCount, 2);
+ QCOMPARE(iterations[1].startPos, 0);
+ QCOMPARE(iterations[1].endPos, m_fixture->player.duration());
+ QCOMPARE_GT(iterations[1].posCount, 2);
+ QCOMPARE(iterations[2].startPos, 0);
+ QCOMPARE(iterations[2].endPos, m_fixture->player.duration());
+ QCOMPARE_GT(iterations[2].posCount, 2);
+
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+}
+
+void tst_QMediaPlayerBackend::changeLoopsOnTheFly()
+{
+ QSKIP_GSTREAMER("QTBUG-123056(?): spuriously failures of the gstreamer backend");
+
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("The test accidently gets crashed on macOS CI, not reproduced locally. To be "
+ "investigated: QTBUG-111744");
+#endif
+
+ m_fixture->player.setLoops(4);
+ m_fixture->player.setPlaybackRate(5);
+
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+
+ m_fixture->player.play();
+ m_fixture->surface.waitForFrame();
+
+ m_fixture->player.setPosition(m_fixture->player.duration() * 4 / 5);
+
+ // wait for the 2nd loop
+ m_fixture->surface.waitForFrame();
+ QTRY_VERIFY(m_fixture->player.position() < m_fixture->player.duration() / 2);
+ m_fixture->player.setPosition(m_fixture->player.duration() * 8 / 9);
+
+ m_fixture->player.setLoops(1);
+
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+
+ auto iterations = loopIterations(m_fixture->positionChanged);
+ QCOMPARE(iterations.size(), 2u);
+
+ QCOMPARE(iterations[1].startPos, 0);
+ QCOMPARE(iterations[1].endPos, m_fixture->player.duration());
+ QCOMPARE_GT(iterations[1].posCount, 2);
+}
+
+void tst_QMediaPlayerBackend::seekAfterLoopReset()
+{
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("The test accidently gets crashed on macOS CI, not reproduced locally. To be "
+ "investigated: QTBUG-111744");
+#endif
+
+ m_fixture->surface.setStoreFrames(false);
+
+ m_fixture->player.setLoops(QMediaPlayer::Infinite);
+ m_fixture->player.setPlaybackRate(2);
+
+ m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
+
+ m_fixture->player.play();
+ m_fixture->surface.waitForFrame();
+
+ // seek in the 1st loop
+ m_fixture->player.setPosition(m_fixture->player.duration() * 4 / 5);
+
+ // wait for the 2nd loop
+ m_fixture->surface.waitForFrame();
+ QTRY_VERIFY(m_fixture->player.position() < m_fixture->player.duration() / 2);
+
+ // reset loops and seek
+ m_fixture->player.setLoops(1);
+ m_fixture->player.setPosition(m_fixture->player.duration() * 8 / 9);
+
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::EndOfMedia);
+}
+
+void tst_QMediaPlayerBackend::changeVideoOutputNoFramesLost()
+{
+ QSKIP_GSTREAMER("QTBUG-124005: gstreamer will lose frames, possibly due to buffering");
+
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ QVideoSink sinks[4];
+ std::atomic_int framesCount[4] = {
+ 0,
+ };
+ for (int i = 0; i < 4; ++i)
+ setVideoSinkAsyncFramesCounter(sinks[i], framesCount[i]);
+
+ QMediaPlayer player;
+
+ player.setPlaybackRate(10);
+
+ player.setVideoOutput(&sinks[0]);
+ player.setSource(*m_localVideoFile3ColorsWithSound);
+ player.play();
+ QTRY_VERIFY(!player.isPlaying());
+
+ player.setPlaybackRate(4);
+ player.setVideoOutput(&sinks[1]);
+ player.play();
+
+ QTRY_COMPARE_GE(framesCount[1], framesCount[0] / 4);
+ player.setVideoOutput(&sinks[2]);
+ const int savedFrameNumber1 = framesCount[1];
+
+ QTRY_COMPARE_GE(framesCount[2], (framesCount[0] - savedFrameNumber1) / 2);
+ player.setVideoOutput(&sinks[3]);
+ const int savedFrameNumber2 = framesCount[2];
+
+ QTRY_VERIFY(!player.isPlaying());
+
+ // check if no frames sent to old sinks
+ QCOMPARE(framesCount[1], savedFrameNumber1);
+ QCOMPARE(framesCount[2], savedFrameNumber2);
+
+ // no frames lost
+ QCOMPARE(framesCount[1] + framesCount[2] + framesCount[3], framesCount[0]);
+}
+
+void tst_QMediaPlayerBackend::cleanSinkAndNoMoreFramesAfterStop()
+{
+ QSKIP_GSTREAMER(
+ "QTBUG-124005: spurious failures on gstreamer, probably due to asynchronous play()");
+
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ QVideoSink sink;
+ std::atomic_int framesCount = 0;
+ setVideoSinkAsyncFramesCounter(sink, framesCount);
+ QMediaPlayer player;
+
+ player.setPlaybackRate(10);
+ player.setVideoOutput(&sink);
+
+ player.setSource(*m_localVideoFile3ColorsWithSound);
+
+ // Run a few time to have more chances to detect race conditions
+ for (int i = 0; i < 8; ++i) {
+ player.play();
+ QTRY_VERIFY(framesCount > 0);
+ QVERIFY(sink.videoFrame().isValid());
+
+ player.stop();
+
+ if (isGStreamerPlatform())
+ // QTBUG-124005: stop() is asynchronous in gstreamer
+ QTRY_VERIFY(!sink.videoFrame().isValid());
+ else
+ QVERIFY(!sink.videoFrame().isValid());
+
+ QCOMPARE_NE(framesCount, 0);
+ framesCount = 0;
+
+ QTest::qWait(30);
+
+ if (isGStreamerPlatform())
+ continue; // QTBUG-124005: stop() is asynchronous in gstreamer
+
+ // check if nothing changed after short waiting
+ QCOMPARE(framesCount, 0);
+ }
+}
+
+void tst_QMediaPlayerBackend::lazyLoadVideo()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(QUrl("qrc:/LazyLoad.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QQuickItem *rootItem = qobject_cast<QQuickItem *>(root.get());
+ QVERIFY(rootItem);
+
+ QQuickView view;
+ rootItem->setParentItem(view.contentItem());
+ view.resize(600, 800);
+ view.show();
+
+ QQuickLoader *loader = qobject_cast<QQuickLoader *>(rootItem->findChild<QQuickItem *>("loader"));
+ QVERIFY(loader);
+ QCOMPARE(QQmlProperty::read(loader, "active").toBool(), false);
+ loader->setProperty("active", true);
+ QCOMPARE(QQmlProperty::read(loader, "active").toBool(), true);
+
+ QQuickItem *videoPlayer = qobject_cast<QQuickItem *>(loader->findChild<QQuickItem *>("videoPlayer"));
+ QVERIFY(videoPlayer);
+
+ QTRY_COMPARE_EQ(QQmlProperty::read(videoPlayer, "playbackState").value<QMediaPlayer::PlaybackState>(), QMediaPlayer::PlayingState);
+ QCOMPARE(QQmlProperty::read(videoPlayer, "error").value<QMediaPlayer::Error>(), QMediaPlayer::NoError);
+
+ QVideoSink *videoSink = QQmlProperty::read(videoPlayer, "videoSink").value<QVideoSink *>();
+ QVERIFY(videoSink);
+
+ QSignalSpy spy(videoSink, &QVideoSink::videoFrameChanged);
+ QVERIFY(spy.wait());
+
+ QVideoFrame frame = spy.at(0).at(0).value<QVideoFrame>();
+ QVERIFY(frame.isValid());
+}
+
+void tst_QMediaPlayerBackend::videoSinkSignals()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("SKIP initTestCase on CI, because of QTBUG-126428");
+#endif
+ std::atomic<int> videoFrameCounter = 0;
+ std::atomic<int> videoSizeCounter = 0;
+
+ // TODO: come up with custom frames source,
+ // create the test target tst_QVideoSinkBackend,
+ // and move the test there
+
+ CHECK_SELECTED_URL(m_localVideoFile2);
+
+ QVideoSink sink;
+ QMediaPlayer player;
+ player.setVideoSink(&sink);
+
+ player.setSource(*m_localVideoFile2);
+
+ QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::MediaStatus::LoadedMedia);
+
+ sink.platformVideoSink()->setNativeSize({}); // reset size to be able to check the size update
+
+ connect(&sink, &QVideoSink::videoFrameChanged, this, [&](const QVideoFrame &frame) {
+ QCOMPARE(sink.videoFrame(), frame);
+ QCOMPARE(sink.videoSize(), frame.size());
+ ++videoFrameCounter;
+ }, Qt::DirectConnection);
+
+ connect(&sink, &QVideoSink::videoSizeChanged, this, [&]() {
+ QCOMPARE(sink.videoSize(), sink.videoFrame().size());
+ if (sink.videoSize().isValid()) // filter end frame
+ ++videoSizeCounter;
+ }, Qt::DirectConnection);
+
+ player.play();
+
+ QTRY_COMPARE_GE(videoFrameCounter, 2);
+ QCOMPARE(videoSizeCounter, 1);
+}
+
+void tst_QMediaPlayerBackend::nonAsciiFileName()
+{
+ CHECK_SELECTED_URL(m_localWavFile);
+
+ auto temporaryFile =
+ copyResourceToTemporaryFile(":/testdata/test.wav", "äöüØøÆ中文.XXXXXX.wav");
+ QVERIFY(temporaryFile);
+
+ m_fixture->player.setSource(temporaryFile->fileName());
+ m_fixture->player.play();
+
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
+
+ QCOMPARE(m_fixture->errorOccurred.size(), 0);
+}
+
+void tst_QMediaPlayerBackend::setMedia_setsVideoSinkSize_beforePlaying()
+{
+ CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
+
+ QVideoSink sink1;
+ QVideoSink sink2;
+ QMediaPlayer player;
+
+ QSignalSpy spy1(&sink1, &QVideoSink::videoSizeChanged);
+ QSignalSpy spy2(&sink2, &QVideoSink::videoSizeChanged);
+
+ player.setVideoOutput(&sink1);
+ QCOMPARE(sink1.videoSize(), QSize());
+
+ player.setSource(*m_localVideoFile3ColorsWithSound);
+
+ QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::MediaStatus::LoadedMedia);
+
+ QCOMPARE(sink1.videoSize(), QSize(684, 384));
+
+ player.setVideoOutput(&sink2);
+ QCOMPARE(sink2.videoSize(), QSize(684, 384));
+
+ QCOMPARE(spy1.size(), 1);
+ QCOMPARE(spy2.size(), 1);
+}
+
+#if QT_CONFIG(process)
+std::unique_ptr<QProcess> tst_QMediaPlayerBackend::createRtpStreamProcess(QString fileName,
+ QString sdpUrl)
+{
+ Q_ASSERT(!m_vlcCommand.isEmpty());
+
+ auto process = std::make_unique<QProcess>();
+#if defined(Q_OS_WINDOWS)
+ fileName.replace('/', '\\');
+#endif
+
+ QStringList vlcParams = { "-vvv", fileName,
+ "--sout", QStringLiteral("#rtp{dst=localhost,sdp=%1}").arg(sdpUrl),
+ "--intf", "dummy" };
+
+ process->start(m_vlcCommand, vlcParams);
+ if (!process->waitForStarted())
+ return nullptr;
+
+ // rtp stream might be with started some delay after the vlc process starts.
+ // Ideally, we should wait for open connections, it requires some extra work + QNetwork
+ // dependency.
+ int timeout = 500;
+#ifdef Q_OS_MACOS
+ timeout = 2000;
+#endif
+ QTest::qWait(timeout);
+
+ return process;
+}
+#endif //QT_CONFIG(process)
+
+void tst_QMediaPlayerBackend::play_playsRotatedVideoOutput_whenVideoFileHasOrientationMetadata_data()
+{
+ QTest::addColumn<MaybeUrl>("fileURL");
+ QTest::addColumn<QRgb>("expectedColor");
+ QTest::addColumn<QtVideo::Rotation>("expectedRotationAngle");
+ QTest::addColumn<QSize>("videoSize");
+
+ // clang-format off
+ QTest::addRow("without rotation") << m_colorMatrixVideo
+ << QRgb(0xff0000)
+ << QtVideo::Rotation::None
+ << QSize(960, 540);
+
+ QTest::addRow("90 deg clockwise") << m_colorMatrix90degClockwiseVideo
+ << QRgb(0x0000FF)
+ << QtVideo::Rotation::Clockwise90
+ << QSize(540, 960);
+
+ QTest::addRow("180 deg clockwise") << m_colorMatrix180degClockwiseVideo
+ << QRgb(0xFFFF00)
+ << QtVideo::Rotation::Clockwise180
+ << QSize(960, 540);
+
+ QTest::addRow("270 deg clockwise") << m_colorMatrix270degClockwiseVideo
+ << QRgb(0x00FF00)
+ << QtVideo::Rotation::Clockwise270
+ << QSize(540, 960);
+ // clang-format on
+}
+
+void tst_QMediaPlayerBackend::play_playsRotatedVideoOutput_whenVideoFileHasOrientationMetadata()
+{
+ if (isGStreamerPlatform() && isCI())
+ QSKIP("QTBUG-124005: Fails with gstreamer on CI");
+
+ // This test uses 4 video files with a 2x2 color matrix consisting of
+ // red (upper left), blue (lower left), yellow (lower right) and green (upper right).
+ // The files are identical, except that three of them contain
+ // orientation (rotation) metadata specifying that they should be
+ // viewed with a 90, 180 and 270 degree clockwise rotation respectively.
+
+ // Fetch path and expected color of upper left area of each file
+ QFETCH(const MaybeUrl, fileURL);
+ QFETCH(const QRgb, expectedColor);
+ QFETCH(const QtVideo::Rotation, expectedRotationAngle);
+ QFETCH(const QSize, videoSize);
+
+ CHECK_SELECTED_URL(fileURL);
+
+ // Load video file
+ m_fixture->player.setSource(*fileURL);
+ QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
+
+ // Compare videoSize of the output video sink with the expected value before starting playing
+ QCOMPARE(m_fixture->surface.videoSize(), videoSize);
+
+ // Compare orientation metadata of QMediaPlayer with expected value
+ const auto metaData = m_fixture->player.metaData();
+ const auto playerOrientation = metaData.value(QMediaMetaData::Orientation).value<QtVideo::Rotation>();
+ QCOMPARE(playerOrientation, expectedRotationAngle);
+
+ // Compare orientation metadata of active video stream with expected value
+ const int activeVideoTrack = m_fixture->player.activeVideoTrack();
+ const auto videoTrackMetaData = m_fixture->player.videoTracks().at(activeVideoTrack);
+ const auto videoTrackOrientation = videoTrackMetaData.value(QMediaMetaData::Orientation).value<QtVideo::Rotation>();
+ QCOMPARE(videoTrackOrientation, expectedRotationAngle);
+
+ // Play video file, sample upper left area, compare with expected color
+ m_fixture->player.play();
+ QTRY_COMPARE(m_fixture->player.playbackState(), QMediaPlayer::PlayingState);
+ QVideoFrame videoFrame = m_fixture->surface.waitForFrame();
+ QVERIFY(videoFrame.isValid());
+ QCOMPARE(videoFrame.rotation(), expectedRotationAngle);
+#ifdef Q_OS_ANDROID
+ QSKIP("frame.toImage will return null image because of QTBUG-108446");
+#endif
+ QImage image = videoFrame.toImage();
+ QVERIFY(!image.isNull());
+ QRgb upperLeftColor = image.pixel(5, 5);
+ QCOMPARE_LT(colorDifference(upperLeftColor, expectedColor), 0.004);
+
+ QSKIP_GSTREAMER("QTBUG-124005: surface.videoSize() not updated with rotation");
+
+ // Compare videoSize of the output video sink with the expected value after getting a frame
+ QCOMPARE(m_fixture->surface.videoSize(), videoSize);
+}
+
+void tst_QMediaPlayerBackend::setVideoOutput_doesNotStopPlayback()
+{
+ using namespace std::chrono_literals;
+
+ CHECK_SELECTED_URL(m_15sVideo);
+
+ QFETCH(QMediaPlayer::PlaybackState, playbackState);
+
+ TestVideoSink surface(false);
+ QAudioOutput audioOut;
+
+ QMediaPlayer player;
+ player.setAudioOutput(&audioOut);
+ player.setSource(*m_15sVideo);
+
+ switch (playbackState) {
+ case QMediaPlayer::StoppedState:
+ break;
+ case QMediaPlayer::PausedState:
+ QSKIP_FFMPEG("QTBUG-126014: Test failure with the ffmpeg backend");
+ player.pause();
+ break;
+ case QMediaPlayer::PlayingState:
+ QSKIP_FFMPEG("QTBUG-126014: Test failure with the ffmpeg backend");
+ QSKIP_GSTREAMER("QTBUG-124005: Test failure with the gstreamer backend");
+ player.play();
+ break;
+ }
+
+ // set video output
+ QTest::qWait(1s);
+ player.setVideoOutput(&surface);
+
+ if (playbackState == QMediaPlayer::PlayingState) {
+ QVideoFrame frame = surface.waitForFrame();
+ QCOMPARE(frame.size(), QSize(20, 20));
+ }
+
+ // unset video output
+ QTest::qWait(1s);
+ player.setVideoOutput(nullptr);
+
+ // wait for play until end
+ if (playbackState != QMediaPlayer::PlayingState)
+ player.play();
+
+ player.setPlaybackRate(5);
+ QTRY_COMPARE(player.playbackState(), QMediaPlayer::StoppedState);
+}
+
+void tst_QMediaPlayerBackend::setVideoOutput_doesNotStopPlayback_data()
+{
+ QTest::addColumn<QMediaPlayer::PlaybackState>("playbackState");
+ QTest::newRow("StoppedState") << QMediaPlayer::StoppedState;
+ QTest::newRow("PausedState") << QMediaPlayer::PausedState;
+ QTest::newRow("PlayingState") << QMediaPlayer::PlayingState;
+}
+
+void tst_QMediaPlayerBackend::setAudioOutput_doesNotStopPlayback()
+{
+ QSKIP_FFMPEG("QTBUG-126014: Test failure with the ffmpeg backend");
+
+ using namespace std::chrono_literals;
+
+ CHECK_SELECTED_URL(m_15sVideo);
+ QFETCH(QMediaPlayer::PlaybackState, playbackState);
+
+ TestVideoSink surface(false);
+ QAudioOutput audioOut;
+
+ QMediaPlayer player;
+ player.setVideoOutput(&surface);
+ player.setSource(*m_15sVideo);
+
+ switch (playbackState) {
+ case QMediaPlayer::StoppedState:
+ break;
+ case QMediaPlayer::PausedState:
+ player.pause();
+ break;
+ case QMediaPlayer::PlayingState:
+ player.play();
+ break;
+ }
+
+ // set audio output
+ QTest::qWait(1s);
+ player.setAudioOutput(&audioOut);
+
+ // unset audio output
+ QTest::qWait(1s);
+ player.setAudioOutput(nullptr);
+
+ // wait for play until end
+ if (playbackState != QMediaPlayer::PlayingState)
+ player.play();
+ player.setPlaybackRate(5);
+ QTRY_COMPARE(player.playbackState(), QMediaPlayer::StoppedState);
+}
+
+void tst_QMediaPlayerBackend::setAudioOutput_doesNotStopPlayback_data()
+{
+ QTest::addColumn<QMediaPlayer::PlaybackState>("playbackState");
+ QTest::newRow("StoppedState") << QMediaPlayer::StoppedState;
+ QTest::newRow("PausedState") << QMediaPlayer::PausedState;
+ QTest::newRow("PlayingState") << QMediaPlayer::PlayingState;
+}
+
+void tst_QMediaPlayerBackend::swapAudioDevice_doesNotStopPlayback()
+{
+ using namespace std::chrono_literals;
+
+ const QList<QAudioDevice> outputDevices = QMediaDevices::audioOutputs();
+
+ if (outputDevices.size() < 2)
+ QSKIP("swapAudioDevice_doesNotStopPlayback requires two audio output devices");
+
+ CHECK_SELECTED_URL(m_15sVideo);
+ QFETCH(QMediaPlayer::PlaybackState, playbackState);
+
+ TestVideoSink surface(false);
+ QAudioOutput audioOut;
+
+ QMediaPlayer player;
+ player.setVideoOutput(&surface);
+ player.setAudioOutput(&audioOut);
+ player.setSource(*m_15sVideo);
+ switch (playbackState) {
+ case QMediaPlayer::StoppedState:
+ break;
+ case QMediaPlayer::PausedState:
+ player.pause();
+ break;
+ case QMediaPlayer::PlayingState:
+ player.play();
+ break;
+ }
+
+ // swap output device
+ QTest::qWait(1s);
+ audioOut.setDevice(outputDevices[0]);
+
+ QTest::qWait(1s);
+ audioOut.setDevice(outputDevices[1]);
+
+ QTest::qWait(1s);
+ audioOut.setDevice(outputDevices[0]);
+
+ // wait for play until end
+ if (playbackState != QMediaPlayer::PlayingState)
+ player.play();
+ player.setPlaybackRate(5);
+ QTRY_COMPARE(player.playbackState(), QMediaPlayer::StoppedState);
+}
+
+void tst_QMediaPlayerBackend::swapAudioDevice_doesNotStopPlayback_data()
+{
+ QTest::addColumn<QMediaPlayer::PlaybackState>("playbackState");
+ QTest::newRow("StoppedState") << QMediaPlayer::StoppedState;
+ QTest::newRow("PausedState") << QMediaPlayer::PausedState;
+ QTest::newRow("PlayingState") << QMediaPlayer::PlayingState;
+}
+
+void tst_QMediaPlayerBackend::play_readsSubtitle()
+{
+ using namespace std::chrono_literals;
+ CHECK_SELECTED_URL(m_subtitleVideo);
+
+ QVideoSink &sink = m_fixture->surface;
+ QMediaPlayer &player = m_fixture->player;
+
+ TestSubtitleSink subtitleSink;
+ QObject::connect(&sink, &QVideoSink::subtitleTextChanged, &subtitleSink,
+ &TestSubtitleSink::addSubtitle);
+
+ player.setSource(*m_subtitleVideo);
+ QTRY_COMPARE(player.subtitleTracks().size(), 1);
+ QCOMPARE_EQ(player.subtitleTracks()[0].value(QMediaMetaData::Duration), 3000);
+
+ player.setActiveSubtitleTrack(0);
+
+ if (!isGStreamerPlatform()) // FIXME: spurious deadlocks
+ player.setPlaybackRate(5.f);
+
+ player.play();
+
+ QStringList expectedSubtitleList = {
+ u"Hello"_s,
+ u""_s,
+ u"World"_s,
+ u""_s,
+ };
+
+ QTRY_COMPARE(subtitleSink.subtitles, expectedSubtitleList);
+}
+
+void tst_QMediaPlayerBackend::multiTrack_validateMetadata()
+{
+ CHECK_SELECTED_URL(m_multitrackVideo);
+ QMediaPlayer &player = m_fixture->player;
+
+ player.setSource(*m_multitrackVideo);
+
+ QTRY_COMPARE(player.videoTracks().size(), 2);
+ QTRY_COMPARE(player.audioTracks().size(), 2);
+ QTRY_COMPARE(player.subtitleTracks().size(), 2);
+
+ QSKIP_GSTREAMER("GStreamer does not provide correct track order");
+
+ QCOMPARE(player.videoTracks()[0][QMediaMetaData::Title], u"One"_s);
+ QCOMPARE(player.videoTracks()[1][QMediaMetaData::Title], u"Two"_s);
+
+ QCOMPARE(player.audioTracks()[0][QMediaMetaData::Language], QLocale::Language::English);
+ QCOMPARE(player.audioTracks()[1][QMediaMetaData::Language], QLocale::Language::Spanish);
+ QCOMPARE(player.subtitleTracks()[0][QMediaMetaData::Language], QLocale::Language::English);
+ QCOMPARE(player.subtitleTracks()[1][QMediaMetaData::Language], QLocale::Language::Spanish);
+}
+
+void tst_QMediaPlayerBackend::play_readsSubtitle_fromMultiTrack()
+{
+ using namespace std::chrono_literals;
+ CHECK_SELECTED_URL(m_multitrackVideo);
+
+ QFETCH(int, track);
+ QFETCH(const QStringList, expectedSubtitles);
+
+ QVideoSink &sink = m_fixture->surface;
+ QMediaPlayer &player = m_fixture->player;
+
+ TestSubtitleSink subtitleSink;
+ QObject::connect(&sink, &QVideoSink::subtitleTextChanged, &subtitleSink,
+ &TestSubtitleSink::addSubtitle);
+
+ player.setSource(*m_multitrackVideo);
+
+ QTRY_COMPARE(player.subtitleTracks().size(), 2);
+
+ if (track != -1) {
+ if (isGStreamerPlatform())
+ QCOMPARE(player.subtitleTracks()[0].value(QMediaMetaData::Duration), 4000);
+ if (isFFMPEGPlatform())
+ QCOMPARE(player.subtitleTracks()[0].value(QMediaMetaData::Duration), 15046);
+ }
+
+ if (isGStreamerPlatform()) {
+ bool swapTracks =
+ player.subtitleTracks()[0][QMediaMetaData::Language] == QLocale::Language::Spanish;
+
+ if (swapTracks && track == 1)
+ track = 0;
+ if (swapTracks && track == 0)
+ track = 1;
+ }
+
+ player.setActiveSubtitleTrack(track);
+ if (!isGStreamerPlatform())
+ player.setPlaybackRate(5.f);
+ player.play();
+
+ if (expectedSubtitles.isEmpty())
+ QTRY_COMPARE_GT(player.position(), 2000);
+
+ QTRY_COMPARE(subtitleSink.subtitles, expectedSubtitles);
+}
+
+void tst_QMediaPlayerBackend::play_readsSubtitle_fromMultiTrack_data()
+{
+ QSKIP_GSTREAMER("GStreamer does not provide consistent track order");
+
+ QTest::addColumn<int>("track");
+ QTest::addColumn<QStringList>("expectedSubtitles");
+
+ QTest::addRow("track 0") << 0
+ << QStringList{
+ u"1s track 1"_s,
+ u""_s,
+ u"3s track 1"_s,
+ u""_s,
+ };
+ QTest::addRow("track 1") << 1
+ << QStringList{
+ u"1s track 2"_s,
+ u""_s,
+ u"3s track 2"_s,
+ u""_s,
+ };
+
+ QTest::addRow("no subtitles") << -1 << QStringList{};
+}
+
+void tst_QMediaPlayerBackend::setActiveSubtitleTrack_switchesSubtitles()
+{
+ QVideoSink &sink = m_fixture->surface;
+ QMediaPlayer &player = m_fixture->player;
+
+ QFETCH(const QUrl, media);
+ QFETCH(const int, positionToSwapTrack);
+ QFETCH(const QLatin1String, testMode);
+ QFETCH(const QStringList, expectedSubtitles);
+
+ TestSubtitleSink subtitleSink;
+ QObject::connect(&sink, &QVideoSink::subtitleTextChanged, &subtitleSink,
+ &TestSubtitleSink::addSubtitle);
+
+ player.setSource(media);
+
+ QTRY_COMPARE(player.subtitleTracks().size(), 2);
+
+ int track0 = 0;
+ int track1 = 1;
+ if (isGStreamerPlatform()) {
+ bool swapTracks =
+ player.subtitleTracks()[0][QMediaMetaData::Language] == QLocale::Language::Spanish;
+
+ if (swapTracks) {
+ track1 = 0;
+ track0 = 1;
+ }
+ }
+
+ player.setActiveSubtitleTrack(track0);
+
+ player.play();
+ QTRY_COMPARE_GT(player.position(), positionToSwapTrack);
+
+ if (testMode == "setWhilePaused"_L1) {
+ player.pause();
+ player.setActiveSubtitleTrack(track1);
+ player.play();
+ } else if (testMode == "setWhilePlaying"_L1) {
+ player.setActiveSubtitleTrack(track1);
+ } else {
+ QFAIL("should not reach");
+ }
+
+ QTRY_COMPARE(subtitleSink.subtitles, expectedSubtitles);
+}
+
+void tst_QMediaPlayerBackend::setActiveSubtitleTrack_switchesSubtitles_data()
+{
+ QSKIP_GSTREAMER("GStreamer does not provide consistent track order");
+
+ QTest::addColumn<QUrl>("media");
+ QTest::addColumn<QLatin1String>("testMode");
+ QTest::addColumn<int>("positionToSwapTrack");
+ QTest::addColumn<QStringList>("expectedSubtitles");
+
+ QTest::addRow("while paused") << *m_multitrackVideo << "setWhilePaused"_L1 << 2100
+ << QStringList{
+ u"1s track 1"_s,
+ u""_s,
+ u"3s track 2"_s,
+ u""_s,
+ };
+ QTest::addRow("while playing") << *m_multitrackVideo << "setWhilePlaying"_L1 << 2100
+ << QStringList{
+ u"1s track 1"_s,
+ u""_s,
+ u"3s track 2"_s,
+ u""_s,
+ };
+
+ QTest::addRow("while paused, subtitles start at zero")
+ << *m_multitrackSubtitleStartsAtZeroVideo << "setWhilePaused"_L1 << 1100
+ << QStringList{
+ u"0s track 1"_s,
+ u""_s,
+ u"2s track 2"_s,
+ u""_s,
+ };
+ QTest::addRow("while playing, subtitles start at zero")
+ << *m_multitrackSubtitleStartsAtZeroVideo << "setWhilePlaying"_L1 << 1100
+ << QStringList{
+ u"0s track 1"_s,
+ u""_s,
+ u"2s track 2"_s,
+ u""_s,
+ };
+}
+
+void tst_QMediaPlayerBackend::setActiveVideoTrack_switchesVideoTrack()
+{
+ using namespace std::chrono_literals;
+ QSKIP_GSTREAMER("GStreamer does not provide consistent track order");
+
+ TestVideoSink &sink = m_fixture->surface;
+ sink.setStoreFrames();
+ QMediaPlayer &player = m_fixture->player;
+
+ player.setSource(*m_multitrackVideo);
+
+ QTRY_COMPARE(player.videoTracks().size(), 2);
+
+ int track0 = 0;
+ int track1 = 1;
+ if (isGStreamerPlatform()) {
+ bool swapTracks = player.subtitleTracks()[0][QMediaMetaData::Title] != u"One"_s;
+
+ if (swapTracks) {
+ track0 = 1;
+ track1 = 0;
+ }
+ }
+
+ player.setActiveVideoTrack(track0);
+ player.play();
+
+ sink.waitForFrame();
+
+ QTest::qWait(500ms);
+ sink.waitForFrame();
+ QCOMPARE(sink.m_frameList.back().toImage().pixel(10, 10), QColor(0xff, 0x80, 0x7f).rgb());
+
+ player.setActiveVideoTrack(track1);
+
+ QTest::qWait(500ms);
+ sink.waitForFrame();
+ QCOMPARE(sink.m_frameList.back().toImage().pixel(10, 10), QColor(0x80, 0x80, 0xff).rgb());
+}
+
+void tst_QMediaPlayerBackend::disablingAllTracks_doesNotStopPlayback()
+{
+ QSKIP_GSTREAMER("position does not advance in GStreamer");
+
+ QMediaPlayer &player = m_fixture->player;
+
+ player.setSource(*m_multitrackVideo);
+
+ // CAVEAT: we cannot set active tracks before tracksChanged is emitted
+ QTRY_COMPARE(player.videoTracks().size(), 2);
+
+ player.setActiveVideoTrack(-1);
+ player.setActiveAudioTrack(-1);
+
+ player.play();
+ QTRY_VERIFY(player.position() > 1000);
+
+ QCOMPARE(m_fixture->surface.m_totalFrames, 0);
+}
+
+void tst_QMediaPlayerBackend::disablingAllTracks_beforeTracksChanged_doesNotStopPlayback()
+{
+ QSKIP_GSTREAMER("position does not advance in GStreamer");
+ QSKIP_FFMPEG("setActiveXXXTrack(-1) only works after tracksChanged");
+
+ QMediaPlayer &player = m_fixture->player;
+
+ player.setSource(*m_multitrackVideo);
+
+ player.setActiveVideoTrack(-1);
+ player.setActiveAudioTrack(-1);
+
+ player.play();
+ QTRY_VERIFY(player.position() > 1000);
+
+ QCOMPARE(m_fixture->surface.m_totalFrames, 0);
+}
+
QTEST_MAIN(tst_QMediaPlayerBackend)
+
#include "tst_qmediaplayerbackend.moc"
diff --git a/tests/auto/integration/qmediaplayerformatsupport/CMakeLists.txt b/tests/auto/integration/qmediaplayerformatsupport/CMakeLists.txt
new file mode 100644
index 000000000..b4dd19f75
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+file(GLOB_RECURSE test_data_glob
+ RELATIVE
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ testdata/**
+)
+
+list(APPEND testdata_resource_files ${test_data_glob})
+
+qt_internal_add_test(tst_qmediaplayerformatsupport
+ SOURCES
+ tst_qmediaplayerformatsupport.cpp
+ ../shared/mediabackendutils.h
+ INCLUDE_DIRECTORIES
+ ../shared/
+ LIBRARIES
+ Qt::Core
+ Qt::MultimediaPrivate
+ TESTDATA
+ ${testdata_resource_files}
+)
+
+qt_internal_add_resource(tst_qmediaplayerformatsupport "testdata"
+ PREFIX
+ "/"
+ FILES
+ ${testdata_resource_files}
+)
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/README.md b/tests/auto/integration/qmediaplayerformatsupport/testdata/README.md
new file mode 100644
index 000000000..f52108bcc
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/README.md
@@ -0,0 +1,35 @@
+Sample video files are created using FFmpeg, for example:
+
+:: Supported container formats
+ffmpeg -ss 2 -i flipable.gif -t 1 -r 5 containers/supported/container.avi
+ffmpeg -ss 2 -i flipable.gif -t 1 -r 5 containers/supported/container.mkv
+ffmpeg -ss 2 -i flipable.gif -t 1 -r 5 containers/supported/container.mp4
+ffmpeg -ss 2 -i flipable.gif -t 1 -r 25 containers/supported/container.mpeg
+ffmpeg -ss 2 -i flipable.gif -t 1 -r 25 containers/supported/container.wmv
+
+:: Unsupported container formats
+ffmpeg -ss 2 -i flipable.gif -t 1 -r 5 containers/unsupported/container.webm
+
+:: Supported pixel formats h264
+ffmpeg -i flipable.gif -pix_fmt yuv420p -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv420p.mp4
+ffmpeg -i flipable.gif -pix_fmt yuv420p10 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv420p10.mp4
+ffmpeg -i flipable.gif -pix_fmt yuv422p -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv422p.mp4
+ffmpeg -i flipable.gif -pix_fmt yuv422p10 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv422p10.mp4
+ffmpeg -i flipable.gif -pix_fmt yuv444p -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv444p.mp4
+ffmpeg -i flipable.gif -pix_fmt yuvj420p -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuvj420p.mp4
+ffmpeg -i flipable.gif -pix_fmt yuvj422p -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuvj422p.mp4
+ffmpeg -i flipable.gif -pix_fmt yuvj444p -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuvj444p.mp4
+ffmpeg -i flipable.gif -pix_fmt nv12 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_nv12.mp4
+ffmpeg -i flipable.gif -pix_fmt nv16 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_nv16.mp4
+ffmpeg -i flipable.gif -pix_fmt nv21 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_nv21.mp4
+ffmpeg -i flipable.gif -pix_fmt yuv420p10le -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv420p10le.mp4
+ffmpeg -i flipable.gif -pix_fmt yuv444p10 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv444p10.mp4
+ffmpeg -i flipable.gif -pix_fmt yuv422p10le -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_yuv422p10le.mp4
+ffmpeg -i flipable.gif -pix_fmt gray -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_gray.mp4
+ffmpeg -i flipable.gif -pix_fmt gray10le -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264 -r 5 pixel_formats/supported/h264_gray10le.mp4
+
+ffmpeg -i flipable.gif -pix_fmt bgr0 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264rgb -r 5 pixel_formats/supported/h264_bgr0.mp4
+ffmpeg -i flipable.gif -pix_fmt bgr24 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264rgb -r 5 pixel_formats/supported/h264_bgr24.mp4
+ffmpeg -i flipable.gif -pix_fmt rgb24 -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -vcodec libx264rgb -r 5 pixel_formats/supported/h264_rgb24.mp4
+
+
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.avi b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.avi
new file mode 100644
index 000000000..a48028550
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.avi
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mkv b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mkv
new file mode 100644
index 000000000..2e362d7ca
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mkv
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mp4
new file mode 100644
index 000000000..bff40278d
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mpeg b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mpeg
new file mode 100644
index 000000000..b94a47f0a
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.mpeg
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.wmv b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.wmv
new file mode 100644
index 000000000..1a7577e3f
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/supported/container.wmv
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/unsupported/container.webp b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/unsupported/container.webp
new file mode 100644
index 000000000..ed8b6f631
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/containers/unsupported/container.webp
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/flipable.gif b/tests/auto/integration/qmediaplayerformatsupport/testdata/flipable.gif
new file mode 100644
index 000000000..fd187906b
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/flipable.gif
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr0.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr0.mp4
new file mode 100644
index 000000000..ff9eacb65
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr0.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr24.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr24.mp4
new file mode 100644
index 000000000..ff9eacb65
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_bgr24.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray.mp4
new file mode 100644
index 000000000..c69357d2b
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray10le.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray10le.mp4
new file mode 100644
index 000000000..339912757
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_gray10le.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv12.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv12.mp4
new file mode 100644
index 000000000..20b51609a
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv12.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv16.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv16.mp4
new file mode 100644
index 000000000..165819b22
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv16.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv21.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv21.mp4
new file mode 100644
index 000000000..20b51609a
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_nv21.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_rgb24.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_rgb24.mp4
new file mode 100644
index 000000000..ff9eacb65
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_rgb24.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p.mp4
new file mode 100644
index 000000000..53ef62b45
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10.mp4
new file mode 100644
index 000000000..bb45d344c
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10le.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10le.mp4
new file mode 100644
index 000000000..bb45d344c
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv420p10le.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p.mp4
new file mode 100644
index 000000000..165819b22
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10.mp4
new file mode 100644
index 000000000..563fce6da
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10le.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10le.mp4
new file mode 100644
index 000000000..563fce6da
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv422p10le.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p.mp4
new file mode 100644
index 000000000..953d014ec
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p10.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p10.mp4
new file mode 100644
index 000000000..c27683ed7
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuv444p10.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj420p.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj420p.mp4
new file mode 100644
index 000000000..3906325e1
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj420p.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj422p.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj422p.mp4
new file mode 100644
index 000000000..6b2d43fd9
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj422p.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj444p.mp4 b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj444p.mp4
new file mode 100644
index 000000000..75008f2aa
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/testdata/pixel_formats/supported/h264_yuvj444p.mp4
Binary files differ
diff --git a/tests/auto/integration/qmediaplayerformatsupport/tst_qmediaplayerformatsupport.cpp b/tests/auto/integration/qmediaplayerformatsupport/tst_qmediaplayerformatsupport.cpp
new file mode 100644
index 000000000..8cabb28c8
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerformatsupport/tst_qmediaplayerformatsupport.cpp
@@ -0,0 +1,124 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mediabackendutils.h"
+#include <QtTest/QtTest>
+#include <QDebug>
+#include <QtMultimedia/qmediaplayer.h>
+#include <QtMultimedia/QVideoSink>
+
+using namespace Qt::StringLiterals;
+
+QT_USE_NAMESPACE
+
+struct Fixture
+{
+ Fixture() { player.setVideoOutput(&videoOutput); }
+
+ QVideoSink videoOutput;
+ QMediaPlayer player;
+ QSignalSpy errorOccurred{ &player, &QMediaPlayer::errorOccurred };
+ QSignalSpy playbackStateChanged{ &player, &QMediaPlayer::playbackStateChanged };
+
+ bool startedPlaying() const
+ {
+ return playbackStateChanged.contains(QList<QVariant>{ QMediaPlayer::PlayingState });
+ }
+};
+
+void addTestData(QLatin1StringView dir)
+{
+ QDirIterator it(dir);
+ while (it.hasNext()) {
+ QString v = it.next();
+ QTest::addRow("%s", v.toLatin1().data()) << QUrl{ "qrc" + v };
+ }
+}
+
+class tst_qmediaplayerformatsupport : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase()
+ {
+ if (!isFFMPEGPlatform())
+ QSKIP("Test is only intended for FFmpeg backend");
+ }
+
+private slots:
+ void play_succeeds_withSupportedContainer_data()
+ {
+ QTest::addColumn<QUrl>("url");
+ addTestData(":testdata/containers/supported"_L1);
+ }
+
+ void play_succeeds_withSupportedContainer()
+ {
+ QFETCH(const QUrl, url);
+
+ Fixture f;
+ f.player.setSource(url);
+ f.player.play();
+
+ QTRY_VERIFY(f.startedPlaying());
+
+ // Log to understand failures in CI
+ for (const QList<QVariant> &err : f.errorOccurred)
+ qCritical() << "Unexpected failure detected:" << err[0] << "," << err[1];
+
+#ifdef Q_OS_ANDROID
+ QSKIP("QTBUG-125613 Limited format support on Android 14");
+#endif
+
+ QVERIFY(f.errorOccurred.empty());
+ }
+
+ void play_succeeds_withSupportedPixelFormats_data()
+ {
+ QTest::addColumn<QUrl>("url");
+ addTestData(":testdata/pixel_formats/supported"_L1);
+ }
+
+ void play_succeeds_withSupportedPixelFormats()
+ {
+ QFETCH(const QUrl, url);
+
+ Fixture f;
+ f.player.setSource(url);
+ f.player.play();
+
+ QTRY_VERIFY(f.startedPlaying());
+
+ // Log to understand failures in CI
+ for (const QList<QVariant> &err : f.errorOccurred)
+ qCritical() << "Unexpected failure detected:" << err[0] << "," << err[1];
+
+#ifdef Q_OS_ANDROID
+ QSKIP("QTBUG-125613 Limited format support on Android 14");
+#endif
+
+ QVERIFY(f.errorOccurred.empty());
+ }
+
+ void play_fails_withUnsupportedContainer_data()
+ {
+ QTest::addColumn<QUrl>("url");
+ addTestData(":testdata/containers/unsupported"_L1);
+ }
+
+ void play_fails_withUnsupportedContainer()
+ {
+ QFETCH(const QUrl, url);
+
+ Fixture f;
+ f.player.setSource(url);
+ f.player.play();
+
+ QTRY_COMPARE_NE(f.player.error(), QMediaPlayer::NoError);
+ }
+};
+
+QTEST_MAIN(tst_qmediaplayerformatsupport)
+
+#include "tst_qmediaplayerformatsupport.moc"
diff --git a/tests/auto/integration/qml/CMakeLists.txt b/tests/auto/integration/qml/CMakeLists.txt
index 35837cbad..1b7a1f686 100644
--- a/tests/auto/integration/qml/CMakeLists.txt
+++ b/tests/auto/integration/qml/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qml.pro.
#####################################################################
@@ -9,7 +12,7 @@ qt_internal_add_test(tst_qml
QMLTEST
SOURCES
tst_qml.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
)
diff --git a/tests/auto/integration/qml/soundeffect/tst_soundeffect.qml b/tests/auto/integration/qml/soundeffect/tst_soundeffect.qml
index 7ebbe2e73..0b5867bce 100644
--- a/tests/auto/integration/qml/soundeffect/tst_soundeffect.qml
+++ b/tests/auto/integration/qml/soundeffect/tst_soundeffect.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtMultimedia
diff --git a/tests/auto/integration/qml/tst_qml.cpp b/tests/auto/integration/qml/tst_qml.cpp
index 668285a31..2bdca1037 100644
--- a/tests/auto/integration/qml/tst_qml.cpp
+++ b/tests/auto/integration/qml/tst_qml.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtQuickTest/quicktest.h>
QUICK_TEST_MAIN(qml)
diff --git a/tests/auto/integration/qquickvideooutput/CMakeLists.txt b/tests/auto/integration/qquickvideooutput/CMakeLists.txt
index 145dd8875..909416140 100644
--- a/tests/auto/integration/qquickvideooutput/CMakeLists.txt
+++ b/tests/auto/integration/qquickvideooutput/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qdeclarativevideooutput.pro.
#####################################################################
@@ -9,7 +12,7 @@ qt_internal_add_test(tst_qquickvideooutput
tst_qquickvideooutput.cpp
INCLUDE_DIRECTORIES
../../../../src/imports/multimedia
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
Qt::MultimediaQuickPrivate
diff --git a/tests/auto/integration/qquickvideooutput/tst_qquickvideooutput.cpp b/tests/auto/integration/qquickvideooutput/tst_qquickvideooutput.cpp
index 519fc6944..85a30bbb7 100644
--- a/tests/auto/integration/qquickvideooutput/tst_qquickvideooutput.cpp
+++ b/tests/auto/integration/qquickvideooutput/tst_qquickvideooutput.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
//TESTED_COMPONENT=plugins/declarative/multimedia
@@ -124,19 +99,19 @@ void tst_QQuickVideoOutput::fillMode()
// Default is preserveaspectfit
QCOMPARE(videoOutput->property("fillMode").value<QQuickVideoOutput::FillMode>(), QQuickVideoOutput::PreserveAspectFit);
- QCOMPARE(propSpy.count(), 0);
+ QCOMPARE(propSpy.size(), 0);
videoOutput->setProperty("fillMode", QVariant(int(QQuickVideoOutput::PreserveAspectCrop)));
QCOMPARE(videoOutput->property("fillMode").value<QQuickVideoOutput::FillMode>(), QQuickVideoOutput::PreserveAspectCrop);
- QCOMPARE(propSpy.count(), 1);
+ QCOMPARE(propSpy.size(), 1);
videoOutput->setProperty("fillMode", QVariant(int(QQuickVideoOutput::Stretch)));
QCOMPARE(videoOutput->property("fillMode").value<QQuickVideoOutput::FillMode>(), QQuickVideoOutput::Stretch);
- QCOMPARE(propSpy.count(), 2);
+ QCOMPARE(propSpy.size(), 2);
videoOutput->setProperty("fillMode", QVariant(int(QQuickVideoOutput::Stretch)));
QCOMPARE(videoOutput->property("fillMode").value<QQuickVideoOutput::FillMode>(), QQuickVideoOutput::Stretch);
- QCOMPARE(propSpy.count(), 2);
+ QCOMPARE(propSpy.size(), 2);
delete videoOutput;
}
@@ -153,43 +128,43 @@ void tst_QQuickVideoOutput::orientation()
// Default orientation is 0
QCOMPARE(videoOutput->property("orientation").toInt(), 0);
- QCOMPARE(propSpy.count(), 0);
+ QCOMPARE(propSpy.size(), 0);
videoOutput->setProperty("orientation", QVariant(90));
QCOMPARE(videoOutput->property("orientation").toInt(), 90);
- QCOMPARE(propSpy.count(), 1);
+ QCOMPARE(propSpy.size(), 1);
videoOutput->setProperty("orientation", QVariant(180));
QCOMPARE(videoOutput->property("orientation").toInt(), 180);
- QCOMPARE(propSpy.count(), 2);
+ QCOMPARE(propSpy.size(), 2);
videoOutput->setProperty("orientation", QVariant(270));
QCOMPARE(videoOutput->property("orientation").toInt(), 270);
- QCOMPARE(propSpy.count(), 3);
+ QCOMPARE(propSpy.size(), 3);
videoOutput->setProperty("orientation", QVariant(360));
QCOMPARE(videoOutput->property("orientation").toInt(), 360);
- QCOMPARE(propSpy.count(), 4);
+ QCOMPARE(propSpy.size(), 4);
// More than 360 should be fine
videoOutput->setProperty("orientation", QVariant(540));
QCOMPARE(videoOutput->property("orientation").toInt(), 540);
- QCOMPARE(propSpy.count(), 5);
+ QCOMPARE(propSpy.size(), 5);
// Negative should be fine
videoOutput->setProperty("orientation", QVariant(-180));
QCOMPARE(videoOutput->property("orientation").toInt(), -180);
- QCOMPARE(propSpy.count(), 6);
+ QCOMPARE(propSpy.size(), 6);
// Same value should not reemit
videoOutput->setProperty("orientation", QVariant(-180));
QCOMPARE(videoOutput->property("orientation").toInt(), -180);
- QCOMPARE(propSpy.count(), 6);
+ QCOMPARE(propSpy.size(), 6);
// Non multiples of 90 should not work
videoOutput->setProperty("orientation", QVariant(-1));
QCOMPARE(videoOutput->property("orientation").toInt(), -180);
- QCOMPARE(propSpy.count(), 6);
+ QCOMPARE(propSpy.size(), 6);
delete videoOutput;
}
@@ -291,7 +266,7 @@ void tst_QQuickVideoOutput::paintSurface()
videoOutput->setSize(QSize(2, 2));
QVideoFrame frame(QVideoFrameFormat(QSize(4, 4), QVideoFrameFormat::Format_ARGB8888));
- frame.map(QVideoFrame::ReadWrite);
+ frame.map(QtVideo::MapMode::ReadWrite);
QCOMPARE(frame.mappedBytes(0), 64);
memcpy(frame.bits(0), rgb32ImageData, 64);
frame.unmap();
@@ -317,11 +292,11 @@ void tst_QQuickVideoOutput::sourceRect()
presentDummyFrame(holder.videoSink(), QSize(200,100));
QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
- QCOMPARE(propSpy.count(), 1);
+ QCOMPARE(propSpy.size(), 1);
// Another frame shouldn't cause a source rect change
presentDummyFrame(holder.videoSink(), QSize(200,100));
- QCOMPARE(propSpy.count(), 1);
+ QCOMPARE(propSpy.size(), 1);
QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
// Changing orientation and stretch modes should not affect this
diff --git a/tests/auto/integration/qquickvideooutput_window/CMakeLists.txt b/tests/auto/integration/qquickvideooutput_window/CMakeLists.txt
index 8d9bb078d..e7b624c70 100644
--- a/tests/auto/integration/qquickvideooutput_window/CMakeLists.txt
+++ b/tests/auto/integration/qquickvideooutput_window/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qdeclarativevideooutput_window.pro.
#####################################################################
@@ -9,7 +12,7 @@ qt_internal_add_test(tst_qquickvideooutput_window
tst_qquickvideooutput_window.cpp
INCLUDE_DIRECTORIES
../../../../src/imports/multimedia
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
Qt::MultimediaQuickPrivate
diff --git a/tests/auto/integration/qquickvideooutput_window/tst_qquickvideooutput_window.cpp b/tests/auto/integration/qquickvideooutput_window/tst_qquickvideooutput_window.cpp
index 5942010e6..68f1771f9 100644
--- a/tests/auto/integration/qquickvideooutput_window/tst_qquickvideooutput_window.cpp
+++ b/tests/auto/integration/qquickvideooutput_window/tst_qquickvideooutput_window.cpp
@@ -1,31 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
//TESTED_COMPONENT=plugins/declarative/multimedia
diff --git a/tests/auto/integration/qscreencapturebackend/BLACKLIST b/tests/auto/integration/qscreencapturebackend/BLACKLIST
new file mode 100644
index 000000000..bd6bb0e01
--- /dev/null
+++ b/tests/auto/integration/qscreencapturebackend/BLACKLIST
@@ -0,0 +1,11 @@
+macos ci
+windows ci
+
+#QTBUG-122577
+opensuse-15.5 ci
+
+#QTBUG-112827 on Android
+#QTBUG-111190, v4l2m2m issues
+[capture_capturesToFile_whenConnectedToMediaRecorder]
+linux ci
+android ci
diff --git a/tests/auto/integration/qscreencapturebackend/CMakeLists.txt b/tests/auto/integration/qscreencapturebackend/CMakeLists.txt
new file mode 100644
index 000000000..9b40642a0
--- /dev/null
+++ b/tests/auto/integration/qscreencapturebackend/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qscreencapturebackend Test:
+#####################################################################
+
+qt_internal_add_test(tst_qscreencapturebackend
+ SOURCES
+ tst_qscreencapturebackend.cpp
+ LIBRARIES
+ Qt::Multimedia
+ Qt::Gui
+ Qt::Widgets
+)
+
+
diff --git a/tests/auto/integration/qscreencapturebackend/tst_qscreencapturebackend.cpp b/tests/auto/integration/qscreencapturebackend/tst_qscreencapturebackend.cpp
new file mode 100644
index 000000000..522d9bcdd
--- /dev/null
+++ b/tests/auto/integration/qscreencapturebackend/tst_qscreencapturebackend.cpp
@@ -0,0 +1,505 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+
+#include <qvideosink.h>
+#include <qvideoframe.h>
+#include <qmediacapturesession.h>
+#include <qpainter.h>
+#include <qscreencapture.h>
+#include <qsignalspy.h>
+#include <qmediarecorder.h>
+#include <qmediaplayer.h>
+
+#include <vector>
+
+QT_USE_NAMESPACE
+
+/*
+ This is the backend conformance test.
+
+ Since it relies on platform media framework it may be less stable.
+ Note, some of screen capture backend is not implemented or has bugs.
+ That's why some of the tests could get failed.
+ TODO: fix and platform implementations and make it stable.
+*/
+
+class QTestWidget : public QWidget
+{
+public:
+ QTestWidget(QColor firstColor, QColor secondColor)
+ : m_firstColor(firstColor), m_secondColor(secondColor)
+ {
+ }
+
+ static std::unique_ptr<QTestWidget> createAndShow(Qt::WindowFlags flags, const QRect &geometry,
+ QScreen *screen = nullptr,
+ QColor firstColor = QColor(0xFF, 0, 0),
+ QColor secondColor = QColor(0, 0, 0xFF))
+ {
+ auto widget = std::make_unique<QTestWidget>(firstColor, secondColor);
+
+ widget->setWindowTitle("Test QScreenCapture");
+ widget->setScreen(screen ? screen : QApplication::primaryScreen());
+ widget->setWindowFlags(flags);
+ widget->setGeometry(geometry);
+ widget->show();
+
+ return widget;
+ }
+
+ void setColors(QColor firstColor, QColor secondColor)
+ {
+ m_firstColor = firstColor;
+ m_secondColor = secondColor;
+ this->repaint();
+ }
+
+protected:
+ void paintEvent(QPaintEvent * /*event*/) override
+ {
+ QPainter p(this);
+ p.setPen(Qt::NoPen);
+
+ p.setBrush(m_firstColor);
+ auto rect = this->rect();
+ p.drawRect(rect);
+
+ if (m_firstColor != m_secondColor) {
+ rect.adjust(40, 50, -60, -70);
+ p.setBrush(m_secondColor);
+ p.drawRect(rect);
+ }
+ }
+
+private:
+ QColor m_firstColor;
+ QColor m_secondColor;
+};
+
+class TestVideoSink : public QVideoSink
+{
+ Q_OBJECT
+public:
+ TestVideoSink()
+ {
+ connect(this, &QVideoSink::videoFrameChanged, this, &TestVideoSink::videoFrameChangedSync);
+ }
+
+ void setStoreImagesEnabled(bool storeImages = true) {
+ if (storeImages)
+ connect(this, &QVideoSink::videoFrameChanged, this, &TestVideoSink::storeImage, Qt::UniqueConnection);
+ else
+ disconnect(this, &QVideoSink::videoFrameChanged, this, &TestVideoSink::storeImage);
+ }
+
+ const std::vector<QImage> &images() const { return m_images; }
+
+ QVideoFrame waitForFrame()
+ {
+ QSignalSpy spy(this, &TestVideoSink::videoFrameChangedSync);
+ return spy.wait() ? spy.at(0).at(0).value<QVideoFrame>() : QVideoFrame{};
+ }
+
+signals:
+ void videoFrameChangedSync(QVideoFrame frame);
+
+private:
+ void storeImage(const QVideoFrame &frame) {
+ auto image = frame.toImage();
+ image.detach();
+ m_images.push_back(std::move(image));
+ }
+
+private:
+ std::vector<QImage> m_images;
+};
+
+class tst_QScreenCaptureBackend : public QObject
+{
+ Q_OBJECT
+
+ void removeWhileCapture(std::function<void(QScreenCapture &)> scModifier,
+ std::function<void()> deleter);
+
+ void capture(QTestWidget &widget, const QPoint &drawingOffset, const QSize &expectedSize,
+ std::function<void(QScreenCapture &)> scModifier);
+
+private slots:
+ void initTestCase();
+ void setActive_startsAndStopsCapture();
+ void setScreen_selectsScreen_whenCalledWithWidgetsScreen();
+ void constructor_selectsPrimaryScreenAsDefault();
+ void setScreen_selectsSecondaryScreen_whenCalledWithSecondaryScreen();
+
+ void capture_capturesToFile_whenConnectedToMediaRecorder();
+ void removeScreenWhileCapture(); // Keep the test last defined. TODO: find a way to restore
+ // application screens.
+};
+
+void tst_QScreenCaptureBackend::setActive_startsAndStopsCapture()
+{
+#ifdef Q_OS_ANDROID
+ // Should be removed after fixing QTBUG-112855
+ auto widget = QTestWidget::createAndShow(Qt::Window | Qt::FramelessWindowHint,
+ QRect{ 200, 100, 430, 351 });
+ QVERIFY(QTest::qWaitForWindowExposed(widget.get()));
+ QTest::qWait(100);
+#endif
+ TestVideoSink sink;
+ QScreenCapture sc;
+
+ QSignalSpy errorsSpy(&sc, &QScreenCapture::errorOccurred);
+ QSignalSpy activeStateSpy(&sc, &QScreenCapture::activeChanged);
+
+ QMediaCaptureSession session;
+
+ session.setScreenCapture(&sc);
+ session.setVideoSink(&sink);
+
+ QCOMPARE(activeStateSpy.size(), 0);
+ QVERIFY(!sc.isActive());
+
+ // set active true
+ {
+ sc.setActive(true);
+
+ QVERIFY(sc.isActive());
+ QCOMPARE(activeStateSpy.size(), 1);
+ QCOMPARE(activeStateSpy.front().front().toBool(), true);
+ QCOMPARE(errorsSpy.size(), 0);
+ }
+
+ // wait a bit
+ {
+ activeStateSpy.clear();
+ QTest::qWait(50);
+
+ QCOMPARE(activeStateSpy.size(), 0);
+ }
+
+ // set active false
+ {
+ sc.setActive(false);
+
+ sink.setStoreImagesEnabled(true);
+
+ QVERIFY(!sc.isActive());
+ QCOMPARE(sink.images().size(), 0u);
+ QCOMPARE(activeStateSpy.size(), 1);
+ QCOMPARE(activeStateSpy.front().front().toBool(), false);
+ QCOMPARE(errorsSpy.size(), 0);
+ }
+
+ // set active false again
+ {
+ activeStateSpy.clear();
+
+ sc.setActive(false);
+
+ QVERIFY(!sc.isActive());
+ QCOMPARE(activeStateSpy.size(), 0);
+ QCOMPARE(errorsSpy.size(), 0);
+ }
+}
+
+void tst_QScreenCaptureBackend::capture(QTestWidget &widget, const QPoint &drawingOffset,
+ const QSize &expectedSize,
+ std::function<void(QScreenCapture &)> scModifier)
+{
+ TestVideoSink sink;
+ QScreenCapture sc;
+
+ QSignalSpy errorsSpy(&sc, &QScreenCapture::errorOccurred);
+
+ if (scModifier)
+ scModifier(sc);
+
+ QMediaCaptureSession session;
+
+ session.setScreenCapture(&sc);
+ session.setVideoSink(&sink);
+
+ const auto pixelRatio = widget.devicePixelRatio();
+
+ sc.setActive(true);
+
+ QVERIFY(sc.isActive());
+
+ // In some cases, on Linux the window seems to be of a wrong color after appearance,
+ // the delay helps.
+ // TODO: remove the delay
+ QTest::qWait(300);
+
+ // Let's wait for the first frame to address a potential initialization delay.
+ // In practice, the delay varies between the platform and may randomly get increased.
+ {
+ const auto firstFrame = sink.waitForFrame();
+ QVERIFY(firstFrame.isValid());
+ }
+
+ sink.setStoreImagesEnabled();
+
+ const int delay = 200;
+
+ QTest::qWait(delay);
+ const auto expectedFramesCount =
+ delay / static_cast<int>(1000 / std::min(widget.screen()->refreshRate(), 60.));
+ const int framesCount = static_cast<int>(sink.images().size());
+ QCOMPARE_LE(framesCount, expectedFramesCount + 2);
+ QCOMPARE_GE(framesCount, 1);
+
+ for (const auto &image : sink.images()) {
+ auto pixelColor = [&drawingOffset, pixelRatio, &image](int x, int y) {
+ return image.pixelColor((QPoint(x, y) + drawingOffset) * pixelRatio).toRgb();
+ };
+ const int capturedWidth = qRound(image.size().width() / pixelRatio);
+ const int capturedHeight = qRound(image.size().height() / pixelRatio);
+ QCOMPARE(QSize(capturedWidth, capturedHeight), expectedSize);
+ QCOMPARE(pixelColor(0, 0), QColor(0xFF, 0, 0));
+
+ QCOMPARE(pixelColor(39, 50), QColor(0xFF, 0, 0));
+ QCOMPARE(pixelColor(40, 49), QColor(0xFF, 0, 0));
+
+ QCOMPARE(pixelColor(40, 50), QColor(0, 0, 0xFF));
+ }
+
+ QCOMPARE(errorsSpy.size(), 0);
+}
+
+void tst_QScreenCaptureBackend::removeWhileCapture(
+ std::function<void(QScreenCapture &)> scModifier, std::function<void()> deleter)
+{
+ QVideoSink sink;
+ QScreenCapture sc;
+
+ QSignalSpy errorsSpy(&sc, &QScreenCapture::errorOccurred);
+
+ QMediaCaptureSession session;
+
+ if (scModifier)
+ scModifier(sc);
+
+ session.setScreenCapture(&sc);
+ session.setVideoSink(&sink);
+
+ sc.setActive(true);
+
+ QTest::qWait(300);
+
+ QCOMPARE(errorsSpy.size(), 0);
+
+ if (deleter)
+ deleter();
+
+ QTest::qWait(100);
+
+ QSignalSpy framesSpy(&sink, &QVideoSink::videoFrameChanged);
+
+ QTest::qWait(100);
+
+ QCOMPARE(errorsSpy.size(), 1);
+ QCOMPARE(errorsSpy.front().front().value<QScreenCapture::Error>(),
+ QScreenCapture::CaptureFailed);
+ QVERIFY2(!errorsSpy.front().back().value<QString>().isEmpty(),
+ "Expected not empty error description");
+
+ QVERIFY2(framesSpy.empty(), "No frames expected after screen removal");
+}
+
+void tst_QScreenCaptureBackend::initTestCase()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("grabWindow() no longer supported on Android adding child windows support: QTBUG-118849");
+#endif
+#if defined(Q_OS_LINUX)
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci" &&
+ qEnvironmentVariable("XDG_SESSION_TYPE").toLower() != "x11")
+ QSKIP("Skip on wayland; to be fixed");
+#endif
+
+ if (!QApplication::primaryScreen())
+ QSKIP("No screens found");
+
+ QScreenCapture sc;
+ if (sc.error() == QScreenCapture::CapturingNotSupported)
+ QSKIP("Screen capturing not supported");
+}
+
+void tst_QScreenCaptureBackend::setScreen_selectsScreen_whenCalledWithWidgetsScreen()
+{
+ auto widget = QTestWidget::createAndShow(Qt::Window | Qt::FramelessWindowHint
+ | Qt::WindowStaysOnTopHint
+#ifdef Q_OS_ANDROID
+ | Qt::Popup
+#endif
+ ,
+ QRect{ 200, 100, 430, 351 });
+ QVERIFY(QTest::qWaitForWindowExposed(widget.get()));
+
+ capture(*widget, { 200, 100 }, widget->screen()->size(),
+ [&widget](QScreenCapture &sc) { sc.setScreen(widget->screen()); });
+}
+
+void tst_QScreenCaptureBackend::constructor_selectsPrimaryScreenAsDefault()
+{
+ auto widget = QTestWidget::createAndShow(Qt::Window | Qt::FramelessWindowHint
+ | Qt::WindowStaysOnTopHint
+#ifdef Q_OS_ANDROID
+ | Qt::Popup
+#endif
+ ,
+ QRect{ 200, 100, 430, 351 });
+ QVERIFY(QTest::qWaitForWindowExposed(widget.get()));
+
+ capture(*widget, { 200, 100 }, QApplication::primaryScreen()->size(), nullptr);
+}
+
+void tst_QScreenCaptureBackend::setScreen_selectsSecondaryScreen_whenCalledWithSecondaryScreen()
+{
+ const auto screens = QApplication::screens();
+ if (screens.size() < 2)
+ QSKIP("2 or more screens required");
+
+ auto topLeft = screens.back()->geometry().topLeft().x();
+
+ auto widgetOnSecondaryScreen = QTestWidget::createAndShow(
+ Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint,
+ QRect{ topLeft + 200, 100, 430, 351 }, screens.back());
+ QVERIFY(QTest::qWaitForWindowExposed(widgetOnSecondaryScreen.get()));
+
+ auto widgetOnPrimaryScreen = QTestWidget::createAndShow(
+ Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint,
+ QRect{ 200, 100, 430, 351 }, screens.front(), QColor(0, 0, 0), QColor(0, 0, 0));
+ QVERIFY(QTest::qWaitForWindowExposed(widgetOnPrimaryScreen.get()));
+ capture(*widgetOnSecondaryScreen, { 200, 100 }, screens.back()->size(),
+ [&screens](QScreenCapture &sc) { sc.setScreen(screens.back()); });
+}
+
+void tst_QScreenCaptureBackend::capture_capturesToFile_whenConnectedToMediaRecorder()
+{
+#ifdef Q_OS_LINUX
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("QTBUG-116671: SKIP on linux CI to avoid crashes in ffmpeg. To be fixed.");
+#endif
+
+ // Create widget with blue color
+ auto widget = QTestWidget::createAndShow(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint,
+ QRect{ 200, 100, 430, 351 });
+ widget->setColors(QColor(0, 0, 0xFF), QColor(0, 0, 0xFF));
+
+ QScreenCapture sc;
+ QSignalSpy errorsSpy(&sc, &QScreenCapture::errorOccurred);
+ QMediaCaptureSession session;
+ QMediaRecorder recorder;
+ session.setScreenCapture(&sc);
+ session.setRecorder(&recorder);
+ auto screen = QApplication::primaryScreen();
+ QSize screenSize = screen->geometry().size();
+ QSize videoResolution = QSize(1920, 1080);
+ recorder.setVideoResolution(videoResolution);
+ recorder.setQuality(QMediaRecorder::VeryHighQuality);
+
+ // Insert metadata
+ QMediaMetaData metaData;
+ metaData.insert(QMediaMetaData::Author, QStringLiteral("Author"));
+ metaData.insert(QMediaMetaData::Date, QDateTime::currentDateTime());
+ recorder.setMetaData(metaData);
+
+ sc.setActive(true);
+
+ QTest::qWait(1000); // wait a bit for SC threading activating
+
+ {
+ QSignalSpy recorderStateChanged(&recorder, &QMediaRecorder::recorderStateChanged);
+
+ recorder.record();
+
+ QTRY_VERIFY(!recorderStateChanged.empty());
+ QCOMPARE(recorder.recorderState(), QMediaRecorder::RecordingState);
+ }
+
+ QTest::qWait(1000);
+ widget->setColors(QColor(0, 0xFF, 0), QColor(0, 0xFF, 0)); // Change widget color
+ QTest::qWait(1000);
+
+ {
+ QSignalSpy recorderStateChanged(&recorder, &QMediaRecorder::recorderStateChanged);
+
+ recorder.stop();
+
+ QTRY_VERIFY(!recorderStateChanged.empty());
+ QCOMPARE(recorder.recorderState(), QMediaRecorder::StoppedState);
+ }
+
+ QString fileName = recorder.actualLocation().toLocalFile();
+ QVERIFY(!fileName.isEmpty());
+ QVERIFY(QFileInfo(fileName).size() > 0);
+
+ TestVideoSink sink;
+ QMediaPlayer player;
+ player.setSource(fileName);
+ QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::LoadedMedia);
+ QCOMPARE_EQ(player.metaData().value(QMediaMetaData::Resolution).toSize(),
+ QSize(videoResolution));
+ QCOMPARE_GT(player.duration(), 350);
+ QCOMPARE_LT(player.duration(), 3000);
+
+ // Convert video frames to QImages
+ player.setVideoSink(&sink);
+ sink.setStoreImagesEnabled();
+ player.setPlaybackRate(10);
+ player.play();
+ QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia);
+ const size_t framesCount = sink.images().size();
+
+ // Find pixel point at center of widget
+ int x = 415 * videoResolution.width() / screenSize.width();
+ int y = 275 * videoResolution.height() / screenSize.height();
+ auto point = QPoint(x, y);
+
+ // Verify color of first fourth of the video frames
+ for (size_t i = 0; i <= static_cast<size_t>(framesCount * 0.25); i++) {
+ QImage image = sink.images().at(i);
+ QVERIFY(!image.isNull());
+ QRgb rgb = image.pixel(point);
+// qDebug() << QStringLiteral("RGB: %1, %2, %3").arg(qRed(rgb)).arg(qGreen(rgb)).arg(qBlue(rgb));
+
+ // RGB values should be 0, 0, 255. Compensating for inaccurate video encoding.
+ QVERIFY(qRed(rgb) <= 60);
+ QVERIFY(qGreen(rgb) <= 60);
+ QVERIFY(qBlue(rgb) >= 200);
+ }
+
+ // Verify color of last fourth of the video frames
+ for (size_t i = static_cast<size_t>(framesCount * 0.75); i < framesCount - 1; i++) {
+ QImage image = sink.images().at(i);
+ QVERIFY(!image.isNull());
+ QRgb rgb = image.pixel(point);
+// qDebug() << QStringLiteral("RGB: %1, %2, %3").arg(qRed(rgb)).arg(qGreen(rgb)).arg(qBlue(rgb));
+
+ // RGB values should be 0, 255, 0. Compensating for inaccurate video encoding.
+ QVERIFY(qRed(rgb) <= 60);
+ QVERIFY(qGreen(rgb) >= 200);
+ QVERIFY(qBlue(rgb) <= 60);
+ }
+
+ QFile(fileName).remove();
+}
+
+void tst_QScreenCaptureBackend::removeScreenWhileCapture()
+{
+ QSKIP("TODO: find a reliable way to emulate it");
+
+ removeWhileCapture([](QScreenCapture &sc) { sc.setScreen(QApplication::primaryScreen()); },
+ []() {
+ // It's something that doesn't look safe but it performs required flow
+ // and allows to test the corener case.
+ delete QApplication::primaryScreen();
+ });
+}
+
+QTEST_MAIN(tst_QScreenCaptureBackend)
+
+#include "tst_qscreencapturebackend.moc"
diff --git a/tests/auto/integration/qsoundeffect/CMakeLists.txt b/tests/auto/integration/qsoundeffect/CMakeLists.txt
index 36340f9c1..d403d9514 100644
--- a/tests/auto/integration/qsoundeffect/CMakeLists.txt
+++ b/tests/auto/integration/qsoundeffect/CMakeLists.txt
@@ -1,40 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qsoundeffect.pro.
#####################################################################
## tst_qsoundeffect Test:
#####################################################################
-# Collect test data
-list(APPEND test_data "test.wav")
-
qt_internal_add_test(tst_qsoundeffect
SOURCES
tst_qsoundeffect.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
- TESTDATA ${test_data}
-)
-
-# Resources:
-set(resources_resource_files
- "test.wav"
- "test_corrupted.wav"
- "test_tone.wav"
-)
-
-qt_internal_add_resource(tst_qsoundeffect "resources"
- PREFIX
- "/"
- FILES
- ${resources_resource_files}
-)
-
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(tst_qsoundeffect CONDITION UNIX AND NOT APPLE AND NOT QT_FEATURE_pulseaudio
- DEFINES
- QT_MULTIMEDIA_QMEDIAPLAYER
+ TESTDATA
+ "test.wav"
+ "test_corrupted.wav"
+ "test_tone.wav"
)
diff --git a/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp b/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
index 21cda97b2..0d3d9f8b3 100644
--- a/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
+++ b/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/qlocale.h>
@@ -116,13 +89,13 @@ void tst_QSoundEffect::initTestCase()
void tst_QSoundEffect::testSource()
{
- QSignalSpy readSignal(sound, SIGNAL(sourceChanged()));
+ QSignalSpy readSignal(sound, &QSoundEffect::sourceChanged);
sound->setSource(url);
sound->setVolume(0.1f);
QCOMPARE(sound->source(),url);
- QCOMPARE(readSignal.count(),1);
+ QCOMPARE(readSignal.size(),1);
QTestEventLoop::instance().enterLoop(1);
sound->play();
@@ -135,24 +108,24 @@ void tst_QSoundEffect::testLooping()
sound->setSource(url);
QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
- QSignalSpy readSignal_Count(sound, SIGNAL(loopCountChanged()));
- QSignalSpy readSignal_Remaining(sound, SIGNAL(loopsRemainingChanged()));
+ QSignalSpy readSignal_Count(sound, &QSoundEffect::loopCountChanged);
+ QSignalSpy readSignal_Remaining(sound, &QSoundEffect::loopsRemainingChanged);
sound->setLoopCount(3);
sound->setVolume(0.1f);
QCOMPARE(sound->loopCount(), 3);
- QCOMPARE(readSignal_Count.count(), 1);
+ QCOMPARE(readSignal_Count.size(), 1);
QCOMPARE(sound->loopsRemaining(), 0);
- QCOMPARE(readSignal_Remaining.count(), 0);
+ QCOMPARE(readSignal_Remaining.size(), 0);
sound->play();
- QVERIFY(readSignal_Remaining.count() > 0);
+ QVERIFY(readSignal_Remaining.size() > 0);
// test.wav is about 200ms, wait until it has finished playing 3 times
QTestEventLoop::instance().enterLoop(3);
QTRY_COMPARE(sound->loopsRemaining(), 0);
- QVERIFY(readSignal_Remaining.count() == 4);
+ QVERIFY(readSignal_Remaining.size() == 4);
QTRY_VERIFY(!sound->isPlaying());
// QTBUG-36643 (setting the loop count while playing should work)
@@ -162,29 +135,29 @@ void tst_QSoundEffect::testLooping()
sound->setLoopCount(10);
QCOMPARE(sound->loopCount(), 10);
- QCOMPARE(readSignal_Count.count(), 1);
+ QCOMPARE(readSignal_Count.size(), 1);
QCOMPARE(sound->loopsRemaining(), 0);
- QCOMPARE(readSignal_Remaining.count(), 0);
+ QCOMPARE(readSignal_Remaining.size(), 0);
sound->play();
- QVERIFY(readSignal_Remaining.count() > 0);
+ QVERIFY(readSignal_Remaining.size() > 0);
// wait for the sound to be played several times
QTRY_VERIFY(sound->loopsRemaining() <= 7);
- QVERIFY(readSignal_Remaining.count() >= 3);
+ QVERIFY(readSignal_Remaining.size() >= 3);
readSignal_Count.clear();
readSignal_Remaining.clear();
// change the loop count while playing
sound->setLoopCount(3);
QCOMPARE(sound->loopCount(), 3);
- QCOMPARE(readSignal_Count.count(), 1);
+ QCOMPARE(readSignal_Count.size(), 1);
QCOMPARE(sound->loopsRemaining(), 3);
- QCOMPARE(readSignal_Remaining.count(), 1);
+ QCOMPARE(readSignal_Remaining.size(), 1);
// wait for all the loops to be completed
QTRY_COMPARE(sound->loopsRemaining(), 0);
- QTRY_VERIFY(readSignal_Remaining.count() == 4);
+ QTRY_VERIFY(readSignal_Remaining.size() == 4);
QTRY_VERIFY(!sound->isPlaying());
}
@@ -194,13 +167,13 @@ void tst_QSoundEffect::testLooping()
sound->setLoopCount(QSoundEffect::Infinite);
QCOMPARE(sound->loopCount(), int(QSoundEffect::Infinite));
- QCOMPARE(readSignal_Count.count(), 1);
+ QCOMPARE(readSignal_Count.size(), 1);
QCOMPARE(sound->loopsRemaining(), 0);
- QCOMPARE(readSignal_Remaining.count(), 0);
+ QCOMPARE(readSignal_Remaining.size(), 0);
sound->play();
QTRY_COMPARE(sound->loopsRemaining(), int(QSoundEffect::Infinite));
- QCOMPARE(readSignal_Remaining.count(), 1);
+ QCOMPARE(readSignal_Remaining.size(), 1);
QTest::qWait(500);
QVERIFY(sound->isPlaying());
@@ -210,34 +183,34 @@ void tst_QSoundEffect::testLooping()
// Setting the loop count to 0 should play it one last time
sound->setLoopCount(0);
QCOMPARE(sound->loopCount(), 1);
- QCOMPARE(readSignal_Count.count(), 1);
+ QCOMPARE(readSignal_Count.size(), 1);
QCOMPARE(sound->loopsRemaining(), 1);
- QCOMPARE(readSignal_Remaining.count(), 1);
+ QCOMPARE(readSignal_Remaining.size(), 1);
QTRY_COMPARE(sound->loopsRemaining(), 0);
- QTRY_VERIFY(readSignal_Remaining.count() >= 2);
+ QTRY_VERIFY(readSignal_Remaining.size() >= 2);
QTRY_VERIFY(!sound->isPlaying());
}
}
void tst_QSoundEffect::testVolume()
{
- QSignalSpy readSignal(sound, SIGNAL(volumeChanged()));
+ QSignalSpy readSignal(sound, &QSoundEffect::volumeChanged);
sound->setVolume(0.5);
QCOMPARE(sound->volume(),0.5);
- QTRY_COMPARE(readSignal.count(),1);
+ QTRY_COMPARE(readSignal.size(),1);
}
void tst_QSoundEffect::testMuting()
{
- QSignalSpy readSignal(sound, SIGNAL(mutedChanged()));
+ QSignalSpy readSignal(sound, &QSoundEffect::mutedChanged);
sound->setMuted(true);
QCOMPARE(sound->isMuted(),true);
- QTRY_COMPARE(readSignal.count(),1);
+ QTRY_COMPARE(readSignal.size(),1);
}
void tst_QSoundEffect::testPlaying()
@@ -401,13 +374,19 @@ void tst_QSoundEffect::testSupportedMimeTypes()
void tst_QSoundEffect::testCorruptFile()
{
+ using namespace Qt::Literals;
+ auto expectedMessagePattern =
+ QRegularExpression(uR"(^QSoundEffect\(qaudio\): Error decoding source .*$)"_s);
+
for (int i = 0; i < 10; i++) {
- QSignalSpy statusSpy(sound, SIGNAL(statusChanged()));
+ QSignalSpy statusSpy(sound, &QSoundEffect::statusChanged);
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, expectedMessagePattern);
+
sound->setSource(urlCorrupted);
QVERIFY(!sound->isPlaying());
QVERIFY(sound->status() == QSoundEffect::Loading || sound->status() == QSoundEffect::Error);
QTRY_COMPARE(sound->status(), QSoundEffect::Error);
- QCOMPARE(statusSpy.count(), 2);
+ QCOMPARE(statusSpy.size(), 2);
sound->play();
QVERIFY(!sound->isPlaying());
diff --git a/tests/auto/integration/qvideoframebackend/CMakeLists.txt b/tests/auto/integration/qvideoframebackend/CMakeLists.txt
new file mode 100644
index 000000000..e4fa79201
--- /dev/null
+++ b/tests/auto/integration/qvideoframebackend/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qvideoframebackend Test:
+#####################################################################
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ testdata/*)
+list(APPEND testdata_resource_files ${test_data_glob})
+
+qt_internal_add_test(tst_qvideoframebackend
+ SOURCES
+ ../shared/mediafileselector.h
+ ../shared/testvideosink.h
+ tst_qvideoframebackend.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::MultimediaPrivate
+ BUILTIN_TESTDATA
+ TESTDATA ${testdata_resource_files}
+ INCLUDE_DIRECTORIES
+ ../shared/
+)
diff --git a/tests/auto/integration/qvideoframebackend/testdata/colors.mp4 b/tests/auto/integration/qvideoframebackend/testdata/colors.mp4
new file mode 100644
index 000000000..30ddda8b0
--- /dev/null
+++ b/tests/auto/integration/qvideoframebackend/testdata/colors.mp4
Binary files differ
diff --git a/tests/auto/integration/qvideoframebackend/testdata/one_red_frame.mp4 b/tests/auto/integration/qvideoframebackend/testdata/one_red_frame.mp4
new file mode 100644
index 000000000..6b67a3433
--- /dev/null
+++ b/tests/auto/integration/qvideoframebackend/testdata/one_red_frame.mp4
Binary files differ
diff --git a/tests/auto/integration/qvideoframebackend/tst_qvideoframebackend.cpp b/tests/auto/integration/qvideoframebackend/tst_qvideoframebackend.cpp
new file mode 100644
index 000000000..30f96fb50
--- /dev/null
+++ b/tests/auto/integration/qvideoframebackend/tst_qvideoframebackend.cpp
@@ -0,0 +1,264 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <qmediaplayer.h>
+#include <qvideoframe.h>
+#include <qdebug.h>
+
+#include "mediafileselector.h"
+#include "mediabackendutils.h"
+#include "testvideosink.h"
+#include "private/qvideotexturehelper_p.h"
+#include "private/qvideowindow_p.h"
+#include <thread>
+
+
+QT_USE_NAMESPACE
+
+class tst_QVideoFrameBackend : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase();
+ void init() { }
+ void cleanup() { }
+
+private slots:
+ void testMediaFilesAreSupported();
+
+ void toImage_retainsThePreviousMappedState_data();
+ void toImage_retainsThePreviousMappedState();
+
+ void toImage_rendersUpdatedFrame_afterMappingInWriteModeAndModifying_data();
+ void toImage_rendersUpdatedFrame_afterMappingInWriteModeAndModifying();
+
+ void toImage_returnsImage_whenCalledFromSeparateThreadAndWhileRenderingToWindow();
+
+private:
+ QVideoFrame createDefaultFrame() const;
+
+ QVideoFrame createMediaPlayerFrame() const;
+
+ using FrameCreator = decltype(&tst_QVideoFrameBackend::createDefaultFrame);
+
+ template <typename F>
+ void addMediaPlayerFrameTestData(F &&f);
+
+private:
+ MaybeUrl m_oneRedFrameVideo = QUnexpect{};
+ MaybeUrl m_colorsVideo = QUnexpect{};
+ MediaFileSelector m_mediaSelector;
+};
+
+QVideoFrame tst_QVideoFrameBackend::createDefaultFrame() const
+{
+ return QVideoFrame(QVideoFrameFormat(QSize(10, 20), QVideoFrameFormat::Format_ARGB8888));
+}
+
+QVideoFrame tst_QVideoFrameBackend::createMediaPlayerFrame() const
+{
+ if (!m_oneRedFrameVideo)
+ return {};
+
+ TestVideoSink sink;
+ QMediaPlayer player;
+
+ player.setVideoOutput(&sink);
+ player.setSource(*m_oneRedFrameVideo);
+
+ player.play();
+
+ return sink.waitForFrame();
+}
+
+template <typename F>
+void tst_QVideoFrameBackend::addMediaPlayerFrameTestData(F &&f)
+{
+ if (!m_oneRedFrameVideo) {
+ qWarning() << "Skipping test data with mediaplayer as the source cannot be open."
+ "\nSee the test case 'testMediaFilesAreSupported' for details";
+ return;
+ }
+
+ if (isGStreamerPlatform()) {
+ qWarning() << "createMediaPlayerFrame spuriously fails with gstreamer";
+ return;
+ }
+
+ f();
+}
+
+void tst_QVideoFrameBackend::initTestCase()
+{
+#ifdef Q_OS_ANDROID
+ qWarning() << "Skip media selection, QTBUG-118571";
+ return;
+#endif
+
+ m_oneRedFrameVideo = m_mediaSelector.select("qrc:/testdata/one_red_frame.mp4");
+ m_colorsVideo = m_mediaSelector.select("qrc:/testdata/colors.mp4");
+}
+
+void tst_QVideoFrameBackend::testMediaFilesAreSupported()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("Skip test cases with mediaPlayerFrame on Android CI, because of QTBUG-118571");
+#endif
+
+ QCOMPARE(m_mediaSelector.dumpErrors(), "");
+}
+
+void tst_QVideoFrameBackend::toImage_retainsThePreviousMappedState_data()
+{
+ QTest::addColumn<FrameCreator>("frameCreator");
+ QTest::addColumn<QtVideo::MapMode>("initialMapMode");
+
+ // clang-format off
+ QTest::addRow("defaulFrame.notMapped") << &tst_QVideoFrameBackend::createDefaultFrame
+ << QtVideo::MapMode::NotMapped;
+ QTest::addRow("defaulFrame.readOnly") << &tst_QVideoFrameBackend::createDefaultFrame
+ << QtVideo::MapMode::ReadOnly;
+
+ addMediaPlayerFrameTestData([]()
+ {
+ QTest::addRow("mediaPlayerFrame.notMapped")
+ << &tst_QVideoFrameBackend::createMediaPlayerFrame
+ << QtVideo::MapMode::NotMapped;
+ QTest::addRow("mediaPlayerFrame.readOnly")
+ << &tst_QVideoFrameBackend::createMediaPlayerFrame
+ << QtVideo::MapMode::ReadOnly;
+ });
+
+ // clang-format on
+}
+
+void tst_QVideoFrameBackend::toImage_retainsThePreviousMappedState()
+{
+ QFETCH(const FrameCreator, frameCreator);
+ QFETCH(const QtVideo::MapMode, initialMapMode);
+ const bool initiallyMapped = initialMapMode != QtVideo::MapMode::NotMapped;
+
+ QVideoFrame frame = std::invoke(frameCreator, this);
+ QVERIFY(frame.isValid());
+
+ frame.map(initialMapMode);
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), initialMapMode);
+
+ QImage image = frame.toImage();
+ QVERIFY(!image.isNull());
+
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), initialMapMode);
+ QCOMPARE(frame.isMapped(), initiallyMapped);
+}
+
+void tst_QVideoFrameBackend::toImage_rendersUpdatedFrame_afterMappingInWriteModeAndModifying_data()
+{
+ QTest::addColumn<FrameCreator>("frameCreator");
+ QTest::addColumn<QtVideo::MapMode>("mapMode");
+
+ // clang-format off
+ QTest::addRow("defaulFrame.writeOnly") << &tst_QVideoFrameBackend::createDefaultFrame
+ << QtVideo::MapMode::WriteOnly;
+ QTest::addRow("defaulFrame.readWrite") << &tst_QVideoFrameBackend::createDefaultFrame
+ << QtVideo::MapMode::ReadWrite;
+
+ addMediaPlayerFrameTestData([]()
+ {
+ QTest::addRow("mediaPlayerFrame.writeOnly")
+ << &tst_QVideoFrameBackend::createMediaPlayerFrame
+ << QtVideo::MapMode::WriteOnly;
+ QTest::addRow("mediaPlayerFrame.readWrite")
+ << &tst_QVideoFrameBackend::createMediaPlayerFrame
+ << QtVideo::MapMode::ReadWrite;
+ });
+ // clang-format on
+}
+
+void tst_QVideoFrameBackend::toImage_rendersUpdatedFrame_afterMappingInWriteModeAndModifying()
+{
+ QFETCH(const FrameCreator, frameCreator);
+ QFETCH(const QtVideo::MapMode, mapMode);
+
+ // Arrange
+
+ QVideoFrame frame = std::invoke(frameCreator, this);
+ QVERIFY(frame.isValid());
+
+ QImage originalImage = frame.toImage();
+ QVERIFY(!originalImage.isNull());
+
+ // Act: map the frame in write mode and change the top level pixel
+ frame.map(mapMode);
+ QVERIFY(frame.isWritable());
+
+ QCOMPARE_NE(frame.pixelFormat(), QVideoFrameFormat::Format_Invalid);
+
+ const QVideoTextureHelper::TextureDescription *textureDescription =
+ QVideoTextureHelper::textureDescription(frame.pixelFormat());
+ QVERIFY(textureDescription);
+
+ uchar *firstPlaneBits = frame.bits(0);
+ QVERIFY(firstPlaneBits);
+
+ for (int i = 0; i < textureDescription->strideFactor; ++i)
+ firstPlaneBits[i] = ~firstPlaneBits[i];
+
+ frame.unmap();
+
+ // get an image from modified frame
+ QImage modifiedImage = frame.toImage();
+
+ // Assert
+
+ QVERIFY(!frame.isMapped());
+ QCOMPARE_NE(originalImage.pixel(0, 0), modifiedImage.pixel(0, 0));
+ QCOMPARE(originalImage.pixel(1, 0), modifiedImage.pixel(1, 0));
+ QCOMPARE(originalImage.pixel(1, 1), modifiedImage.pixel(1, 1));
+}
+
+void tst_QVideoFrameBackend::toImage_returnsImage_whenCalledFromSeparateThreadAndWhileRenderingToWindow()
+{
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci") {
+#ifdef Q_OS_MACOS
+ QSKIP("SKIP on macOS because of crash and error \"Failed to create QWindow::MetalSurface. Metal is not supported by any of the GPUs in this system.\"");
+#elif defined(Q_OS_ANDROID)
+ QSKIP("SKIP initTestCase on CI, because of QTBUG-118571");
+#endif
+ }
+ // Arrange
+ QVideoWindow window;
+ window.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QMediaPlayer player;
+ player.setVideoOutput(&window);
+
+ const QVideoSink *sink = window.videoSink();
+ std::vector<QImage> images;
+
+ // act
+ connect(sink, &QVideoSink::videoFrameChanged, sink, [&](const QVideoFrame &frame) {
+
+ // Run toImage on separate thread to exercise special code path
+ QImage image;
+ auto t = std::thread([&] { image = frame.toImage(); });
+ t.join();
+
+ if (!image.isNull())
+ images.push_back(image);
+ });
+
+ // Arrange some more
+ player.setSource(*m_colorsVideo);
+ player.setLoops(10);
+ player.play();
+
+ // assert
+ QTRY_COMPARE_GE_WITH_TIMEOUT(images.size(), 10u, std::chrono::seconds(60) );
+}
+
+QTEST_MAIN(tst_QVideoFrameBackend)
+#include "tst_qvideoframebackend.moc"
diff --git a/tests/auto/integration/qwindowcapturebackend/BLACKLIST b/tests/auto/integration/qwindowcapturebackend/BLACKLIST
new file mode 100644
index 000000000..bc176cf98
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/BLACKLIST
@@ -0,0 +1,13 @@
+macos ci
+
+#QTBUG-112827 on Android
+#QTBUG-111190, v4l2m2m issues
+[recorder_encodesFrames_toValidMediaFile]
+linux ci
+android ci
+
+#QTBUG-112827 on Android
+#QTBUG-111190, v4l2m2m issues
+[recorder_encodesFrames_toValidMediaFile_whenWindowResizes]
+linux ci
+android ci
diff --git a/tests/auto/integration/qwindowcapturebackend/CMakeLists.txt b/tests/auto/integration/qwindowcapturebackend/CMakeLists.txt
new file mode 100644
index 000000000..8f633a1da
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qwindowcapturebackend
+ SOURCES
+ tst_qwindowcapturebackend.cpp
+ widget.h
+ widget.cpp
+ grabber.h
+ grabber.cpp
+ fixture.h
+ fixture.cpp
+ LIBRARIES
+ Qt::Multimedia
+ Qt::Gui
+ Qt::Widgets
+ Qt::MultimediaWidgets
+)
+
+
diff --git a/tests/auto/integration/qwindowcapturebackend/fixture.cpp b/tests/auto/integration/qwindowcapturebackend/fixture.cpp
new file mode 100644
index 000000000..ee130e294
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/fixture.cpp
@@ -0,0 +1,234 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "fixture.h"
+
+#include <qmediaplayer.h>
+#include <qvideowidget.h>
+#include <qsystemsemaphore.h>
+#include <quuid.h>
+
+DisableCursor::DisableCursor()
+{
+ QCursor cursor(Qt::BlankCursor);
+ QApplication::setOverrideCursor(cursor);
+}
+
+DisableCursor::~DisableCursor()
+{
+ QGuiApplication::restoreOverrideCursor();
+}
+
+WindowCaptureFixture::WindowCaptureFixture()
+{
+ m_session.setWindowCapture(&m_capture);
+ m_session.setVideoSink(&m_grabber);
+}
+
+QString WindowCaptureFixture::getResultsPath(const QString &fileName)
+{
+ const QString sep = QStringLiteral("--");
+
+ QString stem = QCoreApplication::applicationName();
+ if (const char *currentTest = QTest::currentTestFunction())
+ stem += sep + QString::fromLatin1(currentTest);
+
+ if (const char *currentTag = QTest::currentDataTag())
+ stem += sep + QString::fromLatin1(currentTag);
+
+ stem += sep + fileName;
+
+ const QDir resultsDir = qEnvironmentVariable("COIN_CTEST_RESULTSDIR", QDir::tempPath());
+
+ return resultsDir.filePath(stem);
+}
+
+bool WindowCaptureFixture::compareImages(QImage actual, const QImage &expected,
+ const QString &fileSuffix)
+{
+ // Convert to same format so that we can compare images
+ actual = actual.convertToFormat(expected.format());
+
+ if (actual == expected)
+ return true;
+
+ qWarning() << "Image comparison failed.";
+ qWarning() << "Actual image:";
+ qWarning() << actual;
+ qWarning() << "Expected image:";
+ qWarning() << expected;
+
+ const QString actualName = getResultsPath(QStringLiteral("actual%1.png").arg(fileSuffix));
+ if (!actual.save(actualName))
+ qWarning() << "Failed to save actual file to " << actualName;
+
+ const QString expectedName = getResultsPath(QStringLiteral("expected%1.png").arg(fileSuffix));
+ if (!expected.save(expectedName))
+ qWarning() << "Failed to save expected file to " << expectedName;
+
+ return false;
+}
+
+bool WindowCaptureWithWidgetFixture::start(QSize size)
+{
+ // In case of window capture failure, signal the grabber so we can stop
+ // waiting for frames that will never come.
+ connect(&m_capture, &QWindowCapture::errorOccurred, &m_grabber, &FrameGrabber::stop);
+
+ m_widget.setSize(size);
+
+ m_widget.show();
+
+ // Make sure window is in a state that allows it to be found by QWindowCapture.
+ // Not necessary on Windows, but seems to be necessary on some platforms.
+ if (!QTest::qWaitForWindowExposed(&m_widget, static_cast<int>(s_testTimeout.count()))) {
+ qWarning() << "Failed to display widget within timeout";
+ return false;
+ }
+
+ m_captureWindow = findCaptureWindow(m_widget.windowTitle());
+
+ if (!m_captureWindow.isValid())
+ return false;
+
+ m_capture.setWindow(m_captureWindow);
+ m_capture.setActive(true);
+
+ return true;
+}
+
+QVideoFrame WindowCaptureWithWidgetFixture::waitForFrame(qint64 noOlderThanTime)
+{
+ const std::vector<QVideoFrame> frames = m_grabber.waitAndTakeFrames(1u, noOlderThanTime);
+ if (frames.empty())
+ return QVideoFrame{};
+
+ return frames.back();
+}
+
+QCapturableWindow WindowCaptureWithWidgetFixture::findCaptureWindow(const QString &windowTitle)
+{
+ QList<QCapturableWindow> allWindows = QWindowCapture::capturableWindows();
+
+ const auto window = std::find_if(allWindows.begin(), allWindows.end(),
+ [windowTitle](const QCapturableWindow &win) {
+ return win.description() == windowTitle;
+ });
+
+ // Extra debug output to help understanding if test widget window could not be found
+ if (window == allWindows.end()) {
+ qDebug() << "Could not find window" << windowTitle << ". Existing capturable windows:";
+ std::for_each(allWindows.begin(), allWindows.end(), [](const QCapturableWindow &win) {
+ qDebug() << " " << win.description();
+ });
+ return QCapturableWindow{};
+ }
+
+ return *window;
+}
+
+void WindowCaptureWithWidgetAndRecorderFixture::start(QSize size, bool togglePattern)
+{
+ if (togglePattern) {
+ // Drive animation
+ connect(&m_grabber, &FrameGrabber::videoFrameChanged, &m_widget,
+ &TestWidget::togglePattern);
+ }
+
+ connect(&m_recorder, &QMediaRecorder::recorderStateChanged, this,
+ &WindowCaptureWithWidgetAndRecorderFixture::recorderStateChanged);
+
+ m_session.setRecorder(&m_recorder);
+ m_recorder.setQuality(QMediaRecorder::HighQuality);
+ m_recorder.setOutputLocation(QUrl::fromLocalFile(m_mediaFile));
+ m_recorder.setVideoResolution(size);
+
+ WindowCaptureWithWidgetFixture::start(size);
+
+ m_recorder.record();
+}
+
+bool WindowCaptureWithWidgetAndRecorderFixture::stop()
+{
+ m_recorder.stop();
+
+ const auto recorderStopped = [this] { return m_recorderState == QMediaRecorder::StoppedState; };
+
+ return QTest::qWaitFor(recorderStopped, s_testTimeout);
+}
+
+bool WindowCaptureWithWidgetAndRecorderFixture::testVideoFilePlayback(const QString &fileName)
+{
+ QVideoWidget widget;
+
+ QMediaPlayer player;
+
+ bool playing = true;
+ connect(&player, &QMediaPlayer::playbackStateChanged, this,
+ [&](QMediaPlayer::PlaybackState state) {
+ if (state == QMediaPlayer::StoppedState)
+ playing = false;
+ });
+
+ QMediaPlayer::Error error = QMediaPlayer::NoError;
+ connect(&player, &QMediaPlayer::errorOccurred, this,
+ [&](QMediaPlayer::Error e, const QString &errorString) {
+ error = e;
+ qWarning() << errorString;
+ });
+
+ player.setSource(QUrl{ fileName });
+ player.setVideoOutput(&widget);
+ widget.show();
+ player.play();
+
+ const bool completed = QTest::qWaitFor(
+ [&] { return !playing || error != QMediaPlayer::NoError; }, s_testTimeout);
+
+ return completed && error == QMediaPlayer::NoError;
+}
+
+void WindowCaptureWithWidgetAndRecorderFixture::recorderStateChanged(
+ QMediaRecorder::RecorderState state)
+{
+ m_recorderState = state;
+}
+
+bool WindowCaptureWithWidgetInOtherProcessFixture::start()
+{
+ // In case of window capture failure, signal the grabber so we can stop
+ // waiting for frames that will never come.
+ connect(&m_capture, &QWindowCapture::errorOccurred, &m_grabber, &FrameGrabber::stop);
+
+ // Create a new window title that is also used as a semaphore key with less than 30 characters
+ const QString windowTitle = QString::number(qHash(QUuid::createUuid().toString()));
+
+ QSystemSemaphore windowVisible{ QNativeIpcKey{ windowTitle } };
+
+ // Start another instance of the test executable and ask it to show a
+ // its test widget.
+ m_windowProcess.setArguments({ "--show", windowTitle });
+ m_windowProcess.setProgram(QApplication::applicationFilePath());
+ m_windowProcess.start();
+
+ // Make sure window is in a state that allows it to be found by QWindowCapture.
+ // We do this by waiting for the process to release the semaphore once its window is visible
+ windowVisible.acquire();
+
+ m_captureWindow = findCaptureWindow(windowTitle);
+
+ if (!m_captureWindow.isValid())
+ return false;
+
+ // Start capturing the out-of-process window
+ m_capture.setWindow(m_captureWindow);
+ m_capture.setActive(true);
+
+ // Show in-process widget used to create a reference image
+ m_widget.show();
+
+ return true;
+}
+
+
+#include "moc_fixture.cpp"
diff --git a/tests/auto/integration/qwindowcapturebackend/fixture.h b/tests/auto/integration/qwindowcapturebackend/fixture.h
new file mode 100644
index 000000000..2f72c3468
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/fixture.h
@@ -0,0 +1,147 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef WINDOW_CAPTURE_FIXTURE_H
+#define WINDOW_CAPTURE_FIXTURE_H
+
+#include "grabber.h"
+#include "widget.h"
+
+#include <chrono>
+#include <qmediacapturesession.h>
+#include <qmediarecorder.h>
+#include <qobject.h>
+#include <qsignalspy.h>
+#include <qtest.h>
+#include <qvideoframe.h>
+#include <qwindowcapture.h>
+#include <qprocess.h>
+
+QT_USE_NAMESPACE
+
+constexpr inline std::chrono::milliseconds s_testTimeout = std::chrono::seconds(60);
+
+/*!
+ Utility used to hide application cursor for image comparison tests.
+ On Windows, the mouse cursor is captured as part of the window capture.
+ This and can cause differences when comparing captured images with images
+ from QWindow::grab() which is used as a reference.
+*/
+struct DisableCursor final
+{
+ DisableCursor();
+ ~DisableCursor();
+
+ DisableCursor(const DisableCursor &) = delete;
+ DisableCursor &operator=(const DisableCursor &) = delete;
+};
+
+/*!
+ Fixture class that orchestrates setup/teardown of window capturing
+*/
+class WindowCaptureFixture : public QObject
+{
+ Q_OBJECT
+
+public:
+ WindowCaptureFixture();
+
+ /*!
+ Compare two images, ignoring format.
+ If images differ, diagnostic output is logged and images are saved to file.
+ */
+ static bool compareImages(QImage actual, const QImage &expected,
+ const QString &fileSuffix = "");
+
+ QMediaCaptureSession m_session;
+ QWindowCapture m_capture;
+ FrameGrabber m_grabber;
+
+ QSignalSpy m_errors{ &m_capture, &QWindowCapture::errorOccurred };
+ QSignalSpy m_activations{ &m_capture, &QWindowCapture::activeChanged };
+
+private:
+ /*!
+ Calculate a result path based upon a single filename.
+ On CI, the file will be located in COIN_CTEST_RESULTSDIR, and on developer
+ computers, the file will be located in TEMP.
+
+ The file name is on the form "testCase_testFunction_[dataTag_]fileName"
+ */
+ static QString getResultsPath(const QString &fileName);
+};
+
+/*!
+ Fixture class that extends window capture fixture with a capturable widget
+*/
+class WindowCaptureWithWidgetFixture : public WindowCaptureFixture
+{
+ Q_OBJECT
+
+public:
+ /*!
+ Starts capturing and returns true if successful.
+
+ Two phase initialization is used to be able to detect
+ failure to find widget window as a capturable window.
+ */
+ bool start(QSize size = { 60, 40 });
+
+ /*!
+ Waits until the a captured frame is received and returns it
+ */
+ QVideoFrame waitForFrame(qint64 noOlderThanTime = 0);
+
+ DisableCursor m_cursorDisabled; // Avoid mouse cursor causing image differences
+ TestWidget m_widget;
+ QCapturableWindow m_captureWindow;
+
+protected:
+ static QCapturableWindow findCaptureWindow(const QString &windowTitle);
+};
+
+class WindowCaptureWithWidgetInOtherProcessFixture : public WindowCaptureWithWidgetFixture
+{
+ Q_OBJECT
+
+public:
+ ~WindowCaptureWithWidgetInOtherProcessFixture() { m_windowProcess.close(); }
+
+ /*!
+ Create widget in separate process and start capturing its content
+ */
+ bool start();
+
+ QProcess m_windowProcess;
+};
+
+class WindowCaptureWithWidgetAndRecorderFixture : public WindowCaptureWithWidgetFixture
+{
+ Q_OBJECT
+
+public:
+ void start(QSize size = { 60, 40 }, bool togglePattern = true);
+
+ /*!
+ Stop recording.
+
+ Since recorder finalizes the file asynchronously, even after destructors are called,
+ we need to explicitly wait for the stopped state before ending the test. If we don't
+ do this, the media file can not be deleted by the QTemporaryDir at destruction.
+ */
+ bool stop();
+
+ bool testVideoFilePlayback(const QString& fileName);
+
+public slots:
+ void recorderStateChanged(QMediaRecorder::RecorderState state);
+
+public:
+ QTemporaryDir m_tempDir;
+ const QString m_mediaFile = m_tempDir.filePath("test.mp4");
+ QMediaRecorder m_recorder;
+ QMediaRecorder::RecorderState m_recorderState = QMediaRecorder::StoppedState;
+ QSignalSpy m_recorderErrors{ &m_recorder, &QMediaRecorder::errorOccurred };
+};
+
+#endif
diff --git a/tests/auto/integration/qwindowcapturebackend/grabber.cpp b/tests/auto/integration/qwindowcapturebackend/grabber.cpp
new file mode 100644
index 000000000..a7b72aeef
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/grabber.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "grabber.h"
+#include "fixture.h"
+
+#include <qtest.h>
+#include <qvideoframe.h>
+
+FrameGrabber::FrameGrabber()
+{
+ const auto copyFrame = [this](const QVideoFrame &frame) { m_frames.push_back(frame); };
+
+ connect(this, &QVideoSink::videoFrameChanged, this, copyFrame, Qt::DirectConnection);
+}
+
+const std::vector<QVideoFrame> &FrameGrabber::getFrames() const
+{
+ return m_frames;
+}
+
+std::vector<QVideoFrame> FrameGrabber::waitAndTakeFrames(size_t minCount, qint64 noOlderThanTime)
+{
+ m_frames.clear();
+
+ const auto enoughFramesOrStopped = [this, minCount, noOlderThanTime]() -> bool {
+ if (m_stopped)
+ return true; // Stop waiting
+
+ if (noOlderThanTime > 0) {
+ // Reject frames older than noOlderThanTime
+ const auto newEnd = std::remove_if(m_frames.begin(), m_frames.end(),
+ [noOlderThanTime](const QVideoFrame &frame) {
+ return frame.startTime() <= noOlderThanTime;
+ });
+ m_frames.erase(newEnd, m_frames.end());
+ }
+
+ return m_frames.size() >= minCount;
+ };
+
+ if (!QTest::qWaitFor(enoughFramesOrStopped, s_testTimeout))
+ return {};
+
+ if (m_stopped)
+ return {};
+
+ return std::exchange(m_frames, {});
+}
+
+bool FrameGrabber::isStopped() const
+{
+ return m_stopped;
+}
+
+void FrameGrabber::stop()
+{
+ qWarning() << "Stopping grabber";
+ m_stopped = true;
+}
+
+#include "moc_grabber.cpp"
diff --git a/tests/auto/integration/qwindowcapturebackend/grabber.h b/tests/auto/integration/qwindowcapturebackend/grabber.h
new file mode 100644
index 000000000..e997ff954
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/grabber.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef WINDOW_CAPTURE_GRABBER_H
+#define WINDOW_CAPTURE_GRABBER_H
+
+#include <qvideosink.h>
+#include <vector>
+
+QT_USE_NAMESPACE
+
+/*!
+ The FrameGrabber stores frames that arrive from the window capture,
+ and is used to inspect captured frames in the tests.
+*/
+class FrameGrabber : public QVideoSink
+{
+ Q_OBJECT
+
+public:
+ FrameGrabber();
+
+ const std::vector<QVideoFrame> &getFrames() const;
+
+ /*!
+ Wait for at least \a minCount frames that are no older than noOlderThanTime.
+
+ Returns empty if not enough frames arrived, or if grabber was stopped before global timeout
+ elapsed.
+ */
+ std::vector<QVideoFrame> waitAndTakeFrames(size_t minCount, qint64 noOlderThanTime = 0);
+
+ bool isStopped() const;
+
+public slots:
+ void stop();
+
+private:
+ std::vector<QVideoFrame> m_frames;
+ bool m_stopped = false;
+};
+
+#endif
diff --git a/tests/auto/integration/qwindowcapturebackend/tst_qwindowcapturebackend.cpp b/tests/auto/integration/qwindowcapturebackend/tst_qwindowcapturebackend.cpp
new file mode 100644
index 000000000..6809f81a8
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/tst_qwindowcapturebackend.cpp
@@ -0,0 +1,278 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+// TESTED_COMPONENT=src/multimedia
+
+#include "fixture.h"
+#include "widget.h"
+
+#include <qmediarecorder.h>
+#include <qpainter.h>
+#include <qsignalspy.h>
+#include <qtest.h>
+#include <qwindowcapture.h>
+#include <qcommandlineparser.h>
+
+#include <chrono>
+#include <vector>
+
+using std::chrono::duration_cast;
+using std::chrono::high_resolution_clock;
+using std::chrono::microseconds;
+
+QT_USE_NAMESPACE
+
+class tst_QWindowCaptureBackend : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ static void initTestCase()
+ {
+#ifdef Q_OS_ANDROID
+ QSKIP("Feature does not work on Android");
+#endif
+#if defined(Q_OS_LINUX)
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci"
+ && qEnvironmentVariable("XDG_SESSION_TYPE").toLower() != "x11")
+ QSKIP("Skip on wayland; to be fixed");
+#elif defined(Q_OS_MACOS)
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("QTBUG-116285: Skip on macOS CI because of permissions issues");
+#endif
+
+ const QWindowCapture capture;
+ if (capture.error() == QWindowCapture::CapturingNotSupported)
+ QSKIP("Screen capturing not supported");
+ }
+
+ void isActive_returnsFalse_whenNotStarted()
+ {
+ const WindowCaptureFixture fixture;
+ QVERIFY(!fixture.m_capture.isActive());
+ }
+
+ void setActive_failsAndEmitEerrorOccurred_whenNoWindowSelected()
+ {
+ WindowCaptureFixture fixture;
+
+ fixture.m_capture.setActive(true);
+
+ QVERIFY(!fixture.m_capture.isActive());
+ QVERIFY(!fixture.m_errors.empty());
+ }
+
+ void setActive_startsWindowCapture_whenCalledWithTrue()
+ {
+ WindowCaptureWithWidgetFixture fixture;
+ QVERIFY(fixture.start());
+
+ // Ensure that we have received a frame
+ QVERIFY(fixture.waitForFrame().isValid());
+
+ QCOMPARE(fixture.m_activations.size(), 1);
+ QVERIFY(fixture.m_errors.empty());
+ }
+
+ void capturedImage_equals_imageFromGrab_data()
+ {
+ QTest::addColumn<QSize>("windowSize");
+ QTest::newRow("single-pixel-window") << QSize{1, 1};
+ QTest::newRow("small-window") << QSize{60, 40};
+ QTest::newRow("odd-width-window") << QSize{ 61, 40 };
+ QTest::newRow("odd-height-window") << QSize{ 60, 41 };
+ QTest::newRow("big-window") << QApplication::primaryScreen()->size();
+ }
+
+ void capturedImage_equals_imageFromGrab()
+ {
+ QFETCH(QSize, windowSize);
+
+ WindowCaptureWithWidgetFixture fixture;
+ QVERIFY(fixture.start(windowSize));
+
+ const QImage expected = fixture.m_widget.grabImage();
+ const QImage actual = fixture.waitForFrame().toImage();
+
+ QVERIFY(fixture.compareImages(actual, expected));
+ }
+
+ void capturedImage_changes_whenWindowContentChanges()
+ {
+ WindowCaptureWithWidgetFixture fixture;
+ QVERIFY(fixture.start());
+
+ const auto startTime = high_resolution_clock::now();
+
+ const QVideoFrame colorFrame = fixture.waitForFrame();
+ QVERIFY(colorFrame.isValid());
+
+ fixture.m_widget.setDisplayPattern(TestWidget::Grid);
+
+ // Ignore all frames that were grabbed since the colored frame,
+ // to ensure that we get a frame after we changed display pattern
+ const high_resolution_clock::duration delay = high_resolution_clock::now() - startTime;
+ const QVideoFrame gridFrame = fixture.waitForFrame(
+ colorFrame.endTime() + duration_cast<microseconds>(delay).count());
+
+ QVERIFY(gridFrame.isValid());
+
+ // Make sure that the gridFrame has a different content than the colorFrame
+ QCOMPARE(gridFrame.size(), colorFrame.size());
+ QCOMPARE_NE(gridFrame.toImage(), colorFrame.toImage());
+
+ const QImage actualGridImage = fixture.m_widget.grabImage();
+ QVERIFY(fixture.compareImages(gridFrame.toImage(), actualGridImage));
+ }
+
+ void sequenceOfCapturedImages_compareEqual_whenWindowContentIsUnchanged()
+ {
+ WindowCaptureWithWidgetFixture fixture;
+ QVERIFY(fixture.start());
+
+ const std::vector<QVideoFrame> frames = fixture.m_grabber.waitAndTakeFrames(10);
+ QVERIFY(!frames.empty());
+
+ QImage firstFrame = frames.front().toImage();
+ QVERIFY(!firstFrame.isNull());
+
+ qsizetype index = 0;
+ for (const auto &frame : std::as_const(frames)){
+ QVERIFY(fixture.compareImages(frame.toImage(), firstFrame, QString::number(index)));
+ ++index;
+ }
+ }
+
+ void recorder_encodesFrames_toValidMediaFile_data()
+ {
+ QTest::addColumn<QSize>("windowSize");
+ //QTest::newRow("empty-window") << QSize{ 0, 0 }; TODO: Crash
+ //QTest::newRow("single-pixel-window") << QSize{ 1, 1 }; TODO: Crash
+ QTest::newRow("small-window") << QSize{ 60, 40 };
+ QTest::newRow("odd-width-window") << QSize{ 61, 40 };
+ QTest::newRow("odd-height-window") << QSize{ 60, 41 };
+ QTest::newRow("big-window") << QSize{ 800, 600 };
+ }
+
+ void recorder_encodesFrames_toValidMediaFile()
+ {
+#ifdef Q_OS_LINUX
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("QTBUG-116671: SKIP on linux CI to avoid crashes in ffmpeg. To be fixed.");
+#endif
+ QFETCH(QSize, windowSize);
+
+ WindowCaptureWithWidgetAndRecorderFixture fixture;
+ fixture.start(windowSize);
+
+ // Wait on grabber to ensure that video recorder also get some frames
+ fixture.m_grabber.waitAndTakeFrames(60);
+
+ // Wait for recorder finalization
+ fixture.stop();
+
+ QVERIFY(fixture.m_recorderErrors.empty());
+ QVERIFY(QFile{ fixture.m_mediaFile }.exists());
+ QVERIFY(fixture.testVideoFilePlayback(fixture.m_mediaFile));
+ }
+
+ void recorder_encodesFrames_toValidMediaFile_whenWindowResizes_data()
+ {
+ QTest::addColumn<int>("increment");
+ QTest::newRow("shrink") << -1;
+ QTest::newRow("grow") << 1;
+ }
+
+ void recorder_encodesFrames_toValidMediaFile_whenWindowResizes()
+ {
+#ifdef Q_OS_LINUX
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("QTBUG-116671: SKIP on linux CI to avoid crashes in ffmpeg. To be fixed.");
+#endif
+ QFETCH(int, increment);
+
+ QSize windowSize = { 200, 150 };
+ WindowCaptureWithWidgetAndRecorderFixture fixture;
+ fixture.start(windowSize, /*toggle pattern*/ false);
+
+ for (qsizetype i = 0; i < 20; ++i) {
+ windowSize.setWidth(windowSize.width() + increment);
+ windowSize.setHeight(windowSize.height() + increment);
+ fixture.m_widget.setSize(windowSize);
+
+ // Wait on grabber to ensure that video recorder also get some frames
+ fixture.m_grabber.waitAndTakeFrames(1);
+ }
+
+ // Wait for recorder finalization
+ fixture.stop();
+
+ QVERIFY(fixture.m_recorderErrors.empty());
+ QVERIFY(QFile{ fixture.m_mediaFile }.exists());
+ QVERIFY(fixture.testVideoFilePlayback(fixture.m_mediaFile));
+ }
+
+ void windowCapture_capturesWindowsInOtherProcesses()
+ {
+ WindowCaptureWithWidgetInOtherProcessFixture fixture;
+ QVERIFY(fixture.start());
+
+ // Get reference image from our in-process widget
+ const QImage expected = fixture.m_widget.grabImage();
+
+ // Get actual image grabbed from out-of-process widget
+ const QImage actual = fixture.waitForFrame().toImage();
+
+ QVERIFY(fixture.compareImages(actual, expected));
+ }
+
+ /*
+ This test is not a requirement per se, but we want all platforms
+ to behave the same. A reasonable alternative could have been to
+ treat closed window as a regular 'Stop' capture (not an error).
+ */
+ void windowCapture_stopsWithError_whenProcessCloses()
+ {
+ WindowCaptureWithWidgetInOtherProcessFixture fixture;
+ QVERIFY(fixture.start());
+
+ // Get capturing started
+ fixture.m_grabber.waitAndTakeFrames(3);
+
+ // Closing the process waits for it to exit
+ fixture.m_windowProcess.close();
+
+ const bool captureFailed =
+ QTest::qWaitFor([&] { return !fixture.m_errors.empty(); }, s_testTimeout);
+
+ QVERIFY(captureFailed);
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ QCommandLineParser cmd;
+ const QCommandLineOption showTestWidget{ QStringList{ "show" },
+ "Creates a test widget with given title",
+ "windowTitle" };
+ cmd.addOption(showTestWidget);
+ cmd.parse({ argv, argv + argc });
+
+ if (cmd.isSet(showTestWidget)) {
+ QApplication app{ argc, argv };
+ const QString windowTitle = cmd.value(showTestWidget);
+ const bool result = showCaptureWindow(windowTitle);
+ return result ? 0 : 1;
+ }
+
+ // If no special arguments are set, enter the regular QTest main routine
+ TESTLIB_SELFCOVERAGE_START("tst_QWindowCaptureatioBackend")
+ QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<tst_QWindowCaptureBackend>();
+ QApplication app(argc, argv);
+ app.setAttribute(Qt::AA_Use96Dpi, true);
+ tst_QWindowCaptureBackend tc;
+ QTEST_SET_MAIN_SOURCE_PATH return QTest::qExec(&tc, argc, argv);
+
+}
+
+#include "tst_qwindowcapturebackend.moc"
diff --git a/tests/auto/integration/qwindowcapturebackend/widget.cpp b/tests/auto/integration/qwindowcapturebackend/widget.cpp
new file mode 100644
index 000000000..b17487149
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/widget.cpp
@@ -0,0 +1,125 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "widget.h"
+#include "fixture.h"
+
+#include <qapplication.h>
+#include <qsystemsemaphore.h>
+#include <qtest.h>
+
+
+TestWidget::TestWidget(const QString &uuid, QScreen *screen)
+{
+ // Give each window a unique title so that we can uniquely identify it
+ setWindowTitle(uuid);
+
+ setScreen(screen ? screen : QApplication::primaryScreen());
+
+ // Use frameless hint because on Windows UWP platform, the window titlebar is captured,
+ // but the reference image acquired by 'QWindow::grab()' does not include titlebar.
+ // This allows us to do pixel-perfect matching of captured content.
+ setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
+ setFixedSize(60, 40);
+}
+
+void TestWidget::setDisplayPattern(Pattern p)
+{
+ m_pattern = p;
+ repaint();
+}
+
+void TestWidget::setSize(QSize size)
+{
+ if (size == QApplication::primaryScreen()->size())
+ setWindowState(Qt::WindowMaximized);
+ else
+ setFixedSize(size);
+}
+
+QImage TestWidget::grabImage()
+{
+ return grab().toImage();
+}
+
+void TestWidget::togglePattern()
+{
+ Pattern p = m_pattern == ColoredSquares ? Grid : ColoredSquares;
+ setDisplayPattern(p);
+}
+
+void TestWidget::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setPen(Qt::NoPen);
+ p.setBrush(Qt::black);
+ p.drawRect(rect());
+
+ if (m_pattern == ColoredSquares)
+ drawColoredSquares(p);
+ else
+ drawGrid(p);
+
+ p.end();
+}
+
+void TestWidget::drawColoredSquares(QPainter &p)
+{
+ const std::vector<std::vector<Qt::GlobalColor>> colors = { { Qt::red, Qt::green, Qt::blue },
+ { Qt::white, Qt::white, Qt::white },
+ { Qt::blue, Qt::green, Qt::red } };
+
+ const QSize squareSize = size() / 3;
+ QRect rect{ QPoint{ 0, 0 }, squareSize };
+
+ for (const auto &row : colors) {
+ for (const auto &color : row) {
+ p.setBrush(color);
+ p.drawRect(rect);
+ rect.moveLeft(rect.left() + rect.width());
+ }
+ rect.moveTo({ 0, rect.bottom() });
+ }
+}
+
+void TestWidget::drawGrid(QPainter &p) const
+{
+ const QSize winSize = size();
+
+ p.setPen(Qt::white);
+
+ QLine vertical{ QPoint{ 5, 0 }, QPoint{ 5, winSize.height() } };
+ while (vertical.x1() < winSize.width()) {
+ p.drawLine(vertical);
+ vertical.translate(10, 0);
+ }
+ QLine horizontal{ QPoint{ 0, 5 }, QPoint{ winSize.width(), 5 } };
+ while (horizontal.y1() < winSize.height()) {
+ p.drawLine(horizontal);
+ horizontal.translate(0, 10);
+ }
+}
+
+bool showCaptureWindow(const QString &windowTitle)
+{
+ const QNativeIpcKey key{ windowTitle };
+ QSystemSemaphore windowVisible(key);
+
+ TestWidget widget{ windowTitle };
+ widget.show();
+
+ // Wait for window to be visible and suitable for window capturing
+ const bool result = QTest::qWaitForWindowExposed(&widget, s_testTimeout.count());
+ if (!result)
+ qDebug() << "Failed to show window";
+
+ // Signal to host process that the window is visible
+ windowVisible.release();
+
+ // Keep window visible until a termination signal is received
+ QApplication::exec();
+
+ return result;
+}
+
+#include "moc_widget.cpp"
diff --git a/tests/auto/integration/qwindowcapturebackend/widget.h b/tests/auto/integration/qwindowcapturebackend/widget.h
new file mode 100644
index 000000000..56427a566
--- /dev/null
+++ b/tests/auto/integration/qwindowcapturebackend/widget.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef WINDOW_CAPTURE_WIDGET_H
+#define WINDOW_CAPTURE_WIDGET_H
+
+#include <qwidget.h>
+#include <qscreen.h>
+#include <qpainter.h>
+#include <quuid.h>
+
+/*!
+ Window capable of drawing test patterns used for capture tests
+ */
+class TestWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ enum Pattern { ColoredSquares, Grid };
+
+ TestWidget(const QString &uuid = QUuid::createUuid().toString(), QScreen *screen = nullptr);
+
+ void setDisplayPattern(Pattern p);
+ void setSize(QSize size);
+ QImage grabImage();
+
+public slots:
+ void togglePattern();
+
+protected:
+ void paintEvent(QPaintEvent *) override;
+
+private:
+ void drawColoredSquares(QPainter &p);
+ void drawGrid(QPainter &p) const;
+
+ Pattern m_pattern = ColoredSquares;
+};
+
+bool showCaptureWindow(const QString &windowTitle);
+
+#endif
diff --git a/tests/auto/integration/shared/mediabackendutils.h b/tests/auto/integration/shared/mediabackendutils.h
new file mode 100644
index 000000000..b1fa30bb2
--- /dev/null
+++ b/tests/auto/integration/shared/mediabackendutils.h
@@ -0,0 +1,69 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MEDIABACKENDUTILS_H
+#define MEDIABACKENDUTILS_H
+
+#include <QtTest/qtestcase.h>
+#include <private/qplatformmediaintegration_p.h>
+
+inline bool isGStreamerPlatform()
+{
+ return QPlatformMediaIntegration::instance()->name() == "gstreamer";
+}
+
+inline bool isQNXPlatform()
+{
+ return QPlatformMediaIntegration::instance()->name() == "qnx";
+}
+
+inline bool isDarwinPlatform()
+{
+ return QPlatformMediaIntegration::instance()->name() == "darwin";
+}
+
+inline bool isAndroidPlatform()
+{
+ return QPlatformMediaIntegration::instance()->name() == "android";
+}
+
+inline bool isFFMPEGPlatform()
+{
+ return QPlatformMediaIntegration::instance()->name() == "ffmpeg";
+}
+
+inline bool isWindowsPlatform()
+{
+ return QPlatformMediaIntegration::instance()->name() == "windows";
+}
+
+inline bool isCI()
+{
+ return qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci";
+}
+
+#define QSKIP_GSTREAMER(message) \
+ do { \
+ if (isGStreamerPlatform()) \
+ QSKIP(message); \
+ } while (0)
+
+#define QSKIP_IF_NOT_FFMPEG() \
+ do { \
+ if (!isFFMPEGPlatform()) \
+ QSKIP("Feature is only supported on FFmpeg"); \
+ } while (0)
+
+#define QSKIP_FFMPEG(message) \
+ do { \
+ if (isFFMPEGPlatform()) \
+ QSKIP(message); \
+ } while (0)
+
+#define QEXPECT_FAIL_GSTREAMER(dataIndex, comment, mode) \
+ do { \
+ if (isGStreamerPlatform()) \
+ QEXPECT_FAIL(dataIndex, comment, mode); \
+ } while (0)
+
+#endif // MEDIABACKENDUTILS_H
diff --git a/tests/auto/integration/shared/mediafileselector.h b/tests/auto/integration/shared/mediafileselector.h
index 8a9c3e86a..aa192f3e9 100644
--- a/tests/auto/integration/shared/mediafileselector.h
+++ b/tests/auto/integration/shared/mediafileselector.h
@@ -1,75 +1,179 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MEDIAFILESELECTOR_H
#define MEDIAFILESELECTOR_H
#include <QUrl>
-#include <QMediaPlayer>
-#include <QAudioOutput>
+#include <qmediaplayer.h>
+#include <qaudiooutput.h>
+#include <qvideosink.h>
#include <qsignalspy.h>
#include <qfileinfo.h>
#include <qtest.h>
+#include <private/qmultimediautils_p.h>
+
+#include <unordered_map>
QT_BEGIN_NAMESPACE
-namespace MediaFileSelector {
+using MaybeUrl = QMaybe<QUrl, QString>;
+
+#define CHECK_SELECTED_URL(maybeUrl) \
+ if (!maybeUrl) \
+ QSKIP((QLatin1String("\nUnable to select none of the media candidates:\n") + maybeUrl.error()) \
+ .toLocal8Bit() \
+ .data())
-static QUrl selectMediaFile(const QStringList& mediaCandidates)
+class MediaFileSelector
{
- QMediaPlayer player;
- QAudioOutput audioOutput;
- QVideoSink videoOutput;
- player.setAudioOutput(&audioOutput);
- player.setVideoOutput(&videoOutput);
+public:
+ int failedSelectionsCount() const { return m_failedSelectionsCount; }
- QSignalSpy errorSpy(&player, SIGNAL(errorOccurred(QMediaPlayer::Error, const QString&)));
+ QString dumpErrors() const
+ {
+ QStringList failedMedias;
+ for (const auto &mediaToError : m_mediaToErrors)
+ if (!mediaToError.second.isEmpty())
+ failedMedias.emplace_back(mediaToError.first);
- for (const QString &media : mediaCandidates) {
- player.setSource(media);
- player.play();
+ failedMedias.sort();
+ return dumpErrors(failedMedias);
+ }
- for (int i = 0; i < 2000 && player.mediaStatus() != QMediaPlayer::BufferedMedia && errorSpy.isEmpty(); i+=50) {
- QTest::qWait(50);
+ template <typename... Media>
+ MaybeUrl select(Media... media)
+ {
+ return select({ std::move(nativeFileName(media))... });
+ }
+
+ MaybeUrl select(const QStringList &candidates)
+ {
+ QUrl foundUrl;
+ for (const auto &media : candidates) {
+ auto emplaceRes = m_mediaToErrors.try_emplace(media, QString());
+ if (emplaceRes.second) {
+ auto maybeUrl = selectMediaFile(media);
+ if (!maybeUrl) {
+ Q_ASSERT(!maybeUrl.error().isEmpty());
+ emplaceRes.first->second = maybeUrl.error();
+ }
+ }
+
+ if (foundUrl.isEmpty() && emplaceRes.first->second.isEmpty())
+ foundUrl = media;
}
- if (player.mediaStatus() == QMediaPlayer::BufferedMedia && errorSpy.isEmpty()) {
- return media;
+ if (!foundUrl.isEmpty())
+ return foundUrl;
+
+ ++m_failedSelectionsCount;
+ return { QUnexpect{}, dumpErrors(candidates) };
+ }
+
+private:
+ QString dumpErrors(const QStringList &medias) const
+ {
+ using namespace Qt::StringLiterals;
+ QString result;
+
+ for (const auto &media : medias) {
+ auto it = m_mediaToErrors.find(media);
+ if (it != m_mediaToErrors.end() && !it->second.isEmpty())
+ result.append("\t"_L1)
+ .append(it->first)
+ .append(": "_L1)
+ .append(it->second)
+ .append("\n"_L1);
}
- errorSpy.clear();
+
+ return result;
+ }
+
+ static MaybeUrl selectMediaFile(QString media)
+ {
+ if (qEnvironmentVariableIsSet("QTEST_SKIP_MEDIA_VALIDATION"))
+ return QUrl(media);
+
+ using namespace Qt::StringLiterals;
+
+ QAudioOutput audioOutput;
+ QVideoSink videoOutput;
+ QMediaPlayer player;
+ player.setAudioOutput(&audioOutput);
+ player.setVideoOutput(&videoOutput);
+
+ player.setSource(media);
+ player.play();
+
+ const auto waitingFinished = QTest::qWaitFor([&]() {
+ if (player.error() != QMediaPlayer::NoError)
+ return true;
+
+ switch (player.mediaStatus()) {
+ case QMediaPlayer::BufferingMedia:
+ case QMediaPlayer::BufferedMedia:
+ case QMediaPlayer::EndOfMedia:
+ case QMediaPlayer::InvalidMedia:
+ return true;
+
+ default:
+ return false;
+ }
+ });
+
+ auto enumValueToString = [](auto enumValue) {
+ return QString(QMetaEnum::fromType<decltype(enumValue)>().valueToKey(enumValue));
+ };
+
+ if (!waitingFinished)
+ return { QUnexpect{},
+ "The media got stuck in the status "_L1
+ + enumValueToString(player.mediaStatus()) };
+
+ if (player.mediaStatus() == QMediaPlayer::InvalidMedia)
+ return { QUnexpect{},
+ "Unable to load the media. Error ["_L1 + enumValueToString(player.error())
+ + " "_L1 + player.errorString() + "]"_L1 };
+
+ if (player.error() != QMediaPlayer::NoError)
+ return { QUnexpect{},
+ "Unable to start playing the media, codecs issues. Error ["_L1
+ + enumValueToString(player.error()) + " "_L1 + player.errorString()
+ + "]"_L1 };
+
+ return QUrl(media);
}
- return QUrl();
-}
+ QString nativeFileName(const QString &media)
+ {
+#ifdef Q_OS_ANDROID
+ auto it = m_nativeFiles.find(media);
+ if (it != m_nativeFiles.end())
+ return it->second->fileName();
+
+ QFile file(media);
+ if (file.open(QIODevice::ReadOnly)) {
+ m_nativeFiles.insert({ media, std::unique_ptr<QTemporaryFile>(QTemporaryFile::createNativeFile(file))});
+ return m_nativeFiles[media]->fileName();
+ }
+ qWarning() << "Failed to create temporary file";
+#endif // Q_OS_ANDROID
+
+ return media;
+ }
-} // MediaFileSelector namespace
+private:
+#ifdef Q_OS_ANDROID
+ std::unordered_map<QString, std::unique_ptr<QTemporaryFile>> m_nativeFiles;
+#endif
+ std::unordered_map<QString, QString> m_mediaToErrors;
+ int m_failedSelectionsCount = 0;
+};
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(MaybeUrl)
+
#endif
diff --git a/tests/auto/integration/shared/testvideosink.h b/tests/auto/integration/shared/testvideosink.h
new file mode 100644
index 000000000..b14c819c5
--- /dev/null
+++ b/tests/auto/integration/shared/testvideosink.h
@@ -0,0 +1,69 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TESTVIDEOSINK_H
+#define TESTVIDEOSINK_H
+
+#include <qvideosink.h>
+#include <qvideoframe.h>
+#include <qelapsedtimer.h>
+#include <qsignalspy.h>
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ This is a simple video surface which records all presented frames.
+*/
+class TestVideoSink : public QVideoSink
+{
+ Q_OBJECT
+public:
+ explicit TestVideoSink(bool storeFrames = false) : m_storeFrames(storeFrames)
+ {
+ connect(this, &QVideoSink::videoFrameChanged, this, &TestVideoSink::addVideoFrame);
+ connect(this, &QVideoSink::videoFrameChanged, this, &TestVideoSink::videoFrameChangedSync);
+ }
+
+ QVideoFrame waitForFrame()
+ {
+ QSignalSpy spy(this, &TestVideoSink::videoFrameChangedSync);
+ return spy.wait() ? spy.at(0).at(0).value<QVideoFrame>() : QVideoFrame{};
+ }
+
+ void setStoreFrames(bool storeFrames = true) { m_storeFrames = storeFrames; }
+
+private Q_SLOTS:
+ void addVideoFrame(const QVideoFrame &frame)
+ {
+ if (!m_elapsedTimer.isValid())
+ m_elapsedTimer.start();
+ else
+ m_elapsedTimer.restart();
+
+ if (m_storeFrames)
+ m_frameList.append(frame);
+
+ if (frame.isValid())
+ m_frameTimes.emplace_back(std::chrono::microseconds(frame.startTime()));
+
+ ++m_totalFrames;
+ }
+
+signals:
+ void videoFrameChangedSync(const QVideoFrame &frame);
+
+public:
+ QList<QVideoFrame> m_frameList;
+ int m_totalFrames = 0; // used instead of the list when frames are not stored
+ QElapsedTimer m_elapsedTimer;
+ using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
+ std::vector<TimePoint> m_frameTimes;
+
+private:
+ bool m_storeFrames;
+};
+
+QT_END_NAMESPACE
+
+#endif // TESTVIDEOSINK_H
diff --git a/tests/auto/runautotests.py b/tests/auto/runautotests.py
index ba277e943..d163cf98c 100755
--- a/tests/auto/runautotests.py
+++ b/tests/auto/runautotests.py
@@ -1,31 +1,6 @@
#! /usr/bin/env python
-#############################################################################
-##
-## Copyright (C) 2016 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of the build configuration tools of the Qt Toolkit.
-##
-## $QT_BEGIN_LICENSE:GPL-EXCEPT$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 3 as published by the Free Software
-## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
+# Copyright (C) 2016 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import sys;
diff --git a/tests/auto/shared/qscopedenvironmentvariable.h b/tests/auto/shared/qscopedenvironmentvariable.h
new file mode 100644
index 000000000..390dfd400
--- /dev/null
+++ b/tests/auto/shared/qscopedenvironmentvariable.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QSCOPEDENVIRONMENTVARIABLE_H
+#define QSCOPEDENVIRONMENTVARIABLE_H
+
+#include <QtCore/qbytearrayview.h>
+#include <QtCore/qtenvironmentvariables.h>
+
+struct QScopedEnvironmentVariable
+{
+ QScopedEnvironmentVariable(const QScopedEnvironmentVariable &) = delete;
+ QScopedEnvironmentVariable(QScopedEnvironmentVariable &&) = delete;
+ QScopedEnvironmentVariable &operator=(const QScopedEnvironmentVariable &) = delete;
+ QScopedEnvironmentVariable &operator=(QScopedEnvironmentVariable &&) = delete;
+
+ QScopedEnvironmentVariable(const char *envvar, QByteArrayView name) : envvar{ envvar }
+ {
+ Q_ASSERT(envvar);
+ qputenv(envvar, name);
+ };
+
+ ~QScopedEnvironmentVariable() { qunsetenv(envvar); }
+
+private:
+ const char *envvar;
+};
+
+#endif // QSCOPEDENVIRONMENTVARIABLE_H
diff --git a/tests/auto/unit/CMakeLists.txt b/tests/auto/unit/CMakeLists.txt
index d6fe98cc4..d43c29198 100644
--- a/tests/auto/unit/CMakeLists.txt
+++ b/tests/auto/unit/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from unit.pro.
add_subdirectory(mockbackend)
diff --git a/tests/auto/unit/mockbackend/CMakeLists.txt b/tests/auto/unit/mockbackend/CMakeLists.txt
index 56f2c11aa..959341366 100644
--- a/tests/auto/unit/mockbackend/CMakeLists.txt
+++ b/tests/auto/unit/mockbackend/CMakeLists.txt
@@ -1,32 +1,33 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from mockbackend.pro.
#####################################################################
-## QtMultimediaMockBackend Generic Library:
+## MockMultimediaPlugin Generic Library:
#####################################################################
-# special case begin
-add_library(QtMultimediaMockBackend INTERFACE)
-target_include_directories(QtMultimediaMockBackend INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
-target_link_libraries(QtMultimediaMockBackend INTERFACE
- Qt::Core
- Qt::Gui
- Qt::MultimediaPrivate
-)
-target_sources(QtMultimediaMockBackend INTERFACE
- qmockaudiodecoder.h
- qmockaudiooutput.h
- qmockcamera.h
- qmockimagecapture.h qmockimagecapture.cpp
- qmockmediaplayer.h
- qmockmediaencoder.h
- qmockmediacapturesession.h
- qmockvideosink.h
- qmockmediadevices.cpp
- qmockmediadevices_p.h
- qmockintegration.cpp
- qmockintegration_p.h
+qt_internal_add_plugin(MockMultimediaPlugin
+ STATIC
+ OUTPUT_NAME mockmultimediaplugin
+ PLUGIN_TYPE multimedia
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../plugins"
+ DEFAULT_IF FALSE
+ SOURCES
+ qmockaudiodecoder.cpp qmockaudiodecoder.h
+ qmockaudiooutput.h
+ qmockcamera.cpp qmockcamera.h
+ qmockimagecapture.cpp qmockimagecapture.h
+ qmockmediaplayer.h
+ qmockmediaencoder.h
+ qmockmediacapturesession.h
+ qmockvideosink.h
+ qmockmediadevices.cpp qmockmediadevices.h
+ qmockintegration.cpp qmockintegration.h
+ LIBRARIES
+ Qt::MultimediaPrivate
+ Qt::CorePrivate
)
-# special case end
#### Keys ignored in scope 1:.:.:mockbackend.pro:<TRUE>:
# TEMPLATE = "lib"
diff --git a/tests/auto/unit/mockbackend/mock.json b/tests/auto/unit/mockbackend/mock.json
new file mode 100644
index 000000000..499a3de8c
--- /dev/null
+++ b/tests/auto/unit/mockbackend/mock.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "mock" ]
+}
diff --git a/tests/auto/unit/mockbackend/qmockaudiodecoder.cpp b/tests/auto/unit/mockbackend/qmockaudiodecoder.cpp
new file mode 100644
index 000000000..3c6b940a9
--- /dev/null
+++ b/tests/auto/unit/mockbackend/qmockaudiodecoder.cpp
@@ -0,0 +1,139 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qmockaudiodecoder.h"
+
+QT_BEGIN_NAMESPACE
+
+QMockAudioDecoder::QMockAudioDecoder(QAudioDecoder *parent)
+ : QPlatformAudioDecoder(parent), mDevice(0), mPosition(-1), mSerial(0)
+{
+ mFormat.setChannelCount(1);
+ mFormat.setSampleFormat(QAudioFormat::UInt8);
+ mFormat.setSampleRate(1000);
+}
+
+QUrl QMockAudioDecoder::source() const
+{
+ return mSource;
+}
+
+void QMockAudioDecoder::setSource(const QUrl &fileName)
+{
+ mSource = fileName;
+ mDevice = 0;
+ stop();
+}
+
+QIODevice *QMockAudioDecoder::sourceDevice() const
+{
+ return mDevice;
+}
+
+void QMockAudioDecoder::setSourceDevice(QIODevice *device)
+{
+ mDevice = device;
+ mSource.clear();
+ stop();
+}
+
+QAudioFormat QMockAudioDecoder::audioFormat() const
+{
+ return mFormat;
+}
+
+void QMockAudioDecoder::setAudioFormat(const QAudioFormat &format)
+{
+ if (mFormat != format) {
+ mFormat = format;
+ formatChanged(mFormat);
+ }
+}
+
+// When decoding we decode to first buffer, then second buffer
+// we then stop until the first is read again and so on, for
+// 5 buffers
+void QMockAudioDecoder::start()
+{
+ if (!isDecoding()) {
+ if (!mSource.isEmpty()) {
+ setIsDecoding(true);
+ durationChanged(duration());
+
+ QTimer::singleShot(50, this, &QMockAudioDecoder::pretendDecode);
+ } else {
+ error(QAudioDecoder::ResourceError, "No source set");
+ }
+ }
+}
+
+void QMockAudioDecoder::stop()
+{
+ if (isDecoding()) {
+ mSerial = 0;
+ mPosition = 0;
+ mBuffers.clear();
+ setIsDecoding(false);
+ bufferAvailableChanged(false);
+ }
+}
+
+QAudioBuffer QMockAudioDecoder::read()
+{
+ QAudioBuffer a;
+ if (mBuffers.size() > 0) {
+ a = mBuffers.takeFirst();
+ mPosition = a.startTime() / 1000;
+ positionChanged(mPosition);
+
+ if (mBuffers.isEmpty())
+ bufferAvailableChanged(false);
+
+ if (mBuffers.isEmpty() && mSerial >= MOCK_DECODER_MAX_BUFFERS) {
+ finished();
+ } else
+ QTimer::singleShot(50, this, &QMockAudioDecoder::pretendDecode);
+ }
+
+ return a;
+}
+
+bool QMockAudioDecoder::bufferAvailable() const
+{
+ return mBuffers.size() > 0;
+}
+
+qint64 QMockAudioDecoder::position() const
+{
+ return mPosition;
+}
+
+qint64 QMockAudioDecoder::duration() const
+{
+ return (sizeof(mSerial) * MOCK_DECODER_MAX_BUFFERS * qint64(1000))
+ / (mFormat.sampleRate() * mFormat.channelCount());
+}
+
+void QMockAudioDecoder::pretendDecode()
+{
+ // Check if we've reached end of stream
+ if (mSerial >= MOCK_DECODER_MAX_BUFFERS)
+ return;
+
+ // We just keep the length of mBuffers to 3 or less.
+ if (mBuffers.size() < 3) {
+ QByteArray b(sizeof(mSerial), 0);
+ memcpy(b.data(), &mSerial, sizeof(mSerial));
+ qint64 position = (sizeof(mSerial) * mSerial * qint64(1000000))
+ / (mFormat.sampleRate() * mFormat.channelCount());
+ mSerial++;
+ mBuffers.push_back(QAudioBuffer(b, mFormat, position));
+ bufferReady();
+ if (mBuffers.size() == 1)
+ bufferAvailableChanged(true);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qmockaudiodecoder.cpp"
diff --git a/tests/auto/unit/mockbackend/qmockaudiodecoder.h b/tests/auto/unit/mockbackend/qmockaudiodecoder.h
index abc710ac8..89e21ef23 100644
--- a/tests/auto/unit/mockbackend/qmockaudiodecoder.h
+++ b/tests/auto/unit/mockbackend/qmockaudiodecoder.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKAUDIODECODERCONTROL_H
#define MOCKAUDIODECODERCONTROL_H
@@ -47,136 +22,37 @@ class QMockAudioDecoder : public QPlatformAudioDecoder
Q_OBJECT
public:
- QMockAudioDecoder(QAudioDecoder *parent = 0)
- : QPlatformAudioDecoder(parent)
- , mDevice(0)
- , mPosition(-1)
- , mSerial(0)
- {
- mFormat.setChannelCount(1);
- mFormat.setSampleFormat(QAudioFormat::UInt8);
- mFormat.setSampleRate(1000);
- }
-
- QUrl source() const override
- {
- return mSource;
- }
-
- void setSource(const QUrl &fileName) override
- {
- mSource = fileName;
- mDevice = 0;
- stop();
- }
-
- QIODevice* sourceDevice() const override
- {
- return mDevice;
- }
-
- void setSourceDevice(QIODevice *device) override
- {
- mDevice = device;
- mSource.clear();
- stop();
- }
-
- QAudioFormat audioFormat() const override
- {
- return mFormat;
- }
-
- void setAudioFormat(const QAudioFormat &format) override
- {
- if (mFormat != format) {
- mFormat = format;
- emit formatChanged(mFormat);
- }
- }
+ QMockAudioDecoder(QAudioDecoder *parent = nullptr);
+
+ QUrl source() const override;
+
+ void setSource(const QUrl &fileName) override;
+
+ QIODevice *sourceDevice() const override;
+
+ void setSourceDevice(QIODevice *device) override;
+
+ QAudioFormat audioFormat() const override;
+
+ void setAudioFormat(const QAudioFormat &format) override;
// When decoding we decode to first buffer, then second buffer
// we then stop until the first is read again and so on, for
// 5 buffers
- void start() override
- {
- if (!isDecoding()) {
- if (!mSource.isEmpty()) {
- setIsDecoding(true);
- emit durationChanged(duration());
-
- QTimer::singleShot(50, this, SLOT(pretendDecode()));
- } else {
- emit error(QAudioDecoder::ResourceError, "No source set");
- }
- }
- }
-
- void stop() override
- {
- if (isDecoding()) {
- mSerial = 0;
- mPosition = 0;
- mBuffers.clear();
- setIsDecoding(false);
- emit bufferAvailableChanged(false);
- }
- }
-
- QAudioBuffer read() override
- {
- QAudioBuffer a;
- if (mBuffers.length() > 0) {
- a = mBuffers.takeFirst();
- mPosition = a.startTime() / 1000;
- positionChanged(mPosition);
-
- if (mBuffers.isEmpty())
- emit bufferAvailableChanged(false);
-
- if (mBuffers.isEmpty() && mSerial >= MOCK_DECODER_MAX_BUFFERS) {
- emit finished();
- } else
- QTimer::singleShot(50, this, SLOT(pretendDecode()));
- }
-
- return a;
- }
-
- bool bufferAvailable() const override
- {
- return mBuffers.length() > 0;
- }
-
- qint64 position() const override
- {
- return mPosition;
- }
-
- qint64 duration() const override
- {
- return (sizeof(mSerial) * MOCK_DECODER_MAX_BUFFERS * qint64(1000)) / (mFormat.sampleRate() * mFormat.channelCount());
- }
+ void start() override;
+
+ void stop() override;
+
+ QAudioBuffer read() override;
+
+ bool bufferAvailable() const override;
+
+ qint64 position() const override;
+
+ qint64 duration() const override;
private slots:
- void pretendDecode()
- {
- // Check if we've reached end of stream
- if (mSerial >= MOCK_DECODER_MAX_BUFFERS)
- return;
-
- // We just keep the length of mBuffers to 3 or less.
- if (mBuffers.length() < 3) {
- QByteArray b(sizeof(mSerial), 0);
- memcpy(b.data(), &mSerial, sizeof(mSerial));
- qint64 position = (sizeof(mSerial) * mSerial * qint64(1000000)) / (mFormat.sampleRate() * mFormat.channelCount());
- mSerial++;
- mBuffers.push_back(QAudioBuffer(b, mFormat, position));
- emit bufferReady();
- if (mBuffers.count() == 1)
- emit bufferAvailableChanged(true);
- }
- }
+ void pretendDecode();
public:
QUrl mSource;
diff --git a/tests/auto/unit/mockbackend/qmockaudiooutput.h b/tests/auto/unit/mockbackend/qmockaudiooutput.h
index 30cc46604..a35fc8fe4 100644
--- a/tests/auto/unit/mockbackend/qmockaudiooutput.h
+++ b/tests/auto/unit/mockbackend/qmockaudiooutput.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QMOCKAUDIOOUTPUT_H
#define QMOCKAUDIOOUTPUT_H
diff --git a/tests/auto/unit/mockbackend/qmockcamera.cpp b/tests/auto/unit/mockbackend/qmockcamera.cpp
new file mode 100644
index 000000000..23ecc36ae
--- /dev/null
+++ b/tests/auto/unit/mockbackend/qmockcamera.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qmockcamera.h"
+
+QT_BEGIN_NAMESPACE
+
+QMockCamera::QMockCamera(QCamera *parent)
+ : QPlatformCamera(parent), m_propertyChangesSupported(false)
+{
+ if (!simpleCamera) {
+ minIsoChanged(100);
+ maxIsoChanged(800);
+ minExposureTimeChanged(.001f);
+ maxExposureTimeChanged(1.f);
+ exposureCompensationRangeChanged(-2, 2);
+ maximumZoomFactorChanged(4.);
+ setFlashMode(QCamera::FlashAuto);
+ }
+}
+
+QMockCamera::~QMockCamera() { }
+
+bool QMockCamera::isActive() const
+{
+ return m_active;
+}
+
+void QMockCamera::setActive(bool active)
+{
+ if (m_active == active)
+ return;
+ m_active = active;
+ emit activeChanged(active);
+}
+
+void QMockCamera::setCamera(const QCameraDevice &camera)
+{
+ m_camera = camera;
+}
+
+bool QMockCamera::setCameraFormat(const QCameraFormat &format)
+{
+ if (!format.isNull() && !m_camera.videoFormats().contains(format))
+ return false;
+ return true;
+}
+
+void QMockCamera::setFocusMode(QCamera::FocusMode mode)
+{
+ if (isFocusModeSupported(mode))
+ focusModeChanged(mode);
+}
+
+bool QMockCamera::isFocusModeSupported(QCamera::FocusMode mode) const
+{
+ return simpleCamera ? mode == QCamera::FocusModeAuto : mode != QCamera::FocusModeInfinity;
+}
+
+void QMockCamera::setCustomFocusPoint(const QPointF &point)
+{
+ if (!simpleCamera)
+ customFocusPointChanged(point);
+}
+
+void QMockCamera::setFocusDistance(float d)
+{
+ if (!simpleCamera)
+ focusDistanceChanged(d);
+}
+
+void QMockCamera::zoomTo(float newZoomFactor, float /*rate*/)
+{
+ zoomFactorChanged(newZoomFactor);
+}
+
+void QMockCamera::setFlashMode(QCamera::FlashMode mode)
+{
+ if (!simpleCamera)
+ flashModeChanged(mode);
+ flashReadyChanged(mode != QCamera::FlashOff);
+}
+bool QMockCamera::isFlashModeSupported(QCamera::FlashMode mode) const
+{
+ return simpleCamera ? mode == QCamera::FlashOff : true;
+}
+
+bool QMockCamera::isFlashReady() const
+{
+ return flashMode() != QCamera::FlashOff;
+}
+
+void QMockCamera::setExposureMode(QCamera::ExposureMode mode)
+{
+ if (!simpleCamera && isExposureModeSupported(mode))
+ exposureModeChanged(mode);
+}
+
+bool QMockCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
+{
+ return simpleCamera ? mode == QCamera::ExposureAuto : mode <= QCamera::ExposureBeach;
+}
+
+void QMockCamera::setExposureCompensation(float c)
+{
+ if (!simpleCamera)
+ exposureCompensationChanged(qBound(-2., c, 2.));
+}
+
+int QMockCamera::isoSensitivity() const
+{
+ if (simpleCamera)
+ return -1;
+ return manualIsoSensitivity() > 0 ? manualIsoSensitivity() : 100;
+}
+
+void QMockCamera::setManualIsoSensitivity(int iso)
+{
+ if (!simpleCamera)
+ isoSensitivityChanged(qBound(100, iso, 800));
+}
+
+void QMockCamera::setManualExposureTime(float secs)
+{
+ if (!simpleCamera)
+ exposureTimeChanged(qBound(0.001, secs, 1.));
+}
+
+float QMockCamera::exposureTime() const
+{
+ if (simpleCamera)
+ return -1.;
+ return manualExposureTime() > 0 ? manualExposureTime() : .05;
+}
+
+bool QMockCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
+{
+ if (simpleCamera)
+ return mode == QCamera::WhiteBalanceAuto;
+ return mode == QCamera::WhiteBalanceAuto || mode == QCamera::WhiteBalanceManual
+ || mode == QCamera::WhiteBalanceSunlight;
+}
+
+void QMockCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
+{
+ if (isWhiteBalanceModeSupported(mode))
+ whiteBalanceModeChanged(mode);
+}
+
+void QMockCamera::setColorTemperature(int temperature)
+{
+ if (!simpleCamera)
+ colorTemperatureChanged(temperature);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qmockcamera.cpp"
diff --git a/tests/auto/unit/mockbackend/qmockcamera.h b/tests/auto/unit/mockbackend/qmockcamera.h
index 69251e1a6..3d8159e84 100644
--- a/tests/auto/unit/mockbackend/qmockcamera.h
+++ b/tests/auto/unit/mockbackend/qmockcamera.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QMOCKCAMERA_H
#define QMOCKCAMERA_H
@@ -48,135 +23,53 @@ public:
~Simple() { simpleCamera = false; }
};
- QMockCamera(QCamera *parent)
- : QPlatformCamera(parent),
- m_propertyChangesSupported(false)
- {
- if (!simpleCamera) {
- minIsoChanged(100);
- maxIsoChanged(800);
- minExposureTimeChanged(.001f);
- maxExposureTimeChanged(1.f);
- exposureCompensationRangeChanged(-2, 2);
- maximumZoomFactorChanged(4.);
- setFlashMode(QCamera::FlashAuto);
- }
- }
-
- ~QMockCamera() {}
-
- bool isActive() const override { return m_active; }
- void setActive(bool active) override {
- if (m_active == active)
- return;
- m_active = active;
- emit activeChanged(active);
- }
-
- /* helper method to emit the signal error */
- void setError(QCamera::Error err, QString errorString)
- {
- emit error(err, errorString);
- }
-
- void setCamera(const QCameraDevice &camera) override
- {
- m_camera = camera;
- }
-
- bool setCameraFormat(const QCameraFormat& format) override
- {
- if (!format.isNull() && !m_camera.videoFormats().contains(format))
- return false;
- return true;
- }
-
- void setFocusMode(QCamera::FocusMode mode) override
- {
- if (isFocusModeSupported(mode))
- focusModeChanged(mode);
- }
- bool isFocusModeSupported(QCamera::FocusMode mode) const override
- { return simpleCamera ? mode == QCamera::FocusModeAuto : mode != QCamera::FocusModeInfinity; }
-
- void setCustomFocusPoint(const QPointF &point) override
- {
- if (!simpleCamera)
- customFocusPointChanged(point);
- }
-
- void setFocusDistance(float d) override
- {
- if (!simpleCamera)
- focusDistanceChanged(d);
- }
-
- void zoomTo(float newZoomFactor, float /*rate*/) override { zoomFactorChanged(newZoomFactor); }
-
- void setFlashMode(QCamera::FlashMode mode) override
- {
- if (!simpleCamera)
- flashModeChanged(mode);
- flashReadyChanged(mode != QCamera::FlashOff);
- }
- bool isFlashModeSupported(QCamera::FlashMode mode) const override { return simpleCamera ? mode == QCamera::FlashOff : true; }
- bool isFlashReady() const override { return flashMode() != QCamera::FlashOff; }
-
- void setExposureMode(QCamera::ExposureMode mode) override
- {
- if (!simpleCamera && isExposureModeSupported(mode))
- exposureModeChanged(mode);
- }
- bool isExposureModeSupported(QCamera::ExposureMode mode) const override
- {
- return simpleCamera ? mode == QCamera::ExposureAuto : mode <= QCamera::ExposureBeach;
- }
- void setExposureCompensation(float c) override
- {
- if (!simpleCamera)
- exposureCompensationChanged(qBound(-2., c, 2.));
- }
- int isoSensitivity() const override
- {
- if (simpleCamera)
- return -1;
- return manualIsoSensitivity() > 0 ? manualIsoSensitivity() : 100;
- }
- void setManualIsoSensitivity(int iso) override
- {
- if (!simpleCamera)
- isoSensitivityChanged(qBound(100, iso, 800));
- }
- void setManualExposureTime(float secs) override
- {
- if (!simpleCamera)
- exposureTimeChanged(qBound(0.001, secs, 1.));
- }
- float exposureTime() const override
- {
- if (simpleCamera)
- return -1.;
- return manualExposureTime() > 0 ? manualExposureTime() : .05;
- }
-
- bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override
- {
- if (simpleCamera)
- return mode == QCamera::WhiteBalanceAuto;
- return mode == QCamera::WhiteBalanceAuto ||
- mode == QCamera::WhiteBalanceManual ||
- mode == QCamera::WhiteBalanceSunlight;
- }
- void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override
- {
- if (isWhiteBalanceModeSupported(mode))
- whiteBalanceModeChanged(mode);
- }
- void setColorTemperature(int temperature) override
- {
- if (!simpleCamera)
- colorTemperatureChanged(temperature);
- }
+ QMockCamera(QCamera *parent);
+
+ ~QMockCamera() override;
+
+ bool isActive() const override;
+
+ void setActive(bool active) override;
+
+ void setCamera(const QCameraDevice &camera) override;
+
+ bool setCameraFormat(const QCameraFormat &format) override;
+
+ void setFocusMode(QCamera::FocusMode mode) override;
+
+ bool isFocusModeSupported(QCamera::FocusMode mode) const override;
+
+ void setCustomFocusPoint(const QPointF &point) override;
+
+ void setFocusDistance(float d) override;
+
+ void zoomTo(float newZoomFactor, float /*rate*/) override;
+
+ void setFlashMode(QCamera::FlashMode mode) override;
+
+ bool isFlashModeSupported(QCamera::FlashMode mode) const override;
+
+ bool isFlashReady() const override;
+
+ void setExposureMode(QCamera::ExposureMode mode) override;
+
+ bool isExposureModeSupported(QCamera::ExposureMode mode) const override;
+
+ void setExposureCompensation(float c) override;
+
+ int isoSensitivity() const override;
+
+ void setManualIsoSensitivity(int iso) override;
+
+ void setManualExposureTime(float secs) override;
+
+ float exposureTime() const override;
+
+ bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override;
+
+ void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override;
+
+ void setColorTemperature(int temperature) override;
bool m_active = false;
QCameraDevice m_camera;
diff --git a/tests/auto/unit/mockbackend/qmockimagecapture.cpp b/tests/auto/unit/mockbackend/qmockimagecapture.cpp
index 9e2396113..96e53b2f4 100644
--- a/tests/auto/unit/mockbackend/qmockimagecapture.cpp
+++ b/tests/auto/unit/mockbackend/qmockimagecapture.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qmockimagecapture.h>
#include <qmockcamera.h>
@@ -32,6 +7,8 @@
#include <qimagecapture.h>
#include <qcamera.h>
+QT_BEGIN_NAMESPACE
+
QMockImageCapture::QMockImageCapture(QImageCapture *parent)
: QPlatformImageCapture(parent)
{
@@ -48,7 +25,7 @@ int QMockImageCapture::capture(const QString &fileName)
m_fileName = fileName;
m_captureRequest++;
emit readyForCaptureChanged(m_ready = false);
- QTimer::singleShot(5, this, SLOT(captured()));
+ QTimer::singleShot(5, this, &QMockImageCapture::captured);
return m_captureRequest;
} else {
emit error(-1, QImageCapture::NotReadyError,
@@ -63,7 +40,7 @@ void QMockImageCapture::captured()
emit imageCaptured(m_captureRequest, QImage());
QMediaMetaData metaData;
- metaData.insert(QMediaMetaData::Author, QString::fromUtf8("Author"));
+ metaData.insert(QMediaMetaData::Author, QStringLiteral("Author"));
metaData.insert(QMediaMetaData::Date, QDateTime(QDate(2021, 1, 1), QTime()));
emit imageMetadataAvailable(m_captureRequest, metaData);
@@ -76,3 +53,7 @@ void QMockImageCapture::captured()
emit imageSaved(m_captureRequest, m_fileName);
}
+
+QT_END_NAMESPACE
+
+#include "moc_qmockimagecapture.cpp"
diff --git a/tests/auto/unit/mockbackend/qmockimagecapture.h b/tests/auto/unit/mockbackend/qmockimagecapture.h
index 8d7cea1a4..376f53cbc 100644
--- a/tests/auto/unit/mockbackend/qmockimagecapture.h
+++ b/tests/auto/unit/mockbackend/qmockimagecapture.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QMOCKCAMERAIMAGECAPTURE_H
#define QMOCKCAMERAIMAGECAPTURE_H
diff --git a/tests/auto/unit/mockbackend/qmockintegration.cpp b/tests/auto/unit/mockbackend/qmockintegration.cpp
index da4ac787f..b554b31e0 100644
--- a/tests/auto/unit/mockbackend/qmockintegration.cpp
+++ b/tests/auto/unit/mockbackend/qmockintegration.cpp
@@ -1,43 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qmockintegration_p.h"
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtMultimedia/private/qplatformmediaplugin_p.h>
+#include "qmockintegration.h"
#include "qmockmediaplayer.h"
#include "qmockaudiodecoder.h"
#include "qmockcamera.h"
@@ -45,20 +10,106 @@
#include "qmockvideosink.h"
#include "qmockimagecapture.h"
#include "qmockaudiooutput.h"
+#include "qmocksurfacecapture.h"
+#include <private/qcameradevice_p.h>
+#include <private/qplatformvideodevices_p.h>
+
+#include "qmockmediadevices.h"
QT_BEGIN_NAMESPACE
-QMockIntegration::QMockIntegration()
+class MockMultimediaPlugin : public QPlatformMediaPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QPlatformMediaPlugin_iid FILE "mock.json")
+
+public:
+ MockMultimediaPlugin() : QPlatformMediaPlugin() { }
+
+ QPlatformMediaIntegration *create(const QString &name) override
+ {
+ if (name == QLatin1String("mock"))
+ return new QMockIntegration;
+ return nullptr;
+ }
+};
+
+class QMockVideoDevices : public QPlatformVideoDevices
{
- setIntegration(this);
+public:
+ QMockVideoDevices(QPlatformMediaIntegration *pmi)
+ : QPlatformVideoDevices(pmi)
+ {
+ QCameraDevicePrivate *info = new QCameraDevicePrivate;
+ info->description = QStringLiteral("defaultCamera");
+ info->id = "default";
+ info->isDefault = true;
+ auto *f = new QCameraFormatPrivate{
+ QSharedData(),
+ QVideoFrameFormat::Format_ARGB8888,
+ QSize(640, 480),
+ 0,
+ 30
+ };
+ info->videoFormats << f->create();
+ m_cameraDevices.append(info->create());
+ info = new QCameraDevicePrivate;
+ info->description = QStringLiteral("frontCamera");
+ info->id = "front";
+ info->isDefault = false;
+ info->position = QCameraDevice::FrontFace;
+ f = new QCameraFormatPrivate{
+ QSharedData(),
+ QVideoFrameFormat::Format_XRGB8888,
+ QSize(1280, 720),
+ 0,
+ 30
+ };
+ info->videoFormats << f->create();
+ m_cameraDevices.append(info->create());
+ info = new QCameraDevicePrivate;
+ info->description = QStringLiteral("backCamera");
+ info->id = "back";
+ info->isDefault = false;
+ info->position = QCameraDevice::BackFace;
+ m_cameraDevices.append(info->create());
+ }
+
+ void addNewCamera()
+ {
+ auto info = new QCameraDevicePrivate;
+ info->description = QLatin1String("newCamera") + QString::number(m_cameraDevices.size());
+ info->id =
+ QString(QLatin1String("camera") + QString::number(m_cameraDevices.size())).toUtf8();
+ info->isDefault = false;
+ m_cameraDevices.append(info->create());
+
+ emit videoInputsChanged();
+ }
+
+ QList<QCameraDevice> videoDevices() const override
+ {
+ return m_cameraDevices;
+ }
+
+private:
+ QList<QCameraDevice> m_cameraDevices;
+};
+
+QMockIntegration::QMockIntegration() : QPlatformMediaIntegration(QLatin1String("mock")) { }
+QMockIntegration::~QMockIntegration() = default;
+
+QPlatformVideoDevices *QMockIntegration::createVideoDevices()
+{
+ return new QMockVideoDevices(this);
}
-QMockIntegration::~QMockIntegration()
+std::unique_ptr<QPlatformMediaDevices> QMockIntegration::createMediaDevices()
{
- setIntegration(nullptr);
+ return std::make_unique<QMockMediaDevices>();
}
-QPlatformAudioDecoder *QMockIntegration::createAudioDecoder(QAudioDecoder *decoder)
+QMaybe<QPlatformAudioDecoder *> QMockIntegration::createAudioDecoder(QAudioDecoder *decoder)
{
if (m_flags & NoAudioDecoderInterface)
m_lastAudioDecoderControl = nullptr;
@@ -67,7 +118,7 @@ QPlatformAudioDecoder *QMockIntegration::createAudioDecoder(QAudioDecoder *decod
return m_lastAudioDecoderControl;
}
-QPlatformMediaPlayer *QMockIntegration::createPlayer(QMediaPlayer *parent)
+QMaybe<QPlatformMediaPlayer *> QMockIntegration::createPlayer(QMediaPlayer *parent)
{
if (m_flags & NoPlayerInterface)
m_lastPlayer = nullptr;
@@ -76,7 +127,7 @@ QPlatformMediaPlayer *QMockIntegration::createPlayer(QMediaPlayer *parent)
return m_lastPlayer;
}
-QPlatformCamera *QMockIntegration::createCamera(QCamera *parent)
+QMaybe<QPlatformCamera *> QMockIntegration::createCamera(QCamera *parent)
{
if (m_flags & NoCaptureInterface)
m_lastCamera = nullptr;
@@ -85,17 +136,37 @@ QPlatformCamera *QMockIntegration::createCamera(QCamera *parent)
return m_lastCamera;
}
-QPlatformImageCapture *QMockIntegration::createImageCapture(QImageCapture *capture)
+QMaybe<QPlatformImageCapture *> QMockIntegration::createImageCapture(QImageCapture *capture)
{
return new QMockImageCapture(capture);
}
-QPlatformMediaRecorder *QMockIntegration::createRecorder(QMediaRecorder *recorder)
+QMaybe<QPlatformMediaRecorder *> QMockIntegration::createRecorder(QMediaRecorder *recorder)
{
return new QMockMediaEncoder(recorder);
}
-QPlatformMediaCaptureSession *QMockIntegration::createCaptureSession()
+QPlatformSurfaceCapture *QMockIntegration::createScreenCapture(QScreenCapture * /*capture*/)
+{
+ if (m_flags & NoCaptureInterface)
+ m_lastScreenCapture = nullptr;
+ else
+ m_lastScreenCapture = new QMockSurfaceCapture(QPlatformSurfaceCapture::ScreenSource{});
+
+ return m_lastScreenCapture;
+}
+
+QPlatformSurfaceCapture *QMockIntegration::createWindowCapture(QWindowCapture *)
+{
+ if (m_flags & NoCaptureInterface)
+ m_lastWindowCapture = nullptr;
+ else
+ m_lastWindowCapture = new QMockSurfaceCapture(QPlatformSurfaceCapture::WindowSource{});
+
+ return m_lastWindowCapture;
+}
+
+QMaybe<QPlatformMediaCaptureSession *> QMockIntegration::createCaptureSession()
{
if (m_flags & NoCaptureInterface)
m_lastCaptureService = nullptr;
@@ -104,17 +175,24 @@ QPlatformMediaCaptureSession *QMockIntegration::createCaptureSession()
return m_lastCaptureService;
}
-QPlatformVideoSink *QMockIntegration::createVideoSink(QVideoSink *sink)
+QMaybe<QPlatformVideoSink *> QMockIntegration::createVideoSink(QVideoSink *sink)
{
m_lastVideoSink = new QMockVideoSink(sink);
return m_lastVideoSink;
}
-QPlatformAudioOutput *QMockIntegration::createAudioOutput(QAudioOutput *q)
+QMaybe<QPlatformAudioOutput *> QMockIntegration::createAudioOutput(QAudioOutput *q)
{
return new QMockAudioOutput(q);
}
+void QMockIntegration::addNewCamera()
+{
+ static_cast<QMockVideoDevices *>(videoDevices())->addNewCamera();
+}
+
bool QMockCamera::simpleCamera = false;
QT_END_NAMESPACE
+
+#include "qmockintegration.moc"
diff --git a/tests/auto/unit/mockbackend/qmockintegration.h b/tests/auto/unit/mockbackend/qmockintegration.h
new file mode 100644
index 000000000..20b61721c
--- /dev/null
+++ b/tests/auto/unit/mockbackend/qmockintegration.h
@@ -0,0 +1,103 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QMOCKINTEGRATION_H
+#define QMOCKINTEGRATION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediaintegration_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMockMediaPlayer;
+class QMockAudioDecoder;
+class QMockCamera;
+class QMockMediaCaptureSession;
+class QMockVideoSink;
+class QMockSurfaceCapture;
+
+class QMockIntegration : public QPlatformMediaIntegration
+{
+public:
+ QMockIntegration();
+ ~QMockIntegration();
+
+ static QMockIntegration *instance()
+ {
+ return static_cast<QMockIntegration *>(QPlatformMediaIntegration::instance());
+ }
+
+ QMaybe<QPlatformAudioDecoder *> createAudioDecoder(QAudioDecoder *decoder) override;
+ QMaybe<QPlatformMediaPlayer *> createPlayer(QMediaPlayer *) override;
+ QMaybe<QPlatformCamera *> createCamera(QCamera *) override;
+ QMaybe<QPlatformMediaRecorder *> createRecorder(QMediaRecorder *) override;
+ QMaybe<QPlatformImageCapture *> createImageCapture(QImageCapture *) override;
+ QMaybe<QPlatformMediaCaptureSession *> createCaptureSession() override;
+ QMaybe<QPlatformVideoSink *> createVideoSink(QVideoSink *) override;
+
+ QMaybe<QPlatformAudioOutput *> createAudioOutput(QAudioOutput *) override;
+
+ QPlatformSurfaceCapture *createScreenCapture(QScreenCapture *) override;
+ QPlatformSurfaceCapture *createWindowCapture(QWindowCapture *) override;
+
+ void addNewCamera();
+
+ enum Flag { NoPlayerInterface = 0x1, NoAudioDecoderInterface = 0x2, NoCaptureInterface = 0x4 };
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ void setFlags(Flags f) { m_flags = f; }
+ Flags flags() const { return m_flags; }
+
+ QMockMediaPlayer *lastPlayer() const { return m_lastPlayer; }
+ QMockAudioDecoder *lastAudioDecoder() const { return m_lastAudioDecoderControl; }
+ QMockCamera *lastCamera() const { return m_lastCamera; }
+ // QMockMediaEncoder *lastEncoder const { return m_lastEncoder; }
+ QMockMediaCaptureSession *lastCaptureService() const { return m_lastCaptureService; }
+ QMockVideoSink *lastVideoSink() const { return m_lastVideoSink; }
+ QMockSurfaceCapture *lastScreenCapture() { return m_lastScreenCapture; }
+ QMockSurfaceCapture *lastWindowCapture() { return m_lastWindowCapture; }
+
+protected:
+ QPlatformVideoDevices *createVideoDevices() override;
+ std::unique_ptr<QPlatformMediaDevices> createMediaDevices() override;
+
+private:
+
+ Flags m_flags = {};
+ QMockMediaPlayer *m_lastPlayer = nullptr;
+ QMockAudioDecoder *m_lastAudioDecoderControl = nullptr;
+ QMockCamera *m_lastCamera = nullptr;
+ // QMockMediaEncoder *m_lastEncoder = nullptr;
+ QMockMediaCaptureSession *m_lastCaptureService = nullptr;
+ QMockVideoSink *m_lastVideoSink = nullptr;
+ QMockSurfaceCapture *m_lastScreenCapture = nullptr;
+ QMockSurfaceCapture *m_lastWindowCapture = nullptr;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMockIntegration::Flags);
+
+#define Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN \
+ Q_IMPORT_PLUGIN(MockMultimediaPlugin) \
+ struct EnableMockPlugin \
+ { \
+ EnableMockPlugin() \
+ { \
+ qputenv("QT_MEDIA_BACKEND", "mock"); \
+ } \
+ }; \
+ static EnableMockPlugin s_mockMultimediaPluginEnabler;
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tests/auto/unit/mockbackend/qmockintegration_p.h b/tests/auto/unit/mockbackend/qmockintegration_p.h
deleted file mode 100644
index f5a6d167e..000000000
--- a/tests/auto/unit/mockbackend/qmockintegration_p.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QMOCKINTEGRATION_H
-#define QMOCKINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QMockMediaPlayer;
-class QMockAudioDecoder;
-class QMockCamera;
-class QMockMediaCaptureSession;
-class QMockVideoSink;
-
-class QMockIntegration : public QPlatformMediaIntegration
-{
-public:
- QMockIntegration();
- ~QMockIntegration();
-
- QPlatformMediaFormatInfo *formatInfo() override { return nullptr; }
-
- QPlatformAudioDecoder *createAudioDecoder(QAudioDecoder *decoder) override;
- QPlatformMediaPlayer *createPlayer(QMediaPlayer *) override;
- QPlatformCamera *createCamera(QCamera *) override;
- QPlatformMediaRecorder *createRecorder(QMediaRecorder *) override;
- QPlatformImageCapture *createImageCapture(QImageCapture *) override;
- QPlatformMediaCaptureSession *createCaptureSession() override;
- QPlatformVideoSink *createVideoSink(QVideoSink *) override;
-
- QPlatformAudioOutput *createAudioOutput(QAudioOutput *) override;
-
- enum Flag {
- NoPlayerInterface = 0x1,
- NoAudioDecoderInterface = 0x2,
- NoCaptureInterface = 0x4
- };
- Q_DECLARE_FLAGS(Flags, Flag);
-
- void setFlags(Flags f) { m_flags = f; }
- Flags flags() const { return m_flags; }
-
- QMockMediaPlayer *lastPlayer() const { return m_lastPlayer; }
- QMockAudioDecoder *lastAudioDecoder() const { return m_lastAudioDecoderControl; }
- QMockCamera *lastCamera() const { return m_lastCamera; }
- // QMockMediaEncoder *lastEncoder const { return m_lastEncoder; }
- QMockMediaCaptureSession *lastCaptureService() const { return m_lastCaptureService; }
- QMockVideoSink *lastVideoSink() const { return m_lastVideoSink; }
-
-private:
- Flags m_flags = {};
- QMockMediaPlayer *m_lastPlayer = nullptr;
- QMockAudioDecoder *m_lastAudioDecoderControl = nullptr;
- QMockCamera *m_lastCamera = nullptr;
- // QMockMediaEncoder *m_lastEncoder = nullptr;
- QMockMediaCaptureSession *m_lastCaptureService = nullptr;
- QMockVideoSink *m_lastVideoSink;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QMockIntegration::Flags);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/tests/auto/unit/mockbackend/qmockmediacapturesession.h b/tests/auto/unit/mockbackend/qmockmediacapturesession.h
index c9e31fb56..0a2d3fb60 100644
--- a/tests/auto/unit/mockbackend/qmockmediacapturesession.h
+++ b/tests/auto/unit/mockbackend/qmockmediacapturesession.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QMOCKMEDIACAPTURESESSION_H
#define QMOCKMEDIACAPTURESESSION_H
@@ -33,13 +8,13 @@
#include "qmockimagecapture.h"
#include "qmockcamera.h"
#include "qmockimagecapture.h"
+#include "qmocksurfacecapture.h"
#include <private/qplatformmediacapture_p.h>
QT_BEGIN_NAMESPACE
class QMockMediaCaptureSession : public QPlatformMediaCaptureSession
{
- Q_OBJECT
public:
QMockMediaCaptureSession()
: hasControls(true)
@@ -87,10 +62,22 @@ public:
m_audioInput = input;
}
+ QPlatformSurfaceCapture *screenCapture() override { return m_screenCapture; }
+ void setScreenCapture(QPlatformSurfaceCapture *capture) override { m_screenCapture = capture; }
+
+ QPlatformSurfaceCapture *windowCapture() override { return m_windowCapture; }
+ void setWindowCapture(QPlatformSurfaceCapture *capture) override { m_windowCapture = capture; }
+
+ QPlatformVideoFrameInput *videoFrameInput() override { return m_videoFrameInput; }
+ void setVideoFrameInput(QPlatformVideoFrameInput *input) override { m_videoFrameInput = input; }
+
QMockCamera *mockCameraControl = nullptr;
QPlatformImageCapture *mockImageCapture = nullptr;
QMockMediaEncoder *mockControl = nullptr;
QPlatformAudioInput *m_audioInput = nullptr;
+ QPlatformSurfaceCapture *m_screenCapture = nullptr;
+ QPlatformSurfaceCapture *m_windowCapture = nullptr;
+ QPlatformVideoFrameInput *m_videoFrameInput = nullptr;
bool hasControls;
};
diff --git a/tests/auto/unit/mockbackend/qmockmediadevices.cpp b/tests/auto/unit/mockbackend/qmockmediadevices.cpp
index 216991925..7f2478741 100644
--- a/tests/auto/unit/mockbackend/qmockmediadevices.cpp
+++ b/tests/auto/unit/mockbackend/qmockmediadevices.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include "qmockmediadevices_p.h"
+#include "qmockmediadevices.h"
#include "private/qcameradevice_p.h"
QT_BEGIN_NAMESPACE
@@ -45,42 +9,6 @@ QT_BEGIN_NAMESPACE
QMockMediaDevices::QMockMediaDevices()
: QPlatformMediaDevices()
{
- setDevices(this);
-
- QCameraDevicePrivate *info = new QCameraDevicePrivate;
- info->description = QString::fromUtf8("defaultCamera");
- info->id = "default";
- info->isDefault = true;
- auto *f = new QCameraFormatPrivate{
- QSharedData(),
- QVideoFrameFormat::Format_ARGB8888,
- QSize(640, 480),
- 0,
- 30
- };
- info->videoFormats << f->create();
- m_cameraDevices.append(info->create());
- info = new QCameraDevicePrivate;
- info->description = QString::fromUtf8("frontCamera");
- info->id = "front";
- info->isDefault = false;
- info->position = QCameraDevice::FrontFace;
- f = new QCameraFormatPrivate{
- QSharedData(),
- QVideoFrameFormat::Format_XRGB8888,
- QSize(1280, 720),
- 0,
- 30
- };
- info->videoFormats << f->create();
- m_cameraDevices.append(info->create());
- info = new QCameraDevicePrivate;
- info->description = QString::fromUtf8("backCamera");
- info->id = "back";
- info->isDefault = false;
- info->position = QCameraDevice::BackFace;
- m_cameraDevices.append(info->create());
-
}
QMockMediaDevices::~QMockMediaDevices() = default;
@@ -95,20 +23,19 @@ QList<QAudioDevice> QMockMediaDevices::audioOutputs() const
return m_outputDevices;
}
-QList<QCameraDevice> QMockMediaDevices::videoInputs() const
-{
- return m_cameraDevices;
-}
-
-QPlatformAudioSource *QMockMediaDevices::createAudioSource(const QAudioDevice &info)
+QPlatformAudioSource *QMockMediaDevices::createAudioSource(const QAudioDevice &info,
+ QObject *parent)
{
Q_UNUSED(info);
+ Q_UNUSED(parent);
return nullptr;// ###
}
-QPlatformAudioSink *QMockMediaDevices::createAudioSink(const QAudioDevice &info)
+QPlatformAudioSink *QMockMediaDevices::createAudioSink(const QAudioDevice &info,
+ QObject *parent)
{
Q_UNUSED(info);
+ Q_UNUSED(parent);
return nullptr; //###
}
diff --git a/tests/auto/unit/mockbackend/qmockmediadevices.h b/tests/auto/unit/mockbackend/qmockmediadevices.h
new file mode 100644
index 000000000..e9e823194
--- /dev/null
+++ b/tests/auto/unit/mockbackend/qmockmediadevices.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QMOCKMEDIADEVICES_H
+#define QMOCKMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+#include <qelapsedtimer.h>
+#include <qaudiodevice.h>
+#include <qcameradevice.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCameraDevice;
+
+class QMockMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QMockMediaDevices();
+ ~QMockMediaDevices();
+
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &info, QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &info, QObject *parent) override;
+
+private:
+ QList<QAudioDevice> m_inputDevices;
+ QList<QAudioDevice> m_outputDevices;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tests/auto/unit/mockbackend/qmockmediadevices_p.h b/tests/auto/unit/mockbackend/qmockmediadevices_p.h
deleted file mode 100644
index cfa0398f3..000000000
--- a/tests/auto/unit/mockbackend/qmockmediadevices_p.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QMOCKMEDIADEVICES_H
-#define QMOCKMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <qelapsedtimer.h>
-#include <qaudiodevice.h>
-#include <qcameradevice.h>
-
-QT_BEGIN_NAMESPACE
-
-class QCameraDevice;
-
-class QMockMediaDevices : public QPlatformMediaDevices
-{
-public:
- QMockMediaDevices();
- ~QMockMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &info) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &info) override;
-
-private:
- QList<QAudioDevice> m_inputDevices;
- QList<QAudioDevice> m_outputDevices;
- QList<QCameraDevice> m_cameraDevices;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/tests/auto/unit/mockbackend/qmockmediaencoder.h b/tests/auto/unit/mockbackend/qmockmediaencoder.h
index 88ef5b3f9..cf855488b 100644
--- a/tests/auto/unit/mockbackend/qmockmediaencoder.h
+++ b/tests/auto/unit/mockbackend/qmockmediaencoder.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKRECORDERCONTROL_H
#define MOCKRECORDERCONTROL_H
@@ -62,11 +37,11 @@ public:
virtual void setMetaData(const QMediaMetaData &m) override
{
m_metaData = m;
- emit metaDataChanged();
+ metaDataChanged();
}
virtual QMediaMetaData metaData() const override { return m_metaData; }
- using QPlatformMediaRecorder::error;
+ using QPlatformMediaRecorder::updateError;
public:
void record(QMediaEncoderSettings &settings) override
@@ -74,30 +49,30 @@ public:
m_state = QMediaRecorder::RecordingState;
m_settings = settings;
m_position=1;
- emit stateChanged(m_state);
- emit durationChanged(m_position);
+ stateChanged(m_state);
+ durationChanged(m_position);
QUrl actualLocation = outputLocation().isEmpty() ? QUrl::fromLocalFile("default_name.mp4") : outputLocation();
- emit actualLocationChanged(actualLocation);
+ actualLocationChanged(actualLocation);
}
void pause() override
{
m_state = QMediaRecorder::PausedState;
- emit stateChanged(m_state);
+ stateChanged(m_state);
}
void resume() override
{
m_state = QMediaRecorder::RecordingState;
- emit stateChanged(m_state);
+ stateChanged(m_state);
}
void stop() override
{
m_position=0;
m_state = QMediaRecorder::StoppedState;
- emit stateChanged(m_state);
+ stateChanged(m_state);
}
void reset()
@@ -105,8 +80,8 @@ public:
m_state = QMediaRecorder::StoppedState;
m_settings = QMediaEncoderSettings();
m_position = 0;
- emit stateChanged(m_state);
- emit durationChanged(m_position);
+ stateChanged(m_state);
+ durationChanged(m_position);
clearActualLocation();
}
diff --git a/tests/auto/unit/mockbackend/qmockmediaplayer.h b/tests/auto/unit/mockbackend/qmockmediaplayer.h
index aef736cf3..a3ba76beb 100644
--- a/tests/auto/unit/mockbackend/qmockmediaplayer.h
+++ b/tests/auto/unit/mockbackend/qmockmediaplayer.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QMOCKMEDIAPLAYER_H
#define QMOCKMEDIAPLAYER_H
@@ -69,11 +44,15 @@ public:
}
qint64 duration() const override { return _duration; }
- void setDuration(qint64 duration) { emit durationChanged(_duration = duration); }
+ void setDuration(qint64 duration) { durationChanged(_duration = duration); }
qint64 position() const override { return _position; }
- void setPosition(qint64 position) override { if (position != _position) emit positionChanged(_position = position); }
+ void setPosition(qint64 position) override
+ {
+ if (position != _position)
+ positionChanged(_position = position);
+ }
float bufferProgress() const override { return _bufferProgress; }
void setBufferStatus(float status)
@@ -88,13 +67,17 @@ public:
bool isVideoAvailable() const override { return _videoAvailable; }
bool isSeekable() const override { return _isSeekable; }
- void setSeekable(bool seekable) { emit seekableChanged(_isSeekable = seekable); }
+ void setSeekable(bool seekable) { seekableChanged(_isSeekable = seekable); }
QMediaTimeRange availablePlaybackRanges() const override { return QMediaTimeRange(_seekRange.first, _seekRange.second); }
void setSeekRange(qint64 minimum, qint64 maximum) { _seekRange = qMakePair(minimum, maximum); }
qreal playbackRate() const override { return _playbackRate; }
- void setPlaybackRate(qreal rate) override { if (rate != _playbackRate) emit playbackRateChanged(_playbackRate = rate); }
+ void setPlaybackRate(qreal rate) override
+ {
+ if (rate != _playbackRate)
+ playbackRateChanged(_playbackRate = rate);
+ }
QUrl media() const override { return _media; }
void setMedia(const QUrl &content, QIODevice *stream) override
@@ -117,10 +100,7 @@ public:
void setAudioOutput(QPlatformAudioOutput *output) override { m_audioOutput = output; }
- void emitError(QMediaPlayer::Error err, const QString &errorString)
- {
- emit error(err, errorString);
- }
+ void emitError(QMediaPlayer::Error err, const QString &errorString) { error(err, errorString); }
void setState(QMediaPlayer::PlaybackState state)
{
@@ -144,8 +124,16 @@ public:
void setIsValid(bool isValid) { _isValid = isValid; }
void setMedia(QUrl media) { _media = media; }
void setVideoAvailable(bool videoAvailable) { _videoAvailable = videoAvailable; }
- void setError(QMediaPlayer::Error err) { _error = err; emit error(_error, _errorString); }
- void setErrorString(QString errorString) { _errorString = errorString; emit error(_error, _errorString); }
+ void setError(QMediaPlayer::Error err)
+ {
+ _error = err;
+ error(_error, _errorString);
+ }
+ void setErrorString(QString errorString)
+ {
+ _errorString = errorString;
+ error(_error, _errorString);
+ }
void reset()
{
diff --git a/tests/auto/unit/mockbackend/qmocksurfacecapture.h b/tests/auto/unit/mockbackend/qmocksurfacecapture.h
new file mode 100644
index 000000000..00ce80ebb
--- /dev/null
+++ b/tests/auto/unit/mockbackend/qmocksurfacecapture.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QMOCKSURFACECAPTURE_H
+#define QMOCKSURFACECAPTURE_H
+
+#include "private/qplatformsurfacecapture_p.h"
+#include "private/qvideoframe_p.h"
+
+#include "qmockvideobuffer.h"
+#include "qthread.h"
+
+QT_BEGIN_NAMESPACE
+
+class QMockSurfaceCapture : public QPlatformSurfaceCapture
+{
+ class Grabber : public QThread
+ {
+ public:
+ Grabber(QMockSurfaceCapture &capture) : QThread(&capture), m_capture(capture) { }
+
+ void run() override
+ {
+ for (int i = 0; !isInterruptionRequested(); ++i) {
+ QImage image(m_capture.m_imageSize, QImage::Format_ARGB32);
+
+ image.fill(i % 2 ? Qt::red : Qt::blue);
+
+ QVideoFrame frame = QVideoFramePrivate::createFrame(
+ std::make_unique<QMockVideoBuffer>(image),
+ QVideoFrameFormat(m_capture.m_imageSize,
+ QVideoFrameFormat::pixelFormatFromImageFormat(
+ m_capture.m_imageFormat)));
+
+ emit m_capture.newVideoFrame(frame);
+ }
+ }
+
+ private:
+ QMockSurfaceCapture &m_capture;
+ };
+
+public:
+ using QPlatformSurfaceCapture::QPlatformSurfaceCapture;
+
+ ~QMockSurfaceCapture() { resetGrabber(); }
+
+ bool setActiveInternal(bool active) override
+ {
+ if (active) {
+ m_grabber = std::make_unique<Grabber>(*this);
+ m_grabber->start();
+ } else {
+ resetGrabber();
+ }
+
+ return true;
+ }
+
+ bool isActive() const override { return bool(m_grabber); }
+
+ QVideoFrameFormat frameFormat() const override
+ {
+ return m_grabber ? QVideoFrameFormat(
+ m_imageSize, QVideoFrameFormat::pixelFormatFromImageFormat(m_imageFormat))
+ : QVideoFrameFormat{};
+ }
+
+private:
+ void resetGrabber()
+ {
+ if (m_grabber) {
+ m_grabber->requestInterruption();
+ m_grabber->quit();
+ m_grabber->wait();
+ m_grabber.reset();
+ }
+ }
+
+private:
+ std::unique_ptr<Grabber> m_grabber;
+ const QImage::Format m_imageFormat = QImage::Format_ARGB32;
+ const QSize m_imageSize = QSize(2, 3);
+};
+
+QT_END_NAMESPACE
+
+#endif // QMOCKSURFACECAPTURE_H
diff --git a/tests/auto/unit/mockbackend/qmockvideobuffer.h b/tests/auto/unit/mockbackend/qmockvideobuffer.h
new file mode 100644
index 000000000..0ee32416c
--- /dev/null
+++ b/tests/auto/unit/mockbackend/qmockvideobuffer.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QMOCKVIDEOBUFFER_H
+#define QMOCKVIDEOBUFFER_H
+
+#include "qimage.h"
+#include "private/qhwvideobuffer_p.h"
+
+class QMockVideoBuffer : public QHwVideoBuffer
+{
+public:
+ QMockVideoBuffer(QImage image) : QHwVideoBuffer(QVideoFrame::NoHandle), m_image(image) { }
+
+ MapData map(QtVideo::MapMode mode) override
+ {
+ MapData mapData;
+ if (m_mapMode == QtVideo::MapMode::NotMapped && !m_image.isNull()
+ && mode != QtVideo::MapMode::NotMapped) {
+ m_mapMode = mode;
+
+ mapData.planeCount = 1;
+ mapData.bytesPerLine[0] = m_image.bytesPerLine();
+ mapData.data[0] = m_image.bits();
+ mapData.dataSize[0] = m_image.sizeInBytes();
+ }
+
+ return mapData;
+ }
+
+ void unmap() override { m_mapMode = QtVideo::MapMode::NotMapped; }
+
+private:
+ QtVideo::MapMode m_mapMode = QtVideo::MapMode::NotMapped;
+ QImage m_image;
+};
+
+#endif // QMOCKVIDEOBUFFER_H
diff --git a/tests/auto/unit/mockbackend/qmockvideosink.h b/tests/auto/unit/mockbackend/qmockvideosink.h
index 0a8baeef0..d93178668 100644
--- a/tests/auto/unit/mockbackend/qmockvideosink.h
+++ b/tests/auto/unit/mockbackend/qmockvideosink.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QMOCKVIDEOSINK_H
#define QMOCKVIDEOSINK_H
@@ -57,8 +21,6 @@ QT_BEGIN_NAMESPACE
class QMockVideoSink : public QPlatformVideoSink
{
- Q_OBJECT
-
public:
explicit QMockVideoSink(QVideoSink *parent)
: QPlatformVideoSink(parent)
diff --git a/tests/auto/unit/multimedia/CMakeLists.txt b/tests/auto/unit/multimedia/CMakeLists.txt
index d95cab75a..151577d14 100644
--- a/tests/auto/unit/multimedia/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/CMakeLists.txt
@@ -1,19 +1,41 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from multimedia.pro.
add_subdirectory(qabstractvideobuffer)
add_subdirectory(qaudiorecorder)
add_subdirectory(qaudioformat)
add_subdirectory(qaudionamespace)
+add_subdirectory(qaudiostatemachine)
add_subdirectory(qcamera)
add_subdirectory(qcameradevice)
add_subdirectory(qimagecapture)
add_subdirectory(qmediaformat)
+add_subdirectory(qmediametadata)
add_subdirectory(qmediaplayer)
#add_subdirectory(qmediaplaylist)
add_subdirectory(qmediarecorder)
add_subdirectory(qmediatimerange)
+add_subdirectory(qmultimediautils)
add_subdirectory(qvideoframe)
add_subdirectory(qvideoframeformat)
+if(QT_FEATURE_ffmpeg)
+ add_subdirectory(qvideoframecolormanagement)
+endif()
add_subdirectory(qaudiobuffer)
add_subdirectory(qaudiodecoder)
add_subdirectory(qsamplecache)
+add_subdirectory(qscreencapture)
+add_subdirectory(qvideotexturehelper)
+add_subdirectory(qmaybe)
+add_subdirectory(qmediadevices)
+add_subdirectory(qerrorinfo)
+add_subdirectory(qvideobuffers)
+add_subdirectory(qwavedecoder)
+
+if(QT_FEATURE_gstreamer)
+ add_subdirectory(gstreamer_backend)
+ add_subdirectory(qmediacapture_gstreamer)
+ add_subdirectory(qmediaplayer_gstreamer)
+endif()
diff --git a/tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt b/tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt
new file mode 100644
index 000000000..6d52d09e1
--- /dev/null
+++ b/tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_gstreamer_backend Test:
+#####################################################################
+
+qt_internal_add_test(tst_gstreamer_backend
+ SOURCES
+ tst_gstreamer_backend.cpp
+ tst_gstreamer_backend.h
+ LIBRARIES
+ Qt::MultimediaPrivate
+ Qt::QGstreamerMediaPluginPrivate
+)
diff --git a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp
new file mode 100644
index 000000000..929c46b3e
--- /dev/null
+++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp
@@ -0,0 +1,309 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "tst_gstreamer_backend.h"
+
+#include <QtTest/QtTest>
+#include <QtMultimedia/qmediaformat.h>
+
+#include <QtQGstreamerMediaPlugin/private/qgst_handle_types_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgst_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgst_debug_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgstpipeline_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgstreamermetadata_p.h>
+
+QT_USE_NAMESPACE
+
+// NOLINTBEGIN(readability-convert-member-functions-to-static)
+
+using namespace Qt::Literals;
+
+namespace {
+
+template <typename... Pairs>
+QMediaMetaData makeQMediaMetaData(Pairs &&...pairs)
+{
+ QMediaMetaData metadata;
+
+ auto addKeyValuePair = [&](auto &&pair) {
+ metadata.insert(pair.first, pair.second);
+ return;
+ };
+
+ (addKeyValuePair(pairs), ...);
+
+ return metadata;
+}
+
+} // namespace
+
+QGstTagListHandle tst_GStreamer::parseTagList(const char *str)
+{
+ QGstTagListHandle tagList{
+ gst_tag_list_new_from_string(str),
+ QGstTagListHandle::NeedsRef,
+ };
+ return tagList;
+}
+
+QGstTagListHandle tst_GStreamer::parseTagList(const QByteArray &ba)
+{
+ return parseTagList(ba.constData());
+}
+
+void tst_GStreamer::qGstCasts_withElement()
+{
+ QGstElement element = QGstElement::createFromFactory("identity", "myPipeline");
+ QVERIFY(element);
+
+ QVERIFY(!qIsGstObjectOfType<GstPipeline>(element.element()));
+ QVERIFY(!qIsGstObjectOfType<GstBin>(element.element()));
+}
+
+void tst_GStreamer::qGstCasts_withBin()
+{
+ QGstBin bin = QGstBin::create("bin");
+ QVERIFY(bin);
+
+ QVERIFY(!qIsGstObjectOfType<GstPipeline>(bin.element()));
+ QVERIFY(qIsGstObjectOfType<GstBin>(bin.element()));
+}
+
+void tst_GStreamer::qGstCasts_withPipeline()
+{
+ QGstPipeline pipeline = QGstPipeline::create("myPipeline");
+
+ QGstElement element{
+ qGstSafeCast<GstElement>(pipeline.pipeline()),
+ QGstElement::NeedsRef,
+ };
+
+ QVERIFY(element);
+ QVERIFY(qIsGstObjectOfType<GstPipeline>(element.element()));
+ QVERIFY(qIsGstObjectOfType<GstBin>(element.element()));
+}
+
+void tst_GStreamer::metadata_taglistToMetaData()
+{
+ QGstTagListHandle tagList = parseTagList(R"(taglist, title="My Video", comment="yada")");
+
+ QMediaMetaData parsed = taglistToMetaData(tagList);
+
+ QCOMPARE(parsed.stringValue(QMediaMetaData::Title), u"My Video"_s);
+ QCOMPARE(parsed.stringValue(QMediaMetaData::Comment), u"yada"_s);
+}
+
+void tst_GStreamer::metadata_taglistToMetaData_extractsOrientation()
+{
+ QFETCH(QByteArray, taglist);
+ QFETCH(QtVideo::Rotation, rotation);
+
+ QGstTagListHandle tagList = parseTagList(taglist);
+ QMediaMetaData parsed = taglistToMetaData(tagList);
+ QCOMPARE(parsed[QMediaMetaData::Orientation].value<QtVideo::Rotation>(), rotation);
+}
+
+void tst_GStreamer::metadata_taglistToMetaData_extractsOrientation_data()
+{
+ QTest::addColumn<QByteArray>("taglist");
+ QTest::addColumn<QtVideo::Rotation>("rotation");
+
+ QTest::newRow("no rotation") << R"(taglist, title="My Video", comment="yada")"_ba
+ << QtVideo::Rotation::None;
+ QTest::newRow("90 degree")
+ << R"(taglist, title="My Video", comment="yada", image-orientation=(string)rotate-90)"_ba
+ << QtVideo::Rotation::Clockwise90;
+ QTest::newRow("180 degree")
+ << R"(taglist, title="My Video", comment="yada", image-orientation=(string)rotate-180)"_ba
+ << QtVideo::Rotation::Clockwise180;
+ QTest::newRow("270 degree")
+ << R"(taglist, title="My Video", comment="yada", image-orientation=(string)rotate-270)"_ba
+ << QtVideo::Rotation::Clockwise270;
+}
+
+void tst_GStreamer::metadata_taglistToMetaData_extractsDuration()
+{
+ QGstTagListHandle tagList = parseTagList(
+ R"__(taglist, video-codec=(string)"On2\ VP9", container-specific-track-id=(string)1, extended-comment=(string){ "ALPHA_MODE\=1", "HANDLER_NAME\=Apple\ Video\ Media\ Handler", "VENDOR_ID\=appl", "TIMECODE\=00:00:00:00", "DURATION\=00:00:00.400000000" }, encoder=(string)"Lavc59.37.100\ libvpx-vp9")__");
+
+ QMediaMetaData parsed = taglistToMetaData(tagList);
+ QCOMPARE(parsed[QMediaMetaData::Duration].value<int>(), 400);
+}
+
+void tst_GStreamer::metadata_taglistToMetaData_extractsLanguage()
+{
+ QFETCH(QByteArray, tagListString);
+ QFETCH(QLocale::Language, language);
+
+ QGstTagListHandle tagList = parseTagList(tagListString);
+ QVERIFY(tagList);
+
+ QMediaMetaData parsed = taglistToMetaData(tagList);
+ QCOMPARE(parsed[QMediaMetaData::Language].value<QLocale::Language>(), language);
+}
+
+void tst_GStreamer::metadata_taglistToMetaData_extractsLanguage_data()
+{
+ QTest::addColumn<QByteArray>("tagListString");
+ QTest::addColumn<QLocale::Language>("language");
+
+ QTest::newRow("english, en")
+ << R"__(taglist, container-format=(string)Matroska, audio-codec=(string)"MPEG-4\ AAC", language-code=(string)en, container-specific-track-id=(string)5, encoder=(string)Lavf60.16.100, extended-comment=(string)"DURATION\=00:00:05.055000000")__"_ba
+ << QLocale::Language::English;
+ QTest::newRow("spanish, es")
+ << R"__(taglist, container-format=(string)Matroska, audio-codec=(string)"MPEG-4\ AAC", language-code=(string)es, container-specific-track-id=(string)5, encoder=(string)Lavf60.16.100, extended-comment=(string)"DURATION\=00:00:05.055000000")__"_ba
+ << QLocale::Language::Spanish;
+ QTest::newRow("english, eng")
+ << R"__(taglist, container-format=(string)Matroska, audio-codec=(string)"MPEG-4\ AAC", language-code=(string)eng, container-specific-track-id=(string)5, encoder=(string)Lavf60.16.100, extended-comment=(string)"DURATION\=00:00:05.055000000")__"_ba
+ << QLocale::Language::English;
+ QTest::newRow("spanish, spa")
+ << R"__(taglist, container-format=(string)Matroska, audio-codec=(string)"MPEG-4\ AAC", language-code=(string)spa, container-specific-track-id=(string)5, encoder=(string)Lavf60.16.100, extended-comment=(string)"DURATION\=00:00:05.055000000")__"_ba
+ << QLocale::Language::Spanish;
+}
+
+void tst_GStreamer::metadata_capsToMetaData()
+{
+ QFETCH(QByteArray, capsString);
+ QFETCH(QMediaMetaData, expectedMetadata);
+
+ QGstCaps caps{
+ gst_caps_from_string(capsString.constData()),
+ QGstCaps::HasRef,
+ };
+
+ QMediaMetaData md = capsToMetaData(caps);
+
+ QCOMPARE(md, expectedMetadata);
+}
+
+void tst_GStreamer::metadata_capsToMetaData_data()
+{
+ using Key = QMediaMetaData::Key;
+ using KVPair = std::pair<QMediaMetaData::Key, QVariant>;
+
+ auto makeKVPair = [](Key key, auto value) {
+ return KVPair{
+ key,
+ QVariant::fromValue(value),
+ };
+ };
+
+ QTest::addColumn<QByteArray>("capsString");
+ QTest::addColumn<QMediaMetaData>("expectedMetadata");
+
+ QTest::newRow("container") << R"(video/quicktime, variant=(string)iso)"_ba
+ << makeQMediaMetaData(makeKVPair(Key::FileFormat,
+ QMediaFormat::FileFormat::MPEG4));
+
+ QTest::newRow("video")
+ << R"(video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3.1, profile=(string)main, codec_data=(buffer)014d401fffe10017674d401fda014016ec0440000003004000000c83c60ca801000468ef3c80, width=(int)1280, height=(int)720, framerate=(fraction)25/1, pixel-aspect-ratio=(fraction)1/1)"_ba
+ << makeQMediaMetaData(makeKVPair(Key::VideoCodec, QMediaFormat::VideoCodec::H264),
+ makeKVPair(Key::VideoFrameRate, 25),
+ makeKVPair(Key::Resolution, QSize(1280, 720)));
+
+ QTest::newRow("audio")
+ << R"(audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, level=(string)4, base-profile=(string)lc, profile=(string)lc, codec_data=(buffer)11b0, rate=(int)48000, channels=(int)6)"_ba
+ << makeQMediaMetaData(makeKVPair(Key::AudioCodec, QMediaFormat::AudioCodec::AAC));
+}
+
+void tst_GStreamer::QGstBin_createFromPipelineDescription()
+{
+ QGstBin bin = QGstBin::createFromPipelineDescription("identity name=foo ! identity name=bar");
+
+ QVERIFY(bin);
+ QVERIFY(bin.findByName("foo"));
+ QCOMPARE_EQ(bin.findByName("foo").getParent(), bin);
+ QVERIFY(bin.findByName("bar"));
+ QVERIFY(!bin.findByName("baz"));
+ bin.dumpGraph("QGstBin_createFromPipelineDescription");
+}
+
+void tst_GStreamer::QGstElement_createFromPipelineDescription()
+{
+ using namespace std::string_view_literals;
+ QGstElement element = QGstElement::createFromPipelineDescription("identity name=foo");
+ QCOMPARE_EQ(element.name(), "foo"sv);
+ QCOMPARE_EQ(element.typeName(), "GstIdentity"sv);
+}
+
+void tst_GStreamer::QGstElement_createFromPipelineDescription_multipleElementsCreatesBin()
+{
+ using namespace std::string_view_literals;
+ QGstElement element =
+ QGstElement::createFromPipelineDescription("identity name=foo ! identity name=bar");
+
+ QVERIFY(element);
+ QCOMPARE_EQ(element.typeName(), "GstPipeline"sv);
+
+ QGstBin bin{
+ qGstSafeCast<GstBin>(element.element()),
+ QGstBin::NeedsRef,
+ };
+
+ QVERIFY(bin);
+ QVERIFY(bin.findByName("foo"));
+ QCOMPARE_EQ(bin.findByName("foo").getParent(), bin);
+ QVERIFY(bin.findByName("bar"));
+ QVERIFY(!bin.findByName("baz"));
+
+ bin.dumpGraph("QGstElement_createFromPipelineDescription_multipleElements");
+}
+
+void tst_GStreamer::QGstPad_inferTypeFromName()
+{
+ auto makePad = [](const char *name, GstPadDirection direction) {
+ return QGstPad{
+ gst_pad_new(name, direction),
+ QGstPad::NeedsRef,
+ };
+ };
+
+ QVERIFY(makePad("audio_0", GST_PAD_SRC).inferTrackTypeFromName()
+ == QPlatformMediaPlayer::AudioStream);
+ QVERIFY(makePad("video_0", GST_PAD_SRC).inferTrackTypeFromName()
+ == QPlatformMediaPlayer::VideoStream);
+ QVERIFY(makePad("text_0", GST_PAD_SRC).inferTrackTypeFromName()
+ == QPlatformMediaPlayer::SubtitleStream);
+ QVERIFY(makePad("src_0", GST_PAD_SRC).inferTrackTypeFromName() == std::nullopt);
+ QVERIFY(makePad("text", GST_PAD_SRC).inferTrackTypeFromName() == std::nullopt);
+}
+
+void tst_GStreamer::qDebug_GstPadDirection()
+{
+ auto validate = [](GstPadDirection direction, QString expectedString) {
+ QString str;
+ QDebug dbg(&str);
+
+ dbg << direction;
+
+ QCOMPARE_EQ(str, expectedString);
+ };
+
+ validate(GST_PAD_UNKNOWN, u"GST_PAD_UNKNOWN "_s);
+ validate(GST_PAD_SRC, u"GST_PAD_SRC "_s);
+ validate(GST_PAD_SINK, u"GST_PAD_SINK "_s);
+}
+
+void tst_GStreamer::qDebug_GstStreamStatusType()
+{
+ auto validate = [](GstStreamStatusType type, QString expectedString) {
+ QString str;
+ QDebug dbg(&str);
+
+ dbg << type;
+
+ QCOMPARE_EQ(str, expectedString);
+ };
+
+ validate(GST_STREAM_STATUS_TYPE_CREATE, u"GST_STREAM_STATUS_TYPE_CREATE "_s);
+ validate(GST_STREAM_STATUS_TYPE_ENTER, u"GST_STREAM_STATUS_TYPE_ENTER "_s);
+ validate(GST_STREAM_STATUS_TYPE_LEAVE, u"GST_STREAM_STATUS_TYPE_LEAVE "_s);
+ validate(GST_STREAM_STATUS_TYPE_DESTROY, u"GST_STREAM_STATUS_TYPE_DESTROY "_s);
+ validate(GST_STREAM_STATUS_TYPE_START, u"GST_STREAM_STATUS_TYPE_START "_s);
+ validate(GST_STREAM_STATUS_TYPE_PAUSE, u"GST_STREAM_STATUS_TYPE_PAUSE "_s);
+ validate(GST_STREAM_STATUS_TYPE_STOP, u"GST_STREAM_STATUS_TYPE_STOP "_s);
+}
+
+QTEST_GUILESS_MAIN(tst_GStreamer)
+
+#include "moc_tst_gstreamer_backend.cpp"
diff --git a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h
new file mode 100644
index 000000000..7252dffdd
--- /dev/null
+++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TST_GSTREAMER_BACKEND_H
+#define TST_GSTREAMER_BACKEND_H
+
+#include <QtTest/QtTest>
+
+#include <QtQGstreamerMediaPlugin/private/qgstreamerintegration_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgst_handle_types_p.h>
+
+QT_USE_NAMESPACE
+
+class tst_GStreamer : public QObject
+{
+ Q_OBJECT
+
+ QGstTagListHandle parseTagList(const char *);
+ QGstTagListHandle parseTagList(const QByteArray &);
+
+private slots:
+ void qGstCasts_withElement();
+ void qGstCasts_withBin();
+ void qGstCasts_withPipeline();
+
+ void metadata_taglistToMetaData();
+ void metadata_taglistToMetaData_extractsOrientation();
+ void metadata_taglistToMetaData_extractsOrientation_data();
+ void metadata_taglistToMetaData_extractsDuration();
+ void metadata_taglistToMetaData_extractsLanguage();
+ void metadata_taglistToMetaData_extractsLanguage_data();
+
+ void metadata_capsToMetaData();
+ void metadata_capsToMetaData_data();
+
+ void QGstBin_createFromPipelineDescription();
+ void QGstElement_createFromPipelineDescription();
+ void QGstElement_createFromPipelineDescription_multipleElementsCreatesBin();
+
+ void QGstPad_inferTypeFromName();
+
+ void qDebug_GstPadDirection();
+ void qDebug_GstStreamStatusType();
+
+private:
+ QGstreamerIntegration integration;
+};
+
+#endif // TST_GSTREAMER_BACKEND_H
diff --git a/tests/auto/unit/multimedia/qabstractvideobuffer/CMakeLists.txt b/tests/auto/unit/multimedia/qabstractvideobuffer/CMakeLists.txt
index bd7f67a19..8f59a0e40 100644
--- a/tests/auto/unit/multimedia/qabstractvideobuffer/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qabstractvideobuffer/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qabstractvideobuffer.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qabstractvideobuffer
SOURCES
tst_qabstractvideobuffer.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp b/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp
index 94594ba99..e75e1395a 100644
--- a/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp
+++ b/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp
@@ -1,42 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
-#include <private/qabstractvideobuffer_p.h>
-
-// Adds an enum, and the stringized version
-#define ADD_ENUM_TEST(x) \
- QTest::newRow(#x) \
- << QVideoFrame::x \
- << QString(QLatin1String(#x));
+#include <private/qhwvideobuffer_p.h>
class tst_QAbstractVideoBuffer : public QObject
{
@@ -55,19 +22,16 @@ private slots:
void handleType_data();
void handleType();
void handle();
- void mapMode();
void mapModeDebug_data();
void mapModeDebug();
};
-class QtTestVideoBuffer : public QAbstractVideoBuffer
+class QtTestVideoBuffer : public QHwVideoBuffer
{
public:
- QtTestVideoBuffer(QVideoFrame::HandleType type) : QAbstractVideoBuffer(type) {}
-
- [[nodiscard]] QVideoFrame::MapMode mapMode() const override { return QVideoFrame::ReadWrite; }
+ QtTestVideoBuffer(QVideoFrame::HandleType type) : QHwVideoBuffer(type) { }
- MapData map(QVideoFrame::MapMode) override { return {}; }
+ MapData map(QtVideo::MapMode) override { return {}; }
void unmap() override {}
};
@@ -100,8 +64,8 @@ void tst_QAbstractVideoBuffer::handleType_data()
QTest::addColumn<QVideoFrame::HandleType>("type");
QTest::addColumn<QString>("stringized");
- ADD_ENUM_TEST(NoHandle);
- ADD_ENUM_TEST(RhiTextureHandle);
+ QTest::newRow("NoHandle") << QVideoFrame::NoHandle << QStringLiteral("NoHandle");
+ QTest::newRow("RhiTextureHandle") << QVideoFrame::RhiTextureHandle << QStringLiteral("RhiTextureHandle");
}
void tst_QAbstractVideoBuffer::handleType()
@@ -121,29 +85,27 @@ void tst_QAbstractVideoBuffer::handle()
{
QtTestVideoBuffer buffer(QVideoFrame::NoHandle);
- QVERIFY(buffer.textureHandle(0) == 0);
-}
-
-void tst_QAbstractVideoBuffer::mapMode()
-{
- QtTestVideoBuffer maptest(QVideoFrame::NoHandle);
- QVERIFY2(maptest.mapMode() == QVideoFrame::ReadWrite, "ReadWrite Failed");
+ QVERIFY(buffer.textureHandle(nullptr, 0) == 0);
}
void tst_QAbstractVideoBuffer::mapModeDebug_data()
{
- QTest::addColumn<QVideoFrame::MapMode>("mapMode");
+ QTest::addColumn<QtVideo::MapMode>("mapMode");
QTest::addColumn<QString>("stringized");
- ADD_ENUM_TEST(NotMapped);
- ADD_ENUM_TEST(ReadOnly);
- ADD_ENUM_TEST(WriteOnly);
- ADD_ENUM_TEST(ReadWrite);
+ QTest::newRow("NotMapped") << QtVideo::MapMode::NotMapped
+ << QStringLiteral("QtVideo::MapMode::NotMapped");
+ QTest::newRow("ReadOnly") << QtVideo::MapMode::ReadOnly
+ << QStringLiteral("QtVideo::MapMode::ReadOnly");
+ QTest::newRow("WriteOnly") << QtVideo::MapMode::WriteOnly
+ << QStringLiteral("QtVideo::MapMode::WriteOnly");
+ QTest::newRow("ReadWrite") << QtVideo::MapMode::ReadWrite
+ << QStringLiteral("QtVideo::MapMode::ReadWrite");
}
void tst_QAbstractVideoBuffer::mapModeDebug()
{
- QFETCH(QVideoFrame::MapMode, mapMode);
+ QFETCH(QtVideo::MapMode, mapMode);
QFETCH(QString, stringized);
QTest::ignoreMessage(QtDebugMsg, stringized.toLatin1().constData());
diff --git a/tests/auto/unit/multimedia/qaudiobuffer/CMakeLists.txt b/tests/auto/unit/multimedia/qaudiobuffer/CMakeLists.txt
index 6e9a99180..807f3acaa 100644
--- a/tests/auto/unit/multimedia/qaudiobuffer/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qaudiobuffer/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qaudiobuffer.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qaudiobuffer
SOURCES
tst_qaudiobuffer.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Multimedia
)
diff --git a/tests/auto/unit/multimedia/qaudiobuffer/tst_qaudiobuffer.cpp b/tests/auto/unit/multimedia/qaudiobuffer/tst_qaudiobuffer.cpp
index 875025559..7c74fe994 100644
--- a/tests/auto/unit/multimedia/qaudiobuffer/tst_qaudiobuffer.cpp
+++ b/tests/auto/unit/multimedia/qaudiobuffer/tst_qaudiobuffer.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QString>
#include <QtTest/QtTest>
diff --git a/tests/auto/unit/multimedia/qaudiodecoder/CMakeLists.txt b/tests/auto/unit/multimedia/qaudiodecoder/CMakeLists.txt
index d56507756..cced66bda 100644
--- a/tests/auto/unit/multimedia/qaudiodecoder/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qaudiodecoder/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qaudiodecoder.pro.
#####################################################################
@@ -9,10 +12,10 @@ qt_internal_add_test(tst_qaudiodecoder
tst_qaudiodecoder.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::Multimedia
Qt::MultimediaPrivate
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimedia/qaudiodecoder/tst_qaudiodecoder.cpp b/tests/auto/unit/multimedia/qaudiodecoder/tst_qaudiodecoder.cpp
index 6049bd4a2..77e161fda 100644
--- a/tests/auto/unit/multimedia/qaudiodecoder/tst_qaudiodecoder.cpp
+++ b/tests/auto/unit/multimedia/qaudiodecoder/tst_qaudiodecoder.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QString>
@@ -32,13 +7,18 @@
#include "qaudiodecoder.h"
#include "qmockaudiodecoder.h"
-#include "qmockintegration_p.h"
+#include "qmockintegration.h"
+
+QT_USE_NAMESPACE
+
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
class tst_QAudioDecoder : public QObject
{
Q_OBJECT
public:
+
tst_QAudioDecoder();
private Q_SLOTS:
@@ -49,9 +29,6 @@ private Q_SLOTS:
void source();
void readAll();
void nullControl();
-
-private:
- QMockIntegration mockIntegration;
};
tst_QAudioDecoder::tst_QAudioDecoder()
@@ -63,7 +40,7 @@ void tst_QAudioDecoder::ctors()
QAudioDecoder d;
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.source(), QString(""));
+ QCOMPARE(d.source(), QStringLiteral(""));
d.setSource(QUrl());
QVERIFY(!d.isDecoding());
@@ -77,8 +54,8 @@ void tst_QAudioDecoder::read()
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
// Starting with empty source == error
@@ -87,9 +64,9 @@ void tst_QAudioDecoder::read()
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(readySpy.count(), 0);
- QCOMPARE(bufferChangedSpy.count(), 0);
- QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(readySpy.size(), 0);
+ QCOMPARE(bufferChangedSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 1);
// Set the source to something
d.setSource(QUrl::fromLocalFile("Blah"));
@@ -122,13 +99,13 @@ void tst_QAudioDecoder::read()
QVERIFY(b.format().channelCount() == 1);
QVERIFY(b.sampleCount() == 4);
- QVERIFY(readySpy.count() >= 1);
- QVERIFY(errorSpy.count() == 0);
+ QVERIFY(readySpy.size() >= 1);
+ QVERIFY(errorSpy.size() == 0);
if (d.bufferAvailable()) {
- QVERIFY(bufferChangedSpy.count() == 1);
+ QVERIFY(bufferChangedSpy.size() == 1);
} else {
- QVERIFY(bufferChangedSpy.count() == 2);
+ QVERIFY(bufferChangedSpy.size() == 2);
}
}
@@ -138,8 +115,8 @@ void tst_QAudioDecoder::stop()
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
// Starting with empty source == error
@@ -148,9 +125,9 @@ void tst_QAudioDecoder::stop()
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(readySpy.count(), 0);
- QCOMPARE(bufferChangedSpy.count(), 0);
- QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(readySpy.size(), 0);
+ QCOMPARE(bufferChangedSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 1);
// Set the source to something
d.setSource(QUrl::fromLocalFile("Blah"));
@@ -190,8 +167,8 @@ void tst_QAudioDecoder::format()
QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
// Set the source to something
@@ -278,19 +255,19 @@ void tst_QAudioDecoder::readAll()
d.setSource(QUrl::fromLocalFile("Foo"));
QVERIFY(!d.isDecoding());
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
- QSignalSpy isDecodingSpy(&d, SIGNAL(isDecodingChanged(bool)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy bufferAvailableSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy bufferAvailableSpy(&d, &QAudioDecoder::bufferAvailableChanged);
d.start();
int i = 0;
forever {
QVERIFY(d.isDecoding());
- QCOMPARE(isDecodingSpy.count(), 1);
- QCOMPARE(durationSpy.count(), 1);
+ QCOMPARE(isDecodingSpy.size(), 1);
+ QCOMPARE(durationSpy.size(), 1);
QVERIFY(finishedSpy.isEmpty());
- QTRY_VERIFY(bufferAvailableSpy.count() >= 1);
+ QTRY_VERIFY(bufferAvailableSpy.size() >= 1);
if (d.bufferAvailable()) {
QAudioBuffer b = d.read();
QVERIFY(b.isValid());
@@ -301,8 +278,8 @@ void tst_QAudioDecoder::readAll()
i++;
if (i == MOCK_DECODER_MAX_BUFFERS) {
- QCOMPARE(finishedSpy.count(), 1);
- QCOMPARE(isDecodingSpy.count(), 2);
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(isDecodingSpy.size(), 2);
QVERIFY(!d.isDecoding());
QList<QVariant> arguments = isDecodingSpy.takeLast();
QVERIFY(arguments.at(0).toBool() == false);
@@ -319,7 +296,7 @@ void tst_QAudioDecoder::readAll()
void tst_QAudioDecoder::nullControl()
{
- mockIntegration.setFlags(QMockIntegration::NoAudioDecoderInterface);
+ QMockIntegration::instance()->setFlags(QMockIntegration::NoAudioDecoderInterface);
QAudioDecoder d;
QVERIFY(d.error() == QAudioDecoder::NotSupportedError);
diff --git a/tests/auto/unit/multimedia/qaudioformat/CMakeLists.txt b/tests/auto/unit/multimedia/qaudioformat/CMakeLists.txt
index 2cd6fc9a7..5f4c47bd7 100644
--- a/tests/auto/unit/multimedia/qaudioformat/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qaudioformat/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qaudioformat.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qaudioformat
SOURCES
tst_qaudioformat.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/unit/multimedia/qaudioformat/tst_qaudioformat.cpp b/tests/auto/unit/multimedia/qaudioformat/tst_qaudioformat.cpp
index b2ee24808..c4f4e10cf 100644
--- a/tests/auto/unit/multimedia/qaudioformat/tst_qaudioformat.cpp
+++ b/tests/auto/unit/multimedia/qaudioformat/tst_qaudioformat.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -34,8 +9,6 @@
#include <QStringList>
#include <QList>
-//TESTED_COMPONENT=src/multimedia
-
class tst_QAudioFormat : public QObject
{
Q_OBJECT
diff --git a/tests/auto/unit/multimedia/qaudionamespace/CMakeLists.txt b/tests/auto/unit/multimedia/qaudionamespace/CMakeLists.txt
index 2c9bb0605..3d4ac7126 100644
--- a/tests/auto/unit/multimedia/qaudionamespace/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qaudionamespace/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qaudionamespace.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qaudionamespace
SOURCES
tst_qaudionamespace.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/unit/multimedia/qaudionamespace/tst_qaudionamespace.cpp b/tests/auto/unit/multimedia/qaudionamespace/tst_qaudionamespace.cpp
index e3e7e17bf..cae002306 100644
--- a/tests/auto/unit/multimedia/qaudionamespace/tst_qaudionamespace.cpp
+++ b/tests/auto/unit/multimedia/qaudionamespace/tst_qaudionamespace.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -235,7 +208,7 @@ void tst_QAudioNamespace::convertVolume()
qreal actualOutput = QAudio::convertVolume(input, from, to);
QVERIFY2(qAbs(actualOutput - expectedOutput) < 0.01,
- QString("actual: %1, expected: %2").arg(actualOutput).arg(expectedOutput).toLocal8Bit().constData());
+ QStringLiteral("actual: %1, expected: %2").arg(actualOutput).arg(expectedOutput).toLocal8Bit().constData());
}
QTEST_MAIN(tst_QAudioNamespace)
diff --git a/tests/auto/unit/multimedia/qaudiorecorder/CMakeLists.txt b/tests/auto/unit/multimedia/qaudiorecorder/CMakeLists.txt
index 3ee8b5692..b2dc16b69 100644
--- a/tests/auto/unit/multimedia/qaudiorecorder/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qaudiorecorder/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qaudiorecorder.pro.
#####################################################################
@@ -9,9 +12,9 @@ qt_internal_add_test(tst_qaudiorecorder
tst_qaudiorecorder.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimedia/qaudiorecorder/tst_qaudiorecorder.cpp b/tests/auto/unit/multimedia/qaudiorecorder/tst_qaudiorecorder.cpp
index 52f563bb2..7d6309976 100644
--- a/tests/auto/unit/multimedia/qaudiorecorder/tst_qaudiorecorder.cpp
+++ b/tests/auto/unit/multimedia/qaudiorecorder/tst_qaudiorecorder.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
@@ -37,13 +12,13 @@
#include <qaudiosource.h>
#include <qmediacapturesession.h>
-//TESTED_COMPONENT=src/multimedia
-
#include "qmockmediacapturesession.h"
-#include "qmockintegration_p.h"
+#include "qmockintegration.h"
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
class tst_QAudioRecorder: public QObject
{
Q_OBJECT
@@ -59,20 +34,16 @@ private slots:
private:
QMediaRecorder *encoder = nullptr;
- QMockIntegration *mockIntegration;
};
void tst_QAudioRecorder::init()
{
- mockIntegration = new QMockIntegration;
encoder = nullptr;
}
void tst_QAudioRecorder::cleanup()
{
delete encoder;
- delete mockIntegration;
- mockIntegration = nullptr;
encoder = nullptr;
}
diff --git a/tests/auto/unit/multimedia/qaudiostatemachine/CMakeLists.txt b/tests/auto/unit/multimedia/qaudiostatemachine/CMakeLists.txt
new file mode 100644
index 000000000..715091dac
--- /dev/null
+++ b/tests/auto/unit/multimedia/qaudiostatemachine/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qaudiostatemachine
+ SOURCES
+ tst_qaudiostatemachine.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::MultimediaPrivate
+)
+
diff --git a/tests/auto/unit/multimedia/qaudiostatemachine/tst_qaudiostatemachine.cpp b/tests/auto/unit/multimedia/qaudiostatemachine/tst_qaudiostatemachine.cpp
new file mode 100644
index 000000000..433590d09
--- /dev/null
+++ b/tests/auto/unit/multimedia/qaudiostatemachine/tst_qaudiostatemachine.cpp
@@ -0,0 +1,661 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+// TESTED_COMPONENT=src/multimedia
+
+#include <QtTest/QtTest>
+#include <private/qaudiostatemachine_p.h>
+#include <private/qaudiosystem_p.h>
+#include <QThread>
+
+QT_USE_NAMESPACE
+
+template<typename F>
+static std::unique_ptr<QThread> createTestThread(std::vector<std::atomic_int> &counters,
+ size_t index, F &&functor,
+ int minAttemptsCount = 2000)
+{
+ return std::unique_ptr<QThread>(QThread::create([=, &counters]() {
+ auto checkCounter = [=](int counter) { return counter < minAttemptsCount; };
+ for (; !QTest::currentTestFailed()
+ && std::any_of(counters.begin(), counters.end(), checkCounter);
+ ++counters[index])
+ functor();
+ }));
+}
+
+class tst_QAudioStateMachine : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void constructor_setsStoppedStateWithNoError();
+
+ void start_changesState_whenStateIsStopped_data();
+ void start_changesState_whenStateIsStopped();
+
+ void start_doesntChangeState_whenStateIsNotStopped_data();
+ void start_doesntChangeState_whenStateIsNotStopped();
+
+ void stop_changesState_whenStateIsNotStopped_data();
+ void stop_changesState_whenStateIsNotStopped();
+
+ void stop_doesntChangeState_whenStateIsStopped_data();
+ void stop_doesntChangeState_whenStateIsStopped();
+
+ void stopWithDraining_changesState_whenStateIsNotStopped_data();
+ void stopWithDraining_changesState_whenStateIsNotStopped();
+
+ void methods_dontChangeState_whenDraining();
+
+ void onDrained_finishesDraining();
+
+ void onDrained_getsFailed_whenDrainHasntBeenCalled_data();
+ void onDrained_getsFailed_whenDrainHasntBeenCalled();
+
+ void updateActiveOrIdle_doesntChangeState_whenStateIsNotActiveOrIdle_data();
+ void updateActiveOrIdle_doesntChangeState_whenStateIsNotActiveOrIdle();
+
+ void updateActiveOrIdle_changesState_whenStateIsActiveOrIdle_data();
+ void updateActiveOrIdle_changesState_whenStateIsActiveOrIdle();
+
+ void suspendAndResume_saveAndRestoreState_whenStateIsActiveOrIdle_data();
+ void suspendAndResume_saveAndRestoreState_whenStateIsActiveOrIdle();
+
+ void suspend_doesntChangeState_whenStateIsNotActiveOrIdle_data();
+ void suspend_doesntChangeState_whenStateIsNotActiveOrIdle();
+
+ void resume_doesntChangeState_whenStateIsNotSuspended_data();
+ void resume_doesntChangeState_whenStateIsNotSuspended();
+
+ void deleteNotifierInSlot_suppressesAdjacentSignal();
+
+ void twoThreadsToggleSuspendResumeAndIdleActive_statesAreConsistent();
+
+ void twoThreadsToggleStartStop_statesAreConsistent();
+
+private:
+ void generateNotStoppedPrevStates()
+ {
+ QTest::addColumn<QAudio::State>("prevState");
+ QTest::addColumn<QAudio::Error>("prevError");
+
+ QTest::newRow("from IdleState") << QAudio::IdleState << QAudio::UnderrunError;
+ QTest::newRow("from ActiveState") << QAudio::ActiveState << QAudio::NoError;
+ QTest::newRow("from SuspendedState") << QAudio::SuspendedState << QAudio::NoError;
+ }
+
+ void generateStoppedAndSuspendedPrevStates()
+ {
+ QTest::addColumn<QAudio::State>("prevState");
+
+ QTest::newRow("from StoppedState") << QAudio::StoppedState;
+ QTest::newRow("from SuspendedState") << QAudio::SuspendedState;
+ }
+};
+
+void tst_QAudioStateMachine::constructor_setsStoppedStateWithNoError()
+{
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ QCOMPARE(stateMachine.state(), QAudio::StoppedState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+ QVERIFY(!stateMachine.isActiveOrIdle());
+}
+
+void tst_QAudioStateMachine::start_changesState_whenStateIsStopped_data()
+{
+ QTest::addColumn<bool>("active");
+ QTest::addColumn<QAudio::State>("expectedState");
+
+ QTest::newRow("to active") << true << QAudio::ActiveState;
+ QTest::newRow("to not active") << false << QAudio::IdleState;
+}
+
+void tst_QAudioStateMachine::start_changesState_whenStateIsStopped()
+{
+ QFETCH(bool, active);
+ QFETCH(QAudio::State, expectedState);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY(stateMachine.start(active));
+
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(stateSpy.front().front().value<QAudio::State>(), expectedState);
+ QCOMPARE(errorSpy.size(), 0);
+ QCOMPARE(stateMachine.state(), expectedState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+}
+
+void tst_QAudioStateMachine::start_doesntChangeState_whenStateIsNotStopped_data()
+{
+ generateNotStoppedPrevStates();
+}
+
+void tst_QAudioStateMachine::start_doesntChangeState_whenStateIsNotStopped()
+{
+ QFETCH(QAudio::State, prevState);
+ QFETCH(QAudio::Error, prevError);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+ stateMachine.forceSetState(prevState, prevError);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY2(!stateMachine.start(), "Cannot start (active)");
+ QVERIFY2(!stateMachine.start(false), "Cannot start (not active)");
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+
+ QCOMPARE(stateMachine.state(), prevState);
+ QCOMPARE(stateMachine.error(), prevError);
+}
+
+void tst_QAudioStateMachine::stop_changesState_whenStateIsNotStopped_data()
+{
+ generateNotStoppedPrevStates();
+}
+
+void tst_QAudioStateMachine::stop_changesState_whenStateIsNotStopped()
+{
+ QFETCH(QAudio::State, prevState);
+ QFETCH(QAudio::Error, prevError);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState, prevError);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ auto notifier = stateMachine.stop();
+ QVERIFY(notifier);
+
+ QCOMPARE(stateMachine.state(), QAudio::StoppedState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+ QVERIFY(!notifier.isDraining());
+
+ notifier.reset();
+
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(stateSpy.front().front().value<QAudio::State>(), QAudio::StoppedState);
+ QCOMPARE(errorSpy.size(), prevError == QAudio::NoError ? 0 : 1);
+ if (!errorSpy.empty())
+ QCOMPARE(errorSpy.front().front().value<QAudio::Error>(), QAudio::NoError);
+
+ QCOMPARE(stateMachine.state(), QAudio::StoppedState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+ QVERIFY(!stateMachine.isDraining());
+}
+
+void tst_QAudioStateMachine::stop_doesntChangeState_whenStateIsStopped_data()
+{
+ QTest::addColumn<QAudio::Error>("error");
+
+ QTest::newRow("from NoError") << QAudio::NoError;
+ QTest::newRow("from IOError") << QAudio::IOError;
+}
+
+void tst_QAudioStateMachine::stop_doesntChangeState_whenStateIsStopped()
+{
+ QFETCH(QAudio::Error, error);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.setError(error);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY2(!stateMachine.stop(), "should return false if already stopped");
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+ QCOMPARE(stateMachine.state(), QAudio::StoppedState);
+ QCOMPARE(stateMachine.error(), error);
+ QVERIFY(!stateMachine.isDraining());
+}
+
+void tst_QAudioStateMachine::stopWithDraining_changesState_whenStateIsNotStopped_data()
+{
+ generateNotStoppedPrevStates();
+}
+
+void tst_QAudioStateMachine::stopWithDraining_changesState_whenStateIsNotStopped()
+{
+ QFETCH(QAudio::State, prevState);
+ QFETCH(QAudio::Error, prevError);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState, prevError);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+
+ auto notifier = stateMachine.stop(QAudio::NoError, true);
+ QVERIFY(notifier);
+ QCOMPARE(notifier.isDraining(), prevState == QAudio::ActiveState);
+ notifier.reset();
+
+ QCOMPARE(stateMachine.state(), QAudio::StoppedState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+ QCOMPARE(stateMachine.isDraining(), prevState == QAudio::ActiveState);
+
+ QCOMPARE(stateSpy.size(), 1);
+}
+
+void tst_QAudioStateMachine::methods_dontChangeState_whenDraining()
+{
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(QAudio::ActiveState);
+ stateMachine.stop(QAudio::IOError, true);
+ QVERIFY(stateMachine.isDraining());
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY(!stateMachine.start());
+ QVERIFY(!stateMachine.stop());
+ QVERIFY(!stateMachine.stop(QAudio::NoError, true));
+ QVERIFY(!stateMachine.suspend());
+ QVERIFY(!stateMachine.resume());
+ QVERIFY(!stateMachine.updateActiveOrIdle(false));
+ QVERIFY(!stateMachine.updateActiveOrIdle(true));
+
+ QCOMPARE(stateMachine.state(), QAudio::StoppedState);
+ QCOMPARE(stateMachine.error(), QAudio::IOError);
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+
+ QVERIFY(stateMachine.isDraining());
+}
+
+void tst_QAudioStateMachine::onDrained_finishesDraining()
+{
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(QAudio::ActiveState);
+ stateMachine.stop(QAudio::IOError, true);
+ QVERIFY(stateMachine.isDraining());
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY(stateMachine.onDrained());
+ QVERIFY(!stateMachine.isDraining());
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+
+ QCOMPARE(stateMachine.state(), QAudio::StoppedState);
+ QCOMPARE(stateMachine.error(), QAudio::IOError);
+
+ QVERIFY(stateMachine.start());
+}
+
+void tst_QAudioStateMachine::onDrained_getsFailed_whenDrainHasntBeenCalled_data()
+{
+ generateNotStoppedPrevStates();
+ QTest::newRow("from Stopped State") << QAudio::StoppedState << QAudio::IOError;
+}
+
+void tst_QAudioStateMachine::onDrained_getsFailed_whenDrainHasntBeenCalled()
+{
+ QFETCH(QAudio::State, prevState);
+ QFETCH(QAudio::Error, prevError);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState, prevError);
+
+ QVERIFY(!stateMachine.onDrained());
+
+ QCOMPARE(stateMachine.state(), prevState);
+ QCOMPARE(stateMachine.error(), prevError);
+}
+
+void tst_QAudioStateMachine::updateActiveOrIdle_doesntChangeState_whenStateIsNotActiveOrIdle_data()
+{
+ generateStoppedAndSuspendedPrevStates();
+}
+
+void tst_QAudioStateMachine::updateActiveOrIdle_doesntChangeState_whenStateIsNotActiveOrIdle()
+{
+ QFETCH(QAudio::State, prevState);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY(!stateMachine.updateActiveOrIdle(true));
+ QVERIFY(!stateMachine.updateActiveOrIdle(false));
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+}
+
+void tst_QAudioStateMachine::updateActiveOrIdle_changesState_whenStateIsActiveOrIdle_data()
+{
+ QTest::addColumn<QAudio::State>("prevState");
+ QTest::addColumn<QAudio::Error>("prevError");
+ QTest::addColumn<bool>("active");
+ QTest::addColumn<QAudio::Error>("error");
+
+ QTest::newRow("from ActiveState+NoError -> not active+NoError")
+ << QAudio::ActiveState << QAudio::NoError << false << QAudio::NoError;
+ QTest::newRow("from Idle(UnderrunError) -> active+NoError")
+ << QAudio::IdleState << QAudio::UnderrunError << true << QAudio::NoError;
+ QTest::newRow("from Idle(UnderrunError) -> not active+UnderrunError")
+ << QAudio::IdleState << QAudio::UnderrunError << false << QAudio::UnderrunError;
+}
+
+void tst_QAudioStateMachine::updateActiveOrIdle_changesState_whenStateIsActiveOrIdle()
+{
+ QFETCH(QAudio::State, prevState);
+ QFETCH(QAudio::Error, prevError);
+ QFETCH(bool, active);
+ QFETCH(QAudio::Error, error);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState, prevError);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ const auto expectedState = active ? QAudio::ActiveState : QAudio::IdleState;
+
+ auto notifier = stateMachine.updateActiveOrIdle(active, error);
+ QVERIFY(notifier);
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+
+ QCOMPARE(stateMachine.state(), expectedState);
+ QCOMPARE(stateMachine.error(), error);
+
+ notifier.reset();
+
+ QCOMPARE(stateSpy.size(), expectedState == prevState ? 0 : 1);
+ if (!stateSpy.empty())
+ QCOMPARE(stateSpy.front().front().value<QAudio::State>(), expectedState);
+
+ QCOMPARE(errorSpy.size(), prevError == error ? 0 : 1);
+ if (!errorSpy.empty())
+ QCOMPARE(errorSpy.front().front().value<QAudio::Error>(), error);
+
+ QCOMPARE(stateMachine.state(), expectedState);
+ QCOMPARE(stateMachine.error(), error);
+}
+
+void tst_QAudioStateMachine::suspendAndResume_saveAndRestoreState_whenStateIsActiveOrIdle_data()
+{
+ QTest::addColumn<QAudio::State>("prevState");
+ QTest::addColumn<QAudio::Error>("prevError");
+
+ QTest::newRow("from Active+NoError") << QAudio::ActiveState << QAudio::NoError;
+ QTest::newRow("from Idle+UnderrunError") << QAudio::IdleState << QAudio::UnderrunError;
+}
+
+void tst_QAudioStateMachine::suspendAndResume_saveAndRestoreState_whenStateIsActiveOrIdle()
+{
+ QFETCH(QAudio::State, prevState);
+ QFETCH(QAudio::Error, prevError);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState, prevError);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY(stateMachine.suspend());
+
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(stateSpy.front().front().value<QAudio::State>(), QAudio::SuspendedState);
+ QCOMPARE(errorSpy.size(), prevError == QAudio::NoError ? 0 : 1);
+
+ QCOMPARE(stateMachine.state(), QAudio::SuspendedState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+
+ stateSpy.clear();
+ errorSpy.clear();
+
+ QVERIFY(!stateMachine.suspend());
+ QVERIFY(stateMachine.resume());
+
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(stateSpy.front().front().value<QAudio::State>(), prevState);
+ QCOMPARE(errorSpy.size(), 0);
+
+ QCOMPARE(stateMachine.state(), prevState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+}
+
+void tst_QAudioStateMachine::suspend_doesntChangeState_whenStateIsNotActiveOrIdle_data()
+{
+ generateStoppedAndSuspendedPrevStates();
+}
+
+void tst_QAudioStateMachine::suspend_doesntChangeState_whenStateIsNotActiveOrIdle()
+{
+ QFETCH(QAudio::State, prevState);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY(!stateMachine.suspend());
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+
+ QCOMPARE(stateMachine.state(), prevState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+}
+
+void tst_QAudioStateMachine::resume_doesntChangeState_whenStateIsNotSuspended_data()
+{
+ QTest::addColumn<QAudio::State>("prevState");
+
+ QTest::newRow("from StoppedState") << QAudio::StoppedState;
+ QTest::newRow("from ActiveState") << QAudio::ActiveState;
+ QTest::newRow("from IdleState") << QAudio::IdleState;
+}
+
+void tst_QAudioStateMachine::resume_doesntChangeState_whenStateIsNotSuspended()
+{
+ QFETCH(QAudio::State, prevState);
+
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ stateMachine.forceSetState(prevState);
+
+ QSignalSpy stateSpy(&changeNotifier, &QAudioStateChangeNotifier::stateChanged);
+ QSignalSpy errorSpy(&changeNotifier, &QAudioStateChangeNotifier::errorChanged);
+
+ QVERIFY(!stateMachine.resume());
+
+ QCOMPARE(stateSpy.size(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+
+ QCOMPARE(stateMachine.state(), prevState);
+ QCOMPARE(stateMachine.error(), QAudio::NoError);
+}
+
+void tst_QAudioStateMachine::deleteNotifierInSlot_suppressesAdjacentSignal()
+{
+ auto changeNotifier = std::make_unique<QAudioStateChangeNotifier>();
+ QAudioStateMachine stateMachine(*changeNotifier);
+ stateMachine.start();
+
+ auto onSignal = [&]() {
+ QVERIFY2(changeNotifier, "The 2nd signal shouldn't be emitted");
+ changeNotifier.reset();
+ };
+
+ connect(changeNotifier.get(), &QAudioStateChangeNotifier::errorChanged,
+ this, onSignal, Qt::DirectConnection);
+ connect(changeNotifier.get(), &QAudioStateChangeNotifier::stateChanged,
+ this, onSignal, Qt::DirectConnection);
+
+ stateMachine.stop(QAudio::IOError);
+}
+
+void tst_QAudioStateMachine::twoThreadsToggleSuspendResumeAndIdleActive_statesAreConsistent()
+{
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ QVERIFY(stateMachine.start());
+ QCOMPARE(stateMachine.state(), QAudio::ActiveState);
+
+ std::atomic<int> signalsCount = 0;
+ std::atomic<int> changesCount = 0;
+
+ connect(&changeNotifier, &QAudioStateChangeNotifier::stateChanged,
+ this, [&](QAudio::State) { ++signalsCount; }, Qt::DirectConnection);
+
+ std::vector<std::atomic_int> counters(2);
+
+ auto threadSuspendResume = createTestThread(counters, 0, [&]() {
+ {
+ auto notifier = stateMachine.suspend();
+ QVERIFY(notifier);
+ QVERIFY(notifier.isStateChanged());
+ QCOMPARE(notifier.audioState(), QAudio::SuspendedState);
+ ++changesCount;
+ }
+
+ {
+ auto notifier = stateMachine.resume();
+ QVERIFY(notifier);
+ QVERIFY(notifier.isStateChanged());
+ QCOMPARE_NE(notifier.audioState(), QAudio::SuspendedState);
+ ++changesCount;
+ }
+ });
+
+ auto threadIdleActive = createTestThread(counters, 1, [&]() {
+ if (auto notifier = stateMachine.updateActiveOrIdle(false)) {
+ if (notifier.isStateChanged())
+ ++changesCount;
+
+ QCOMPARE(notifier.audioState(), QAudio::IdleState);
+ }
+
+ if (auto notifier = stateMachine.updateActiveOrIdle(true)) {
+ if (notifier.isStateChanged())
+ ++changesCount;
+
+ QCOMPARE(notifier.audioState(), QAudio::ActiveState);
+ }
+ });
+
+ threadSuspendResume->start();
+ threadIdleActive->start();
+
+ threadSuspendResume->wait();
+ threadIdleActive->wait();
+
+ if (QTest::currentTestFailed()) {
+ qDebug() << "counterSuspendResume:" << counters[0];
+ qDebug() << "counterIdleActive:" << counters[1];
+ }
+
+ QCOMPARE(signalsCount, changesCount);
+}
+
+void tst_QAudioStateMachine::twoThreadsToggleStartStop_statesAreConsistent()
+{
+ QAudioStateChangeNotifier changeNotifier;
+ QAudioStateMachine stateMachine(changeNotifier);
+
+ QVERIFY(stateMachine.start());
+ QCOMPARE(stateMachine.state(), QAudio::ActiveState);
+
+ std::atomic<int> signalsCount = 0;
+ std::atomic<int> changesCount = 0;
+
+ connect(&changeNotifier, &QAudioStateChangeNotifier::stateChanged,
+ this, [&](QAudio::State) { ++signalsCount; }, Qt::DirectConnection);
+
+ std::vector<std::atomic_int> counters(2);
+
+ auto threadStartActive = createTestThread(counters, 0, [&]() {
+ if (auto startNotifier = stateMachine.start()) {
+ QCOMPARE(startNotifier.prevAudioState(), QAudio::StoppedState);
+ QCOMPARE(startNotifier.audioState(), QAudio::ActiveState);
+ ++changesCount;
+ startNotifier.reset();
+
+ auto stopNotifier = stateMachine.stop();
+ ++changesCount;
+ QVERIFY(stopNotifier);
+ QCOMPARE(stopNotifier.prevAudioState(), QAudio::ActiveState);
+ }
+ });
+
+ auto threadStartIdle = createTestThread(counters, 1, [&]() {
+ if (auto startNotifier = stateMachine.start(false)) {
+ QCOMPARE(startNotifier.prevAudioState(), QAudio::StoppedState);
+ QCOMPARE(startNotifier.audioState(), QAudio::IdleState);
+ ++changesCount;
+ startNotifier.reset();
+
+ auto stopNotifier = stateMachine.stop();
+ ++changesCount;
+ QVERIFY(stopNotifier);
+ QCOMPARE(stopNotifier.audioState(), QAudio::StoppedState);
+ QCOMPARE(stopNotifier.prevAudioState(), QAudio::IdleState);
+ }
+ });
+
+ threadStartActive->start();
+ threadStartIdle->start();
+
+ threadStartActive->wait();
+ threadStartIdle->wait();
+
+ if (QTest::currentTestFailed()) {
+ qDebug() << "counterSuspendResume:" << counters[0];
+ qDebug() << "counterIdleActive:" << counters[1];
+ }
+
+ QCOMPARE(signalsCount, changesCount);
+}
+
+QTEST_GUILESS_MAIN(tst_QAudioStateMachine)
+
+#include "tst_qaudiostatemachine.moc"
diff --git a/tests/auto/unit/multimedia/qcamera/CMakeLists.txt b/tests/auto/unit/multimedia/qcamera/CMakeLists.txt
index 8413c6de4..484793923 100644
--- a/tests/auto/unit/multimedia/qcamera/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qcamera/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qcamera.pro.
#####################################################################
@@ -9,9 +12,9 @@ qt_internal_add_test(tst_multimedia_qcamera
tst_qcamera.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp b/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp
index 52a34d4f4..bd1972550 100644
--- a/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp
+++ b/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
@@ -41,12 +14,13 @@
#include <qobject.h>
#include <qmediadevices.h>
-#include "qmockintegration_p.h"
+#include "qmockintegration.h"
#include "qmockmediacapturesession.h"
#include "qmockcamera.h"
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
class tst_QCamera: public QObject
{
@@ -97,13 +71,14 @@ private slots:
void testSignalIsoSensitivityChanged();
void testSignalShutterSpeedChanged();
void testSignalFlashReady();
-
-private:
- QMockIntegration integration;
};
void tst_QCamera::initTestCase()
{
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("Flakiness on macOS CI, to be investigated, QTBUG-111812");
+#endif
}
void tst_QCamera::init()
@@ -222,14 +197,14 @@ void tst_QCamera::testSimpleCameraCapture()
QCOMPARE(imageCapture.error(), QImageCapture::NoError);
QVERIFY(imageCapture.errorString().isEmpty());
- QSignalSpy errorSignal(&imageCapture, SIGNAL(errorOccurred(int,QImageCapture::Error,QString)));
- imageCapture.captureToFile(QString::fromLatin1("/dev/null"));
+ QSignalSpy errorSignal(&imageCapture, &QImageCapture::errorOccurred);
+ imageCapture.captureToFile(QStringLiteral("/dev/null"));
QCOMPARE(errorSignal.size(), 1);
QCOMPARE(imageCapture.error(), QImageCapture::NotReadyError);
QVERIFY(!imageCapture.errorString().isEmpty());
camera.start();
- imageCapture.captureToFile(QString::fromLatin1("/dev/null"));
+ imageCapture.captureToFile(QStringLiteral("/dev/null"));
QCOMPARE(errorSignal.size(), 1);
QCOMPARE(imageCapture.error(), QImageCapture::NoError);
QVERIFY(imageCapture.errorString().isEmpty());
@@ -245,10 +220,10 @@ void tst_QCamera::testCameraCapture()
QVERIFY(!imageCapture.isReadyForCapture());
- QSignalSpy capturedSignal(&imageCapture, SIGNAL(imageCaptured(int,QImage)));
- QSignalSpy errorSignal(&imageCapture, SIGNAL(errorOccurred(int,QImageCapture::Error,QString)));
+ QSignalSpy capturedSignal(&imageCapture, &QImageCapture::imageCaptured);
+ QSignalSpy errorSignal(&imageCapture, &QImageCapture::errorOccurred);
- imageCapture.captureToFile(QString::fromLatin1("/dev/null"));
+ imageCapture.captureToFile(QStringLiteral("/dev/null"));
QCOMPARE(capturedSignal.size(), 0);
QCOMPARE(errorSignal.size(), 1);
QCOMPARE(imageCapture.error(), QImageCapture::NotReadyError);
@@ -259,7 +234,7 @@ void tst_QCamera::testCameraCapture()
QVERIFY(imageCapture.isReadyForCapture());
QCOMPARE(errorSignal.size(), 0);
- imageCapture.captureToFile(QString::fromLatin1("/dev/null"));
+ imageCapture.captureToFile(QStringLiteral("/dev/null"));
QTRY_COMPARE(capturedSignal.size(), 1);
QCOMPARE(errorSignal.size(), 0);
@@ -274,11 +249,11 @@ void tst_QCamera::testCameraCaptureMetadata()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy metadataSignal(&imageCapture, SIGNAL(imageMetadataAvailable(int,const QMediaMetaData&)));
- QSignalSpy savedSignal(&imageCapture, SIGNAL(imageSaved(int,QString)));
+ QSignalSpy metadataSignal(&imageCapture, &QImageCapture::imageMetadataAvailable);
+ QSignalSpy savedSignal(&imageCapture, &QImageCapture::imageSaved);
camera.start();
- int id = imageCapture.captureToFile(QString::fromLatin1("/dev/null"));
+ int id = imageCapture.captureToFile(QStringLiteral("/dev/null"));
QTRY_COMPARE(savedSignal.size(), 1);
@@ -287,7 +262,7 @@ void tst_QCamera::testCameraCaptureMetadata()
QVariantList metadata = metadataSignal[0];
QCOMPARE(metadata[0].toInt(), id);
QMediaMetaData data = metadata[1].value<QMediaMetaData>();
- QCOMPARE(data.keys().length(), 2);
+ QCOMPARE(data.keys().size(), 2);
QCOMPARE(data[QMediaMetaData::Author].toString(), "Author");
QCOMPARE(data[QMediaMetaData::Date].toDateTime().date().year(), 2021);
}
@@ -444,11 +419,11 @@ void tst_QCamera::testCameraEncodingProperyChange()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy activeChangedSignal(&camera, SIGNAL(activeChanged(bool)));
+ QSignalSpy activeChangedSignal(&camera, &QCamera::activeChanged);
camera.start();
QCOMPARE(camera.isActive(), true);
- QCOMPARE(activeChangedSignal.count(), 1);
+ QCOMPARE(activeChangedSignal.size(), 1);
}
void tst_QCamera::testSetVideoOutput()
@@ -625,32 +600,34 @@ void tst_QCamera::testErrorSignal()
QMediaCaptureSession session;
QCamera camera;
session.setCamera(&camera);
- auto *service = integration.lastCaptureService();
+ auto *service = QMockIntegration::instance()->lastCaptureService();
Q_ASSERT(service);
Q_ASSERT(service->mockCameraControl);
- QSignalSpy spyError(&camera, SIGNAL(errorOccurred(QCamera::Error,const QString&)));
+ QSignalSpy spyError(&camera, &QCamera::errorOccurred);
/* Set the QPlatformCamera error and verify if the signal is emitted correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("Camera Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError, QStringLiteral("Camera Error"));
- QVERIFY(spyError.count() == 1);
+ QVERIFY(spyError.size() == 1);
QCamera::Error err = qvariant_cast<QCamera::Error >(spyError.at(0).at(0));
QVERIFY(err == QCamera::CameraError);
spyError.clear();
/* Set the QPlatformCamera error and verify if the signal is emitted correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("InvalidRequestError Error"));
- QVERIFY(spyError.count() == 1);
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("InvalidRequestError Error"));
+ QVERIFY(spyError.size() == 1);
err = qvariant_cast<QCamera::Error >(spyError.at(0).at(0));
QVERIFY(err == QCamera::CameraError);
spyError.clear();
/* Set the QPlatformCamera error and verify if the signal is emitted correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("NotSupportedFeatureError Error"));
- QVERIFY(spyError.count() == 1);
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("NotSupportedFeatureError Error"));
+ QVERIFY(spyError.size() == 1);
err = qvariant_cast<QCamera::Error >(spyError.at(0).at(0));
QVERIFY(err == QCamera::CameraError);
@@ -662,18 +639,20 @@ void tst_QCamera::testError()
QMediaCaptureSession session;
QCamera camera;
session.setCamera(&camera);
- auto *service = integration.lastCaptureService();
+ auto *service = QMockIntegration::instance()->lastCaptureService();
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("Camera Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError, QStringLiteral("Camera Error"));
QVERIFY(camera.error() == QCamera::CameraError);
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("InvalidRequestError Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("InvalidRequestError Error"));
QVERIFY(camera.error() == QCamera::CameraError);
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("CameraError Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("CameraError Error"));
QVERIFY(camera.error() == QCamera::CameraError);
}
@@ -684,19 +663,21 @@ void tst_QCamera::testErrorString()
QMediaCaptureSession session;
QCamera camera;
session.setCamera(&camera);
- auto *service = integration.lastCaptureService();
+ auto *service = QMockIntegration::instance()->lastCaptureService();
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("Camera Error"));
- QVERIFY(camera.errorString() == QString("Camera Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError, QStringLiteral("Camera Error"));
+ QVERIFY(camera.errorString() == QStringLiteral("Camera Error"));
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("InvalidRequestError Error"));
- QVERIFY(camera.errorString() == QString("InvalidRequestError Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("InvalidRequestError Error"));
+ QVERIFY(camera.errorString() == QStringLiteral("InvalidRequestError Error"));
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QString("CameraError Error"));
- QVERIFY(camera.errorString() == QString("CameraError Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("CameraError Error"));
+ QVERIFY(camera.errorString() == QStringLiteral("CameraError Error"));
}
void tst_QCamera::testSetCameraFormat()
@@ -704,34 +685,34 @@ void tst_QCamera::testSetCameraFormat()
QCamera camera;
QCameraDevice device = camera.cameraDevice();
auto videoFormats = device.videoFormats();
- QVERIFY(videoFormats.count());
+ QVERIFY(videoFormats.size());
QCameraFormat cameraFormat = videoFormats.first();
- QSignalSpy spy(&camera, SIGNAL(cameraFormatChanged()));
- QVERIFY(spy.count() == 0);
+ QSignalSpy spy(&camera, &QCamera::cameraFormatChanged);
+ QVERIFY(spy.size() == 0);
camera.setCameraFormat(cameraFormat);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(camera.cameraFormat(), cameraFormat);
QCOMPARE(camera.cameraFormat().pixelFormat(), QVideoFrameFormat::Format_ARGB8888);
QCOMPARE(camera.cameraFormat().resolution(), QSize(640, 480));
QCOMPARE(camera.cameraFormat().minFrameRate(), 0);
QCOMPARE(camera.cameraFormat().maxFrameRate(), 30);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
spy.clear();
camera.setCameraFormat({});
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(camera.cameraFormat(), QCameraFormat());
spy.clear();
camera.setCameraDevice(QMediaDevices::videoInputs().at(1));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(camera.cameraFormat(), QCameraFormat());
camera.setCameraFormat(camera.cameraDevice().videoFormats().first());
QCOMPARE(camera.cameraFormat().pixelFormat(), QVideoFrameFormat::Format_XRGB8888);
QCOMPARE(camera.cameraFormat().resolution(), QSize(1280, 720));
QCOMPARE(camera.cameraFormat().minFrameRate(), 0);
QCOMPARE(camera.cameraFormat().maxFrameRate(), 30);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
//Added this code to cover QCamera::FocusModeHyperfocal and QCamera::FocusModeAutoNear
@@ -758,14 +739,14 @@ void tst_QCamera::testZoomChanged()
QCamera camera;
session.setCamera(&camera);
- QSignalSpy spy(&camera, SIGNAL(zoomFactorChanged(float)));
- QVERIFY(spy.count() == 0);
+ QSignalSpy spy(&camera, &QCamera::zoomFactorChanged);
+ QVERIFY(spy.size() == 0);
camera.setZoomFactor(2.0);
- QVERIFY(spy.count() == 1);
+ QVERIFY(spy.size() == 1);
camera.zoomTo(3.0, 1);
- QVERIFY(spy.count() == 2);
+ QVERIFY(spy.size() == 2);
camera.zoomTo(1.0, 0);
- QVERIFY(spy.count() == 3);
+ QVERIFY(spy.size() == 3);
}
void tst_QCamera::testMaxZoomChangedSignal()
@@ -773,12 +754,12 @@ void tst_QCamera::testMaxZoomChangedSignal()
QMediaCaptureSession session;
QCamera camera;
session.setCamera(&camera);
- QMockCamera *mock = integration.lastCamera();
+ QMockCamera *mock = QMockIntegration::instance()->lastCamera();
// ### change max zoom factor on backend, e.g. by changing camera
- QSignalSpy spy(&camera, SIGNAL(maximumZoomFactorChanged(float)));
+ QSignalSpy spy(&camera, &QCamera::maximumZoomFactorChanged);
mock->maximumZoomFactorChanged(55);
- QVERIFY(spy.count() == 1);
+ QVERIFY(spy.size() == 1);
QCOMPARE(camera.maximumZoomFactor(), 55);
}
@@ -788,9 +769,9 @@ void tst_QCamera::testSignalExposureCompensationChanged()
QCamera camera;
session.setCamera(&camera);
- QSignalSpy spyExposureCompensationChanged(&camera, SIGNAL(exposureCompensationChanged(float)));
+ QSignalSpy spyExposureCompensationChanged(&camera, &QCamera::exposureCompensationChanged);
- QVERIFY(spyExposureCompensationChanged.count() ==0);
+ QVERIFY(spyExposureCompensationChanged.size() == 0);
QVERIFY(camera.exposureCompensation() != 800);
camera.setExposureCompensation(2.0);
@@ -799,14 +780,14 @@ void tst_QCamera::testSignalExposureCompensationChanged()
QVERIFY(camera.exposureCompensation() == 2.0);
- QCOMPARE(spyExposureCompensationChanged.count(),1);
+ QCOMPARE(spyExposureCompensationChanged.size(),1);
// Setting the same should not result in a signal
camera.setExposureCompensation(2.0);
QTest::qWait(100);
QVERIFY(camera.exposureCompensation() == 2.0);
- QCOMPARE(spyExposureCompensationChanged.count(),1);
+ QCOMPARE(spyExposureCompensationChanged.size(),1);
}
void tst_QCamera::testSignalIsoSensitivityChanged()
@@ -815,13 +796,13 @@ void tst_QCamera::testSignalIsoSensitivityChanged()
QCamera camera;
session.setCamera(&camera);
- QSignalSpy spyisoSensitivityChanged(&camera, SIGNAL(isoSensitivityChanged(int)));
+ QSignalSpy spyisoSensitivityChanged(&camera, &QCamera::isoSensitivityChanged);
- QVERIFY(spyisoSensitivityChanged.count() ==0);
+ QVERIFY(spyisoSensitivityChanged.size() ==0);
camera.setManualIsoSensitivity(800); //set the manualiso sentivity to 800
QTest::qWait(100);
- QVERIFY(spyisoSensitivityChanged.count() ==1);
+ QVERIFY(spyisoSensitivityChanged.size() ==1);
}
void tst_QCamera::testSignalShutterSpeedChanged()
@@ -830,14 +811,14 @@ void tst_QCamera::testSignalShutterSpeedChanged()
QCamera camera;
session.setCamera(&camera);
- QSignalSpy spySignalExposureTimeChanged(&camera, SIGNAL(exposureTimeChanged(float)));
+ QSignalSpy spySignalExposureTimeChanged(&camera, &QCamera::exposureTimeChanged);
- QVERIFY(spySignalExposureTimeChanged.count() ==0);
+ QVERIFY(spySignalExposureTimeChanged.size() == 0);
camera.setManualExposureTime(2.0);//set the ManualShutterSpeed to 2.0
QTest::qWait(100);
- QVERIFY(spySignalExposureTimeChanged.count() ==1);
+ QVERIFY(spySignalExposureTimeChanged.size() ==1);
}
void tst_QCamera::testSignalFlashReady()
@@ -846,9 +827,9 @@ void tst_QCamera::testSignalFlashReady()
QCamera camera;
session.setCamera(&camera);
- QSignalSpy spyflashReady(&camera,SIGNAL(flashReady(bool)));
+ QSignalSpy spyflashReady(&camera, &QCamera::flashReady);
- QVERIFY(spyflashReady.count() == 0);
+ QVERIFY(spyflashReady.size() == 0);
QVERIFY(camera.flashMode() == QCamera::FlashAuto);
@@ -856,7 +837,7 @@ void tst_QCamera::testSignalFlashReady()
QVERIFY(camera.flashMode() == QCamera::FlashOff);
- QCOMPARE(spyflashReady.count(), 1);
+ QCOMPARE(spyflashReady.size(), 1);
}
QTEST_MAIN(tst_QCamera)
diff --git a/tests/auto/unit/multimedia/qcameradevice/CMakeLists.txt b/tests/auto/unit/multimedia/qcameradevice/CMakeLists.txt
index 150307fea..4d9977e8e 100644
--- a/tests/auto/unit/multimedia/qcameradevice/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qcameradevice/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qcameradevice.pro.
#####################################################################
@@ -9,9 +12,9 @@ qt_internal_add_test(tst_qcameradevice
tst_qcameradevice.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp b/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp
index c8f93330f..455586243 100644
--- a/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp
+++ b/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
@@ -33,42 +8,26 @@
#include <qcameradevice.h>
#include <qmediadevices.h>
-#include "qmockintegration_p.h"
-#include "qmockmediacapturesession.h"
+#include "qmockintegration.h"
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
+using namespace Qt::Literals;
+
class tst_QCameraDevice: public QObject
{
Q_OBJECT
-public slots:
- void initTestCase();
- void init();
- void cleanup();
-
private slots:
void constructor();
void defaultCamera();
void availableCameras();
void equality_operators();
-
-private:
- QMockIntegration integration;
+ void qDebug_operator();
};
-void tst_QCameraDevice::initTestCase()
-{
-}
-
-void tst_QCameraDevice::init()
-{
-}
-
-void tst_QCameraDevice::cleanup()
-{
-}
-
void tst_QCameraDevice::constructor()
{
{
@@ -76,8 +35,8 @@ void tst_QCameraDevice::constructor()
QCamera camera;
QCameraDevice info(camera.cameraDevice());
QVERIFY(!info.isNull());
- QCOMPARE(info.id(), QStringLiteral("default"));
- QCOMPARE(info.description(), QStringLiteral("defaultCamera"));
+ QCOMPARE(info.id(), u"default"_s);
+ QCOMPARE(info.description(), u"defaultCamera"_s);
QCOMPARE(info.position(), QCameraDevice::UnspecifiedPosition);
}
@@ -92,14 +51,14 @@ void tst_QCameraDevice::constructor()
QCamera camera(info);
QCOMPARE(info, camera.cameraDevice());
QVERIFY(!info.isNull());
- QCOMPARE(info.id(), QStringLiteral("back"));
- QCOMPARE(info.description(), QStringLiteral("backCamera"));
+ QCOMPARE(info.id(), u"back"_s);
+ QCOMPARE(info.description(), u"backCamera"_s);
QCOMPARE(info.position(), QCameraDevice::BackFace);
QCameraDevice info2(info);
QVERIFY(!info2.isNull());
- QCOMPARE(info2.id(), QStringLiteral("back"));
- QCOMPARE(info2.description(), QStringLiteral("backCamera"));
+ QCOMPARE(info2.id(), u"back"_s);
+ QCOMPARE(info2.description(), u"backCamera"_s);
QCOMPARE(info2.position(), QCameraDevice::BackFace);
}
@@ -108,8 +67,8 @@ void tst_QCameraDevice::defaultCamera()
QCameraDevice info = QMediaDevices::defaultVideoInput();
QVERIFY(!info.isNull());
- QCOMPARE(info.id(), QStringLiteral("default"));
- QCOMPARE(info.description(), QStringLiteral("defaultCamera"));
+ QCOMPARE(info.id(), u"default"_s);
+ QCOMPARE(info.description(), u"defaultCamera"_s);
QCOMPARE(info.position(), QCameraDevice::UnspecifiedPosition);
QCamera camera(info);
@@ -119,12 +78,12 @@ void tst_QCameraDevice::defaultCamera()
void tst_QCameraDevice::availableCameras()
{
QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
- QCOMPARE(cameras.count(), 3);
+ QCOMPARE(cameras.size(), 3);
QCameraDevice info = cameras.at(0);
QVERIFY(!info.isNull());
- QCOMPARE(info.id(), QStringLiteral("default"));
- QCOMPARE(info.description(), QStringLiteral("defaultCamera"));
+ QCOMPARE(info.id(), u"default"_s);
+ QCOMPARE(info.description(), u"defaultCamera"_s);
QCOMPARE(info.position(), QCameraDevice::UnspecifiedPosition);
info = cameras.at(1);
@@ -133,11 +92,11 @@ void tst_QCameraDevice::availableCameras()
QCOMPARE(info.description(), QStringLiteral("frontCamera"));
QCOMPARE(info.position(), QCameraDevice::FrontFace);
- QCOMPARE(cameras.count(), 3);
+ QCOMPARE(cameras.size(), 3);
info = cameras.at(2);
QVERIFY(!info.isNull());
- QCOMPARE(info.id(), QStringLiteral("back"));
- QCOMPARE(info.description(), QStringLiteral("backCamera"));
+ QCOMPARE(info.id(), u"back"_s);
+ QCOMPARE(info.description(), u"backCamera"_s);
QCOMPARE(info.position(), QCameraDevice::BackFace);
}
@@ -162,6 +121,18 @@ void tst_QCameraDevice::equality_operators()
}
}
+void tst_QCameraDevice::qDebug_operator()
+{
+ QString outputString;
+ QDebug debug(&outputString);
+ debug.nospace();
+
+ QCameraDevice defaultCamera = QMediaDevices::defaultVideoInput();
+ debug << defaultCamera;
+
+ QCOMPARE(outputString,
+ u"\"QCameraDevice(name=defaultCamera, id=default, position=UnspecifiedPosition)\" "_s);
+}
QTEST_MAIN(tst_QCameraDevice)
diff --git a/tests/auto/unit/multimedia/qerrorinfo/CMakeLists.txt b/tests/auto/unit/multimedia/qerrorinfo/CMakeLists.txt
new file mode 100644
index 000000000..ea6ac5690
--- /dev/null
+++ b/tests/auto/unit/multimedia/qerrorinfo/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qerrorinfo
+ SOURCES
+ tst_qerrorinfo.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/unit/multimedia/qerrorinfo/tst_qerrorinfo.cpp b/tests/auto/unit/multimedia/qerrorinfo/tst_qerrorinfo.cpp
new file mode 100644
index 000000000..0d266705d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qerrorinfo/tst_qerrorinfo.cpp
@@ -0,0 +1,117 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+// TESTED_COMPONENT=src/multimedia
+
+#include <QtTest/QtTest>
+#include <QSignalSpy>
+#include <private/qerrorinfo_p.h>
+
+QT_USE_NAMESPACE
+
+enum class TestError { ErrorA, ErrorB, NoError };
+
+using TestErrorInfo = QErrorInfo<TestError>;
+
+class TestNotifier : public QObject
+{
+ Q_OBJECT
+public:
+signals:
+ void errorOccurred(TestError error, QString errorDescription);
+ void errorChanged();
+};
+
+class tst_QErrorInfo : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void defaultConstructor_setsNoError();
+ void constructor_setsPassedError();
+
+ void setAndNotify_setsErrorAndNotifes_data();
+ void setAndNotify_setsErrorAndNotifes();
+};
+
+void tst_QErrorInfo::defaultConstructor_setsNoError()
+{
+ TestErrorInfo errorInfo;
+ QCOMPARE(errorInfo.code(), TestError::NoError);
+ QCOMPARE(errorInfo.description(), QString());
+}
+
+void tst_QErrorInfo::constructor_setsPassedError()
+{
+ TestErrorInfo errorInfo(TestError::ErrorB, "test error");
+ QCOMPARE(errorInfo.code(), TestError::ErrorB);
+ QCOMPARE(errorInfo.description(), "test error");
+}
+
+void tst_QErrorInfo::setAndNotify_setsErrorAndNotifes_data()
+{
+ QTest::addColumn<TestError>("initialError");
+ QTest::addColumn<QString>("initialErrorDescription");
+ QTest::addColumn<TestError>("error");
+ QTest::addColumn<QString>("errorDescription");
+ QTest::addColumn<bool>("errorChangedEmitted");
+ QTest::addColumn<bool>("errorOccurredEmitted");
+
+ QTest::newRow("No error -> No error")
+ << TestError::NoError << QString() << TestError::NoError << QString() << false << false;
+ QTest::newRow("No error -> An error with empty string")
+ << TestError::NoError << QString() << TestError::ErrorA << QString() << true << true;
+ QTest::newRow("No error -> An error with non-empty string")
+ << TestError::NoError << QString() << TestError::ErrorB << QStringLiteral("error") << true
+ << true;
+ QTest::newRow("An error with empty string -> No error")
+ << TestError::ErrorA << QString() << TestError::NoError << QString() << true << false;
+ QTest::newRow("An error with non-empty string -> No Error")
+ << TestError::ErrorA << QStringLiteral("error") << TestError::NoError << QString() << true
+ << false;
+ QTest::newRow("An error -> Another error")
+ << TestError::ErrorA << QStringLiteral("error A") << TestError::ErrorB << QStringLiteral("error B")
+ << true << true;
+ QTest::newRow("An error -> Another error with empty string")
+ << TestError::ErrorA << QStringLiteral("error A") << TestError::ErrorB << QString() << true
+ << true;
+ QTest::newRow("An error -> The same error with changed string")
+ << TestError::ErrorA << QStringLiteral("error") << TestError::ErrorA
+ << QStringLiteral("another error") << true << true;
+}
+
+void tst_QErrorInfo::setAndNotify_setsErrorAndNotifes()
+{
+ QFETCH(TestError, initialError);
+ QFETCH(QString, initialErrorDescription);
+ QFETCH(TestError, error);
+ QFETCH(QString, errorDescription);
+ QFETCH(bool, errorChangedEmitted);
+ QFETCH(bool, errorOccurredEmitted);
+
+ TestErrorInfo errorInfo(initialError, initialErrorDescription);
+
+ TestNotifier notifier;
+ QSignalSpy errorOccurredSpy(&notifier, &TestNotifier::errorOccurred);
+ QSignalSpy errorChangedSpy(&notifier, &TestNotifier::errorChanged);
+
+ errorInfo.setAndNotify(error, errorDescription, notifier);
+
+ QCOMPARE(errorInfo.code(), error);
+ QCOMPARE(errorInfo.description(), errorDescription);
+
+ QList<QList<QVariant>> expectedErrorChanged;
+ if (errorChangedEmitted)
+ expectedErrorChanged.push_back({});
+
+ QList<QList<QVariant>> expectedErrorOccured;
+ if (errorOccurredEmitted)
+ expectedErrorOccured.push_back({ QVariant::fromValue(error), errorDescription });
+
+ QCOMPARE(errorOccurredSpy, expectedErrorOccured);
+ QCOMPARE(errorChangedSpy, expectedErrorChanged);
+}
+
+QTEST_GUILESS_MAIN(tst_QErrorInfo)
+
+#include "tst_qerrorinfo.moc"
diff --git a/tests/auto/unit/multimedia/qimagecapture/CMakeLists.txt b/tests/auto/unit/multimedia/qimagecapture/CMakeLists.txt
index 11a2c79bc..908154cf9 100644
--- a/tests/auto/unit/multimedia/qimagecapture/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qimagecapture/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qimagecapture.pro.
#####################################################################
@@ -9,9 +12,9 @@ qt_internal_add_test(tst_qimagecapture
tst_qimagecapture.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimedia/qimagecapture/tst_qimagecapture.cpp b/tests/auto/unit/multimedia/qimagecapture/tst_qimagecapture.cpp
index b81f989db..3267b6f40 100644
--- a/tests/auto/unit/multimedia/qimagecapture/tst_qimagecapture.cpp
+++ b/tests/auto/unit/multimedia/qimagecapture/tst_qimagecapture.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
@@ -36,20 +11,16 @@
#include <qmediacapturesession.h>
#include "qmockmediacapturesession.h"
-#include "qmockintegration_p.h"
+#include "qmockintegration.h"
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
class tst_QImageCapture: public QObject
{
Q_OBJECT
-public slots:
- void initTestCase();
- void init();
- void cleanup();
- void cleanupTestCase();
-
private slots:
void constructor();
void isAvailable();
@@ -63,29 +34,8 @@ private slots:
void imageExposed();
void imageSaved();
void readyForCaptureChanged();
-
-private:
- QMockIntegration *mockIntegration;
};
-void tst_QImageCapture::initTestCase()
-{
- mockIntegration = new QMockIntegration;
-}
-
-void tst_QImageCapture::init()
-{
-}
-
-void tst_QImageCapture::cleanup()
-{
-}
-
-void tst_QImageCapture::cleanupTestCase()
-{
- delete mockIntegration;
-}
-
void tst_QImageCapture::constructor()
{
QMediaCaptureSession session;
@@ -199,7 +149,7 @@ void tst_QImageCapture::errors()
session.setImageCapture(&imageCapture);
QVERIFY(imageCapture.isAvailable() == true);
- imageCapture.captureToFile(QString::fromLatin1("/dev/null"));
+ imageCapture.captureToFile(QStringLiteral("/dev/null"));
QCOMPARE(imageCapture.error(), QImageCapture::NotReadyError);
QVERIFY(!imageCapture.errorString().isEmpty());
}
@@ -228,10 +178,10 @@ void tst_QImageCapture::error()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy spy(&imageCapture, SIGNAL(errorOccurred(int,QImageCapture::Error,QString)));
+ QSignalSpy spy(&imageCapture, &QImageCapture::errorOccurred);
imageCapture.captureToFile();
QTest::qWait(30);
- QVERIFY(spy.count() == 1);
+ QVERIFY(spy.size() == 1);
QVERIFY(qvariant_cast<int>(spy.at(0).at(0)) == -1);
QVERIFY(qvariant_cast<QImageCapture::Error>(spy.at(0).at(1)) == QImageCapture::NotReadyError);
QVERIFY(qvariant_cast<QString>(spy.at(0).at(2)) == "Could not capture in stopped state");
@@ -246,14 +196,14 @@ void tst_QImageCapture::imageCaptured()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy spy(&imageCapture, SIGNAL(imageCaptured(int,QImage)));
+ QSignalSpy spy(&imageCapture, &QImageCapture::imageCaptured);
QVERIFY(imageCapture.isAvailable() == true);
QVERIFY(imageCapture.isReadyForCapture() == false);
camera.start();
imageCapture.captureToFile();
QTRY_VERIFY(imageCapture.isReadyForCapture());
- QVERIFY(spy.count() == 1);
+ QVERIFY(spy.size() == 1);
QVERIFY(qvariant_cast<int>(spy.at(0).at(0)) > 0);
QImage image = qvariant_cast<QImage>(spy.at(0).at(1));
QVERIFY(image.isNull() == true);
@@ -269,14 +219,14 @@ void tst_QImageCapture::imageExposed()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy spy(&imageCapture, SIGNAL(imageExposed(int)));
+ QSignalSpy spy(&imageCapture, &QImageCapture::imageExposed);
QVERIFY(imageCapture.isAvailable() == true);
QVERIFY(imageCapture.isReadyForCapture() == false);
camera.start();
imageCapture.captureToFile();
QTRY_VERIFY(imageCapture.isReadyForCapture());
- QVERIFY(spy.count() == 1);
+ QVERIFY(spy.size() == 1);
QVERIFY(qvariant_cast<int>(spy.at(0).at(0)) > 0);
spy.clear();
camera.stop();
@@ -290,14 +240,14 @@ void tst_QImageCapture::imageSaved()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy spy(&imageCapture, SIGNAL(imageSaved(int,QString)));
+ QSignalSpy spy(&imageCapture, &QImageCapture::imageSaved);
QVERIFY(imageCapture.isAvailable() == true);
QVERIFY(imageCapture.isReadyForCapture() == false);
camera.start();
- imageCapture.captureToFile(QString::fromLatin1("/usr/share"));
+ imageCapture.captureToFile(QStringLiteral("/usr/share"));
QTRY_VERIFY(imageCapture.isReadyForCapture());
- QVERIFY(spy.count() == 1);
+ QVERIFY(spy.size() == 1);
QVERIFY(qvariant_cast<int>(spy.at(0).at(0)) > 0);
QVERIFY(qvariant_cast<QString>(spy.at(0).at(1)) == "/usr/share");
spy.clear();
@@ -312,17 +262,17 @@ void tst_QImageCapture::readyForCaptureChanged()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy spy(&imageCapture, SIGNAL(readyForCaptureChanged(bool)));
+ QSignalSpy spy(&imageCapture, &QImageCapture::readyForCaptureChanged);
QVERIFY(imageCapture.isReadyForCapture() == false);
imageCapture.captureToFile();
QTest::qWait(100);
- QVERIFY(spy.count() == 0);
+ QVERIFY(spy.size() == 0);
QVERIFY2(!imageCapture.errorString().isEmpty(),"Could not capture in stopped state" );
camera.start();
QTest::qWait(100);
imageCapture.captureToFile();
QTest::qWait(100);
- QVERIFY(spy.count() == 2);
+ QVERIFY(spy.size() == 2);
QVERIFY(spy.at(0).at(0).toBool() == false);
QVERIFY(spy.at(1).at(0).toBool() == true);
camera.stop();
diff --git a/tests/auto/unit/multimedia/qmaybe/CMakeLists.txt b/tests/auto/unit/multimedia/qmaybe/CMakeLists.txt
new file mode 100644
index 000000000..a9053e87c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmaybe/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qmaybe
+ SOURCES
+ tst_qmaybe.cpp
+ LIBRARIES
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/unit/multimedia/qmaybe/tst_qmaybe.cpp b/tests/auto/unit/multimedia/qmaybe/tst_qmaybe.cpp
new file mode 100644
index 000000000..fbf21a26d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmaybe/tst_qmaybe.cpp
@@ -0,0 +1,124 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <private/qmaybe_p.h>
+#include <QtCore/private/quniquehandle_p.h>
+#ifdef Q_OS_WINDOWS
+#include <private/qcomptr_p.h>
+#include <private/qcomobject_p.h>
+#endif
+
+QT_USE_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace {
+
+// Helpers used to verify interop with QUniqueHandle and ComPtr which
+// overloads operator&
+struct DummyHandleTraits
+{
+ using Type = int;
+ static Type invalidValue() { return -1; }
+ static bool close(Type /*handle*/) { return true; }
+};
+
+using DummyHandle = QUniqueHandle<DummyHandleTraits>;
+
+#ifdef Q_OS_WINDOWS
+struct DummyComObject : QComObject<IUnknown>
+{
+};
+#endif
+
+} // namespace
+
+//clang-format off
+
+class tst_QMaybe : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void operatorBool_returnsFalse_onlyWhenErrorSet()
+ {
+ {
+ const QMaybe<QString, int> error{ -1 }; // TOOD: Is it safe to deduce expected/unexpected only based on type?
+ QVERIFY(!static_cast<bool>(error));
+ }
+
+ {
+ const QMaybe<QString, int> success{ "It worked!"_L1 };
+ QVERIFY(static_cast<bool>(success));
+ }
+ }
+
+ void value_returnsReferenceToValue_whenValueSet()
+ {
+ {
+ QMaybe mutableVal{ 1 };
+ mutableVal.value() = 2;
+ QCOMPARE_EQ(*mutableVal, 2); // value() must have returned a mutable reference
+ }
+
+ {
+ const QMaybe immutableVal{ 2 };
+ QCOMPARE_EQ(*std::addressof(immutableVal.value()), 2); // value() must have returned a reference
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(immutableVal.value())>>); // And it is const
+ }
+ }
+
+ void dereferenceOperator_returnsPointerToValue_whenValueTypeOverloadsAddressOfOperator()
+ {
+ {
+ QMaybe<DummyHandle, int> mutableValue{ DummyHandle{ 1 } };
+ QCOMPARE_EQ(mutableValue->get(), 1);
+ QVERIFY(mutableValue->isValid()); // We did not accidentally call operator& that resets
+ // QUniqueHandle
+ }
+
+ {
+ const QMaybe<DummyHandle, int> immutableValue{ DummyHandle{ 2 } };
+ QCOMPARE_EQ(immutableValue->get(), 2);
+ QVERIFY(immutableValue->isValid()); // We did not accidentally call operator& that
+ // resets QUniqueHandle
+ }
+ }
+
+#ifdef Q_OS_WINDOWS
+ void dereferenceOperator_returnsPointerToValue_whenValueIsComPtr()
+ {
+ // Similar test as with QUniqueHandle, but with ComPtr that is used
+ // frequently on Windows and may behave slightly differently
+
+ {
+ QMaybe<ComPtr<DummyComObject>, HRESULT> mutableObject{
+ makeComObject<DummyComObject>()
+ };
+ QCOMPARE_NE(mutableObject->Get(), nullptr);
+
+ const ComPtr<IUnknown> unknownFromMutable = mutableObject.value();
+ QVERIFY(unknownFromMutable); // We did not accidentally call operator& that resets
+ // QUniqueHandle
+ }
+
+ {
+ QMaybe<ComPtr<DummyComObject>, HRESULT> immutableObject{
+ makeComObject<DummyComObject>()
+ };
+ QCOMPARE_NE(immutableObject->Get(), nullptr);
+
+ const ComPtr<IUnknown> unknownFromImmutable = immutableObject.value();
+ QVERIFY(unknownFromImmutable); // We did not accidentally call operator& that resets
+ // QUniqueHandle
+ }
+ }
+#endif
+};
+
+QTEST_APPLESS_MAIN(tst_QMaybe)
+
+#include "tst_qmaybe.moc"
+
+//clang-format on
diff --git a/tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt b/tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt
new file mode 100644
index 000000000..209be5883
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmediacapture_gstreamer Test:
+#####################################################################
+
+qt_internal_add_test(tst_qmediacapture_gstreamer
+ SOURCES
+ tst_qmediacapture_gstreamer.cpp
+ ../../../shared/qscopedenvironmentvariable.h
+ INCLUDE_DIRECTORIES
+ ../../../shared
+ LIBRARIES
+ Qt::Multimedia
+ Qt::MultimediaPrivate
+ Qt::QGstreamerMediaPluginPrivate
+)
diff --git a/tests/auto/unit/multimedia/qmediacapture_gstreamer/tst_qmediacapture_gstreamer.cpp b/tests/auto/unit/multimedia/qmediacapture_gstreamer/tst_qmediacapture_gstreamer.cpp
new file mode 100644
index 000000000..7fe6a06ac
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediacapture_gstreamer/tst_qmediacapture_gstreamer.cpp
@@ -0,0 +1,212 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QtMultimedia/QAudioDevice>
+#include <QtMultimedia/QAudioInput>
+#include <QtMultimedia/QAudioOutput>
+#include <QtMultimedia/QCamera>
+#include <QtMultimedia/QMediaCaptureSession>
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+#include <QtMultimedia/private/qplatformmediacapture_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgstpipeline_p.h>
+
+#include <qscopedenvironmentvariable.h>
+
+#include <memory>
+
+// NOLINTBEGIN(readability-convert-member-functions-to-static)
+
+QT_USE_NAMESPACE
+
+using namespace Qt::Literals;
+
+class tst_QMediaCaptureGStreamer : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QMediaCaptureGStreamer();
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void mediaIntegration_hasPlatformSpecificInterface();
+ void constructor_preparesGstPipeline();
+ void audioInput_makeCustomGStreamerAudioInput_fromPipelineDescription();
+ void audioOutput_makeCustomGStreamerAudioOutput_fromPipelineDescription();
+
+ void makeCustomGStreamerCamera_fromPipelineDescription();
+ void makeCustomGStreamerCamera_fromPipelineDescription_multipleItems();
+ void makeCustomGStreamerCamera_fromPipelineDescription_userProvidedGstElement();
+
+private:
+ std::unique_ptr<QMediaCaptureSession> session;
+
+ QGStreamerPlatformSpecificInterface *gstInterface()
+ {
+ return QGStreamerPlatformSpecificInterface::instance();
+ }
+
+ GstPipeline *getGstPipeline()
+ {
+ auto *iface = QGStreamerPlatformSpecificInterface::instance();
+ return iface ? iface->gstPipeline(session.get()) : nullptr;
+ }
+
+ QGstPipeline getPipeline()
+ {
+ return QGstPipeline{
+ getGstPipeline(),
+ QGstPipeline::NeedsRef,
+ };
+ }
+
+ void dumpGraph(const char *fileNamePrefix)
+ {
+ GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(getGstPipeline()),
+ GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_VERBOSE),
+ fileNamePrefix);
+ }
+};
+
+tst_QMediaCaptureGStreamer::tst_QMediaCaptureGStreamer()
+{
+ qputenv("QT_MEDIA_BACKEND", "gstreamer");
+}
+
+void tst_QMediaCaptureGStreamer::init()
+{
+ session = std::make_unique<QMediaCaptureSession>();
+}
+
+void tst_QMediaCaptureGStreamer::cleanup()
+{
+ session.reset();
+}
+
+void tst_QMediaCaptureGStreamer::mediaIntegration_hasPlatformSpecificInterface()
+{
+ QVERIFY(QGStreamerPlatformSpecificInterface::instance());
+}
+
+void tst_QMediaCaptureGStreamer::constructor_preparesGstPipeline()
+{
+ auto *rawPipeline = getGstPipeline();
+ QVERIFY(rawPipeline);
+
+ QGstPipeline pipeline{
+ rawPipeline,
+ QGstPipeline::NeedsRef,
+ };
+ QVERIFY(pipeline);
+
+ dumpGraph("constructor_preparesGstPipeline");
+}
+
+void tst_QMediaCaptureGStreamer::audioInput_makeCustomGStreamerAudioInput_fromPipelineDescription()
+{
+ auto pipelineString =
+ "audiotestsrc wave=2 freq=200 name=myOscillator ! identity name=myConverter"_ba;
+
+ QAudioInput input{
+ gstInterface()->makeCustomGStreamerAudioInput(pipelineString),
+ };
+
+ session->setAudioInput(&input);
+
+ QGstPipeline pipeline = getPipeline();
+ QTEST_ASSERT(pipeline);
+
+ pipeline.finishStateChange();
+
+ QVERIFY(pipeline.findByName("myOscillator"));
+ QVERIFY(pipeline.findByName("myConverter"));
+
+ dumpGraph("audioInput_customAudioDevice");
+}
+
+void tst_QMediaCaptureGStreamer::
+ audioOutput_makeCustomGStreamerAudioOutput_fromPipelineDescription()
+{
+ auto pipelineStringInput =
+ "audiotestsrc wave=2 freq=200 name=myOscillator ! identity name=myConverter"_ba;
+ QAudioInput input{
+ gstInterface()->makeCustomGStreamerAudioInput(pipelineStringInput),
+ };
+ session->setAudioInput(&input);
+
+ auto pipelineStringOutput = "identity name=myConverter ! fakesink name=mySink"_ba;
+ QAudioOutput output{
+ gstInterface()->makeCustomGStreamerAudioOutput(pipelineStringOutput),
+ };
+ session->setAudioOutput(&output);
+
+ QGstPipeline pipeline = getPipeline();
+ QTEST_ASSERT(pipeline);
+
+ pipeline.finishStateChange();
+
+ QVERIFY(pipeline.findByName("mySink"));
+ QVERIFY(pipeline.findByName("myConverter"));
+
+ dumpGraph("audioOutput_customAudioDevice");
+}
+
+void tst_QMediaCaptureGStreamer::makeCustomGStreamerCamera_fromPipelineDescription()
+{
+ auto pipelineString = "videotestsrc name=mySrc"_ba;
+ QCamera *cam =
+ gstInterface()->makeCustomGStreamerCamera(pipelineString, /*parent=*/session.get());
+
+ session->setCamera(cam);
+ cam->start();
+
+ QGstPipeline pipeline = getPipeline();
+ QTEST_ASSERT(pipeline);
+ QVERIFY(pipeline.findByName("mySrc"));
+ dumpGraph("makeCustomGStreamerCamera_fromPipelineDescription");
+}
+
+void tst_QMediaCaptureGStreamer::makeCustomGStreamerCamera_fromPipelineDescription_multipleItems()
+{
+ auto pipelineString = "videotestsrc name=mySrc ! gamma gamma=2.0 name=myFilter"_ba;
+ QCamera *cam =
+ gstInterface()->makeCustomGStreamerCamera(pipelineString, /*parent=*/session.get());
+
+ session->setCamera(cam);
+ cam->start();
+
+ QGstPipeline pipeline = getPipeline();
+ QTEST_ASSERT(pipeline);
+ QVERIFY(pipeline.findByName("mySrc"));
+ QVERIFY(pipeline.findByName("myFilter"));
+ dumpGraph("makeCustomGStreamerCamera_fromPipelineDescription_multipleItems");
+}
+
+void tst_QMediaCaptureGStreamer::
+ makeCustomGStreamerCamera_fromPipelineDescription_userProvidedGstElement()
+{
+ QGstElement element = QGstElement::createFromPipelineDescription("videotestsrc");
+ gst_element_set_name(element.element(), "mySrc");
+
+ QCamera *cam =
+ gstInterface()->makeCustomGStreamerCamera(element.element(), /*parent=*/session.get());
+
+ session->setCamera(cam);
+ cam->start();
+
+ QGstPipeline pipeline = getPipeline();
+ QTEST_ASSERT(pipeline);
+ QCOMPARE(pipeline.findByName("mySrc"), element);
+ dumpGraph("makeCustomGStreamerCamera_fromPipelineDescription_userProvidedGstElement");
+
+ element.set("foreground-color", 0xff0000);
+ dumpGraph("makeCustomGStreamerCamera_fromPipelineDescription_userProvidedGstElement2");
+}
+
+QTEST_GUILESS_MAIN(tst_QMediaCaptureGStreamer)
+
+#include "tst_qmediacapture_gstreamer.moc"
diff --git a/tests/auto/unit/multimedia/qmediadevices/CMakeLists.txt b/tests/auto/unit/multimedia/qmediadevices/CMakeLists.txt
new file mode 100644
index 000000000..e8360f8b5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediadevices/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qmediadevices
+ SOURCES
+ tst_qmediadevices.cpp
+ INCLUDE_DIRECTORIES
+ ../../mockbackend
+ LIBRARIES
+ Qt::Gui
+ Qt::MultimediaPrivate
+ MockMultimediaPlugin
+)
diff --git a/tests/auto/unit/multimedia/qmediadevices/tst_qmediadevices.cpp b/tests/auto/unit/multimedia/qmediadevices/tst_qmediadevices.cpp
new file mode 100644
index 000000000..9767c0e73
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediadevices/tst_qmediadevices.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QDebug>
+
+#include <qmediadevices.h>
+
+#include "qmockintegration.h"
+
+QT_USE_NAMESPACE
+
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
+class tst_QMediaDevices : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void videoInputsChangedEmitted_whenCamerasChanged();
+ void onlyVideoInputsChangedEmitted_when2MediaDevicesCreated_andCamerasChanged();
+};
+
+void tst_QMediaDevices::videoInputsChangedEmitted_whenCamerasChanged()
+{
+ QMediaDevices mediaDevices;
+ QSignalSpy videoInputsSpy(&mediaDevices, &QMediaDevices::videoInputsChanged);
+
+ QCOMPARE(videoInputsSpy.size(), 0);
+
+ QMockIntegration::instance()->addNewCamera();
+ QTRY_COMPARE(videoInputsSpy.size(), 1);
+
+ QMockIntegration::instance()->addNewCamera();
+ QCOMPARE(videoInputsSpy.size(), 2);
+}
+
+void tst_QMediaDevices::onlyVideoInputsChangedEmitted_when2MediaDevicesCreated_andCamerasChanged()
+{
+ QMediaDevices mediaDevicesA;
+ QMediaDevices mediaDevicesB;
+
+ QSignalSpy videoInputsSpyA(&mediaDevicesA, &QMediaDevices::videoInputsChanged);
+ QSignalSpy videoInputsSpyB(&mediaDevicesB, &QMediaDevices::videoInputsChanged);
+ QSignalSpy audioInputsSpy(&mediaDevicesA, &QMediaDevices::audioInputsChanged);
+ QSignalSpy audioOutputsSpy(&mediaDevicesA, &QMediaDevices::audioOutputsChanged);
+
+ QMockIntegration::instance()->addNewCamera();
+ QCOMPARE(videoInputsSpyA.size(), 1);
+ QCOMPARE(videoInputsSpyB.size(), 1);
+
+ QCOMPARE(audioInputsSpy.size(), 0);
+ QCOMPARE(audioOutputsSpy.size(), 0);
+}
+
+QTEST_MAIN(tst_QMediaDevices)
+
+#include "tst_qmediadevices.moc"
diff --git a/tests/auto/unit/multimedia/qmediaformat/CMakeLists.txt b/tests/auto/unit/multimedia/qmediaformat/CMakeLists.txt
index 23c4ad18c..4ad36e7bb 100644
--- a/tests/auto/unit/multimedia/qmediaformat/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qmediaformat/CMakeLists.txt
@@ -1,7 +1,10 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_internal_add_test(tst_qmediaformat
SOURCES
tst_qmediaformat.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/unit/multimedia/qmediaformat/tst_qmediaformat.cpp b/tests/auto/unit/multimedia/qmediaformat/tst_qmediaformat.cpp
index b3d45e727..9f1345db6 100644
--- a/tests/auto/unit/multimedia/qmediaformat/tst_qmediaformat.cpp
+++ b/tests/auto/unit/multimedia/qmediaformat/tst_qmediaformat.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
diff --git a/tests/auto/unit/multimedia/qmediametadata/CMakeLists.txt b/tests/auto/unit/multimedia/qmediametadata/CMakeLists.txt
new file mode 100644
index 000000000..7b7b8f174
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediametadata/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmediametadata Test:
+#####################################################################
+
+qt_internal_add_test(tst_qmediametadata
+ SOURCES
+ tst_qmediametadata.cpp
+ LIBRARIES
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/unit/multimedia/qmediametadata/tst_qmediametadata.cpp b/tests/auto/unit/multimedia/qmediametadata/tst_qmediametadata.cpp
new file mode 100644
index 000000000..a3763399d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediametadata/tst_qmediametadata.cpp
@@ -0,0 +1,96 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/QString>
+
+#include <QtMultimedia/qmediametadata.h>
+
+QT_USE_NAMESPACE
+
+using namespace Qt::Literals;
+
+class tst_QMediaMetaData : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void insertAndRemove();
+ void qdebug_empty();
+ void qdebug_printContent();
+};
+
+void tst_QMediaMetaData::insertAndRemove()
+{
+ QMediaMetaData dut;
+ QVERIFY(dut.isEmpty());
+
+ // fill
+ dut.insert(QMediaMetaData::Author, "yada");
+ dut.insert(QMediaMetaData::Title, "title");
+ QVERIFY(!dut.isEmpty());
+
+ // validate
+ {
+ auto range = dut.asKeyValueRange();
+ QCOMPARE_EQ(std::distance(range.begin(), range.end()), 2u);
+
+ QSet expectedKeys{
+ QMediaMetaData::Author,
+ QMediaMetaData::Title,
+ };
+
+ QList keyList = dut.keys();
+ QSet<QMediaMetaData::Key> keys{ keyList.begin(), keyList.end() };
+
+ QCOMPARE_EQ(keys, expectedKeys);
+
+ QCOMPARE(dut.value(QMediaMetaData::Author), u"yada"_s);
+ QCOMPARE(dut.stringValue(QMediaMetaData::Author), u"yada"_s);
+ };
+
+ // remove missing key
+ QMediaMetaData reference = dut;
+ dut.remove(QMediaMetaData::AlbumArtist);
+ QCOMPARE_EQ(dut, reference);
+
+ // clear
+ dut.clear();
+ QVERIFY(dut.isEmpty());
+}
+
+void tst_QMediaMetaData::qdebug_empty()
+{
+ QMediaMetaData dut;
+
+ QString str;
+ QDebug dbg(&str);
+ dbg << dut;
+
+ auto expected = u"QMediaMetaData{} ";
+
+ QCOMPARE_EQ(str, expected);
+}
+
+void tst_QMediaMetaData::qdebug_printContent()
+{
+ QMediaMetaData dut;
+ dut.insert(QMediaMetaData::Author, "yada");
+ dut.insert(QMediaMetaData::Title, "title");
+
+ QString str;
+ QDebug dbg(&str);
+ dbg << dut;
+
+ auto expected = u"QMediaMetaData{QMediaMetaData::Title: QVariant(QString, \"title\"), "
+ u"QMediaMetaData::Author: QVariant(QString, \"yada\")} ";
+ auto expected2 = u"QMediaMetaData{QMediaMetaData::Author: QVariant(QString, \"yada\"), "
+ u"QMediaMetaData::Title: QVariant(QString, \"title\")} ";
+
+ QVERIFY(str == expected || str == expected2);
+}
+
+QTEST_GUILESS_MAIN(tst_QMediaMetaData)
+#include "tst_qmediametadata.moc"
diff --git a/tests/auto/unit/multimedia/qmediaplayer/CMakeLists.txt b/tests/auto/unit/multimedia/qmediaplayer/CMakeLists.txt
index cc9e39503..4d3f2f865 100644
--- a/tests/auto/unit/multimedia/qmediaplayer/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qmediaplayer/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qmediaplayer.pro.
#####################################################################
@@ -9,12 +12,12 @@ qt_internal_add_test(tst_qmediaplayer
tst_qmediaplayer.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
Qt::Network
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
# Resources:
diff --git a/tests/auto/unit/multimedia/qmediaplayer/tst_qmediaplayer.cpp b/tests/auto/unit/multimedia/qmediaplayer/tst_qmediaplayer.cpp
index bf48b7f9a..3fb77ca2d 100644
--- a/tests/auto/unit/multimedia/qmediaplayer/tst_qmediaplayer.cpp
+++ b/tests/auto/unit/multimedia/qmediaplayer/tst_qmediaplayer.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -38,7 +11,7 @@
#include <private/qplatformmediaplayer_p.h>
#include <qobject.h>
-#include "qmockintegration_p.h"
+#include "qmockintegration.h"
#include "qmockmediaplayer.h"
#include "qmockaudiooutput.h"
#include "qvideosink.h"
@@ -46,6 +19,8 @@
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
class AutoConnection
{
public:
@@ -123,7 +98,6 @@ private slots:
private:
void setupCommonTestData();
- QMockIntegration *mockIntegration;
QMockMediaPlayer *mockPlayer;
QAudioOutput *audioOutput = nullptr;
QMediaPlayer *player;
@@ -200,7 +174,7 @@ void tst_QMediaPlayer::setupCommonTestData()
qreal(1) << QMediaPlayer::NoError << QString();
QTest::newRow("valid+error") << true << QMediaPlayer::StoppedState << QMediaPlayer::InvalidMedia <<
QUrl(QUrl("http://example.com/stream")) << qint64(0) << qint64(0) << false << 50 << false << false << 0 <<
- qreal(0) << QMediaPlayer::ResourceError << QString("Resource unavailable");
+ qreal(0) << QMediaPlayer::ResourceError << QStringLiteral("Resource unavailable");
}
void tst_QMediaPlayer::initTestCase()
@@ -213,9 +187,8 @@ void tst_QMediaPlayer::cleanupTestCase()
void tst_QMediaPlayer::init()
{
- mockIntegration = new QMockIntegration;
player = new QMediaPlayer;
- mockPlayer = mockIntegration->lastPlayer();
+ mockPlayer = QMockIntegration::instance()->lastPlayer();
Q_ASSERT(mockPlayer);
audioOutput = new QAudioOutput;
player->setAudioOutput(audioOutput);
@@ -225,7 +198,6 @@ void tst_QMediaPlayer::init()
void tst_QMediaPlayer::cleanup()
{
delete player;
- delete mockIntegration;
}
void tst_QMediaPlayer::testValid()
@@ -322,36 +294,44 @@ void tst_QMediaPlayer::testPosition()
QVERIFY(player->duration() == duration);
if (seekable) {
- { QSignalSpy spy(player, SIGNAL(positionChanged(qint64)));
- player->setPosition(position);
- QCOMPARE(player->position(), position);
- QCOMPARE(spy.count(), 0); }
+ {
+ QSignalSpy spy(player, &QMediaPlayer::positionChanged);
+ player->setPosition(position);
+ QCOMPARE(player->position(), position);
+ QCOMPARE(spy.size(), 0);
+ }
mockPlayer->setPosition(position);
- { QSignalSpy spy(player, SIGNAL(positionChanged(qint64)));
- player->setPosition(0);
- QCOMPARE(player->position(), qint64(0));
- QCOMPARE(spy.count(), position == 0 ? 0 : 1); }
+ {
+ QSignalSpy spy(player, &QMediaPlayer::positionChanged);
+ player->setPosition(0);
+ QCOMPARE(player->position(), qint64(0));
+ QCOMPARE(spy.size(), position == 0 ? 0 : 1);
+ }
mockPlayer->setPosition(position);
- { QSignalSpy spy(player, SIGNAL(positionChanged(qint64)));
- player->setPosition(duration);
- QCOMPARE(player->position(), duration);
- QCOMPARE(spy.count(), position == duration ? 0 : 1); }
+ {
+ QSignalSpy spy(player, &QMediaPlayer::positionChanged);
+ player->setPosition(duration);
+ QCOMPARE(player->position(), duration);
+ QCOMPARE(spy.size(), position == duration ? 0 : 1);
+ }
mockPlayer->setPosition(position);
- { QSignalSpy spy(player, SIGNAL(positionChanged(qint64)));
- player->setPosition(-1);
- QCOMPARE(player->position(), qint64(0));
- QCOMPARE(spy.count(), position == 0 ? 0 : 1); }
+ {
+ QSignalSpy spy(player, &QMediaPlayer::positionChanged);
+ player->setPosition(-1);
+ QCOMPARE(player->position(), qint64(0));
+ QCOMPARE(spy.size(), position == 0 ? 0 : 1);
+ }
}
else {
- QSignalSpy spy(player, SIGNAL(positionChanged(qint64)));
+ QSignalSpy spy(player, &QMediaPlayer::positionChanged);
player->setPosition(position);
QCOMPARE(player->position(), position);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
}
}
@@ -370,25 +350,33 @@ void tst_QMediaPlayer::testVolume()
QVERIFY(audioOutput->volume() == vol);
if (valid) {
- { QSignalSpy spy(audioOutput, SIGNAL(volumeChanged(float)));
- audioOutput->setVolume(.1f);
- QCOMPARE(audioOutput->volume(), .1f);
- QCOMPARE(spy.count(), 1); }
-
- { QSignalSpy spy(audioOutput, SIGNAL(volumeChanged(float)));
- audioOutput->setVolume(-1000.f);
- QCOMPARE(audioOutput->volume(), 0.f);
- QCOMPARE(spy.count(), 1); }
-
- { QSignalSpy spy(audioOutput, SIGNAL(volumeChanged(float)));
- audioOutput->setVolume(1.f);
- QCOMPARE(audioOutput->volume(), 1.f);
- QCOMPARE(spy.count(), 1); }
-
- { QSignalSpy spy(audioOutput, SIGNAL(volumeChanged(float)));
- audioOutput->setVolume(1000.f);
- QCOMPARE(audioOutput->volume(), 1.f);
- QCOMPARE(spy.count(), 0); }
+ {
+ QSignalSpy spy(audioOutput, &QAudioOutput::volumeChanged);
+ audioOutput->setVolume(.1f);
+ QCOMPARE(audioOutput->volume(), .1f);
+ QCOMPARE(spy.size(), 1);
+ }
+
+ {
+ QSignalSpy spy(audioOutput, &QAudioOutput::volumeChanged);
+ audioOutput->setVolume(-1000.f);
+ QCOMPARE(audioOutput->volume(), 0.f);
+ QCOMPARE(spy.size(), 1);
+ }
+
+ {
+ QSignalSpy spy(audioOutput, &QAudioOutput::volumeChanged);
+ audioOutput->setVolume(1.f);
+ QCOMPARE(audioOutput->volume(), 1.f);
+ QCOMPARE(spy.size(), 1);
+ }
+
+ {
+ QSignalSpy spy(audioOutput, &QAudioOutput::volumeChanged);
+ audioOutput->setVolume(1000.f);
+ QCOMPARE(audioOutput->volume(), 1.f);
+ QCOMPARE(spy.size(), 0);
+ }
}
}
@@ -409,11 +397,11 @@ void tst_QMediaPlayer::testMuted()
audioOutput->setVolume(vol);
QVERIFY(audioOutput->isMuted() == muted);
- QSignalSpy spy(audioOutput, SIGNAL(mutedChanged(bool)));
+ QSignalSpy spy(audioOutput, &QAudioOutput::mutedChanged);
audioOutput->setMuted(!muted);
QCOMPARE(audioOutput->isMuted(), !muted);
QCOMPARE(audioOutput->volume(), vol);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
}
@@ -470,10 +458,10 @@ void tst_QMediaPlayer::testPlaybackRate()
mockPlayer->setPlaybackRate(playbackRate);
QVERIFY(player->playbackRate() == playbackRate);
- QSignalSpy spy(player, SIGNAL(playbackRateChanged(qreal)));
+ QSignalSpy spy(player, &QMediaPlayer::playbackRateChanged);
player->setPlaybackRate(playbackRate + 0.5f);
QCOMPARE(player->playbackRate(), playbackRate + 0.5f);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
}
@@ -537,19 +525,25 @@ void tst_QMediaPlayer::testPlay()
player->setSource(mediaContent);
mockPlayer->setState(state);
QCOMPARE(player->playbackState(), state);
+ QCOMPARE(player->isPlaying(), state == QMediaPlayer::PlayingState);
QCOMPARE(player->source(), mediaContent);
- QSignalSpy spy(player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
+ QSignalSpy spy(player, &QMediaPlayer::playbackStateChanged);
+ QSignalSpy playingChanged(player, &QMediaPlayer::playingChanged);
player->play();
if (!valid || mediaContent.isEmpty()) {
QCOMPARE(player->playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(spy.count(), 0);
+ QVERIFY(!player->isPlaying());
+ QCOMPARE(spy.size(), 0);
+ QVERIFY(playingChanged.empty());
}
else {
QCOMPARE(player->playbackState(), QMediaPlayer::PlayingState);
- QCOMPARE(spy.count(), state == QMediaPlayer::PlayingState ? 0 : 1);
+ QVERIFY(player->isPlaying());
+ QCOMPARE(spy.size(), state == QMediaPlayer::PlayingState ? 0 : 1);
+ QCOMPARE_EQ(playingChanged.size(), state == QMediaPlayer::PlayingState ? 0 : 1);
}
}
@@ -568,19 +562,25 @@ void tst_QMediaPlayer::testPause()
player->setSource(mediaContent);
mockPlayer->setState(state);
QVERIFY(player->playbackState() == state);
+ QCOMPARE(player->isPlaying(), state == QMediaPlayer::PlayingState);
QVERIFY(player->source() == mediaContent);
- QSignalSpy spy(player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
+ QSignalSpy spy(player, &QMediaPlayer::playbackStateChanged);
+ QSignalSpy playingChanged(player, &QMediaPlayer::playingChanged);
player->pause();
+ QVERIFY(!player->isPlaying());
+
if (!valid || mediaContent.isEmpty()) {
QCOMPARE(player->playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
+ QCOMPARE(playingChanged.size(), 0);
}
else {
QCOMPARE(player->playbackState(), QMediaPlayer::PausedState);
- QCOMPARE(spy.count(), state == QMediaPlayer::PausedState ? 0 : 1);
+ QCOMPARE(spy.size(), state == QMediaPlayer::PausedState ? 0 : 1);
+ QCOMPARE(playingChanged.size(), state == QMediaPlayer::PlayingState ? 1 : 0);
}
}
@@ -597,19 +597,25 @@ void tst_QMediaPlayer::testStop()
player->setSource(mediaContent);
mockPlayer->setState(state);
QVERIFY(player->playbackState() == state);
+ QCOMPARE(player->isPlaying(), state == QMediaPlayer::PlayingState);
QVERIFY(player->source() == mediaContent);
- QSignalSpy spy(player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)));
+ QSignalSpy spy(player, &QMediaPlayer::playbackStateChanged);
+ QSignalSpy playingChanged(player, &QMediaPlayer::playingChanged);
player->stop();
+ QVERIFY(!player->isPlaying());
+
if (mediaContent.isEmpty() || state == QMediaPlayer::StoppedState) {
QCOMPARE(player->playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
+ QCOMPARE(playingChanged.size(), 0);
}
else {
QCOMPARE(player->playbackState(), QMediaPlayer::StoppedState);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
+ QCOMPARE(playingChanged.size(), state == QMediaPlayer::PlayingState ? 1 : 0);
}
}
@@ -626,65 +632,65 @@ void tst_QMediaPlayer::testMediaStatus()
mockPlayer->setMediaStatus(QMediaPlayer::NoMedia);
mockPlayer->setBufferStatus(bufferProgress);
- QSignalSpy statusSpy(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
- QSignalSpy bufferSpy(player, SIGNAL(bufferProgressChanged(float)));
+ QSignalSpy statusSpy(player, &QMediaPlayer::mediaStatusChanged);
+ QSignalSpy bufferSpy(player, &QMediaPlayer::bufferProgressChanged);
QCOMPARE(player->mediaStatus(), QMediaPlayer::NoMedia);
mockPlayer->setMediaStatus(QMediaPlayer::LoadingMedia);
QCOMPARE(player->mediaStatus(), QMediaPlayer::LoadingMedia);
- QCOMPARE(statusSpy.count(), 1);
+ QCOMPARE(statusSpy.size(), 1);
QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)),
QMediaPlayer::LoadingMedia);
mockPlayer->setMediaStatus(QMediaPlayer::LoadedMedia);
QCOMPARE(player->mediaStatus(), QMediaPlayer::LoadedMedia);
- QCOMPARE(statusSpy.count(), 2);
+ QCOMPARE(statusSpy.size(), 2);
QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)),
QMediaPlayer::LoadedMedia);
// Verify the bufferProgressChanged() signal isn't being emitted.
- QCOMPARE(bufferSpy.count(), 0);
+ QCOMPARE(bufferSpy.size(), 0);
mockPlayer->setMediaStatus(QMediaPlayer::StalledMedia);
QCOMPARE(player->mediaStatus(), QMediaPlayer::StalledMedia);
- QCOMPARE(statusSpy.count(), 3);
+ QCOMPARE(statusSpy.size(), 3);
QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)),
QMediaPlayer::StalledMedia);
// Verify the bufferProgressChanged() signal is being emitted.
- QVERIFY(bufferSpy.count() > bufferSignals);
+ QVERIFY(bufferSpy.size() > bufferSignals);
QCOMPARE(bufferSpy.last().value(0).toInt(), bufferProgress);
- bufferSignals = bufferSpy.count();
+ bufferSignals = bufferSpy.size();
mockPlayer->setMediaStatus(QMediaPlayer::BufferingMedia);
QCOMPARE(player->mediaStatus(), QMediaPlayer::BufferingMedia);
- QCOMPARE(statusSpy.count(), 4);
+ QCOMPARE(statusSpy.size(), 4);
QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)),
QMediaPlayer::BufferingMedia);
// Verify the bufferProgressChanged() signal is being emitted.
- QVERIFY(bufferSpy.count() > bufferSignals);
+ QVERIFY(bufferSpy.size() > bufferSignals);
QCOMPARE(bufferSpy.last().value(0).toInt(), bufferProgress);
- bufferSignals = bufferSpy.count();
+ bufferSignals = bufferSpy.size();
mockPlayer->setMediaStatus(QMediaPlayer::BufferedMedia);
QCOMPARE(player->mediaStatus(), QMediaPlayer::BufferedMedia);
- QCOMPARE(statusSpy.count(), 5);
+ QCOMPARE(statusSpy.size(), 5);
QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)),
QMediaPlayer::BufferedMedia);
// Verify the bufferProgressChanged() signal isn't being emitted.
- QCOMPARE(bufferSpy.count(), bufferSignals);
+ QCOMPARE(bufferSpy.size(), bufferSignals);
mockPlayer->setMediaStatus(QMediaPlayer::EndOfMedia);
QCOMPARE(player->mediaStatus(), QMediaPlayer::EndOfMedia);
- QCOMPARE(statusSpy.count(), 6);
+ QCOMPARE(statusSpy.size(), 6);
QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)),
QMediaPlayer::EndOfMedia);
@@ -796,22 +802,22 @@ void tst_QMediaPlayer::testQrc()
mockPlayer->setState(QMediaPlayer::PlayingState, QMediaPlayer::NoMedia);
mockPlayer->setStreamPlaybackSupported(backendHasStream);
- QSignalSpy mediaSpy(player, SIGNAL(sourceChanged(QUrl)));
- QSignalSpy statusSpy(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
- QSignalSpy errorSpy(player, SIGNAL(errorOccurred(QMediaPlayer::Error,const QString&)));
+ QSignalSpy mediaSpy(player, &QMediaPlayer::sourceChanged);
+ QSignalSpy statusSpy(player, &QMediaPlayer::mediaStatusChanged);
+ QSignalSpy errorSpy(player, &QMediaPlayer::errorOccurred);
player->setSource(mediaContent);
QTRY_COMPARE(player->mediaStatus(), status);
- QCOMPARE(statusSpy.count(), 1);
+ QCOMPARE(statusSpy.size(), 1);
QCOMPARE(qvariant_cast<QMediaPlayer::MediaStatus>(statusSpy.last().value(0)), status);
QCOMPARE(player->source(), mediaContent);
- QCOMPARE(mediaSpy.count(), 1);
+ QCOMPARE(mediaSpy.size(), 1);
QCOMPARE(qvariant_cast<QUrl>(mediaSpy.last().value(0)), mediaContent);
QCOMPARE(player->error(), error);
- QCOMPARE(errorSpy.count(), errorCount);
+ QCOMPARE(errorSpy.size(), errorCount);
if (errorCount > 0) {
QCOMPARE(qvariant_cast<QMediaPlayer::Error>(errorSpy.last().value(0)), error);
QVERIFY(!player->errorString().isEmpty());
diff --git a/tests/auto/unit/multimedia/qmediaplayer_gstreamer/CMakeLists.txt b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/CMakeLists.txt
new file mode 100644
index 000000000..dd54afd25
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmediaplayer_gstreamer Test:
+#####################################################################
+
+qt_internal_add_test(tst_qmediaplayer_gstreamer
+ SOURCES
+ tst_qmediaplayer_gstreamer.cpp
+ tst_qmediaplayer_gstreamer.h
+ ../../../shared/qscopedenvironmentvariable.h
+ INCLUDE_DIRECTORIES
+ ../../../shared
+ LIBRARIES
+ Qt::MultimediaPrivate
+ Qt::QGstreamerMediaPluginPrivate
+)
+
+
+# Resources:
+set(testdata_resource_files
+ "testdata/color_matrix.mp4"
+)
+
+qt_internal_add_resource(tst_qmediaplayer_gstreamer "testdata"
+ PREFIX
+ "/"
+ FILES
+ ${testdata_resource_files}
+)
+
diff --git a/tests/auto/unit/multimedia/qmediaplayer_gstreamer/testdata/color_matrix.mp4 b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/testdata/color_matrix.mp4
new file mode 100644
index 000000000..a3661b9d2
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/testdata/color_matrix.mp4
Binary files differ
diff --git a/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp
new file mode 100644
index 000000000..3bb0b626e
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp
@@ -0,0 +1,153 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "tst_qmediaplayer_gstreamer.h"
+
+#include <QtTest/QtTest>
+#include <QtMultimedia/private/qmediaplayer_p.h>
+
+#include <qscopedenvironmentvariable.h>
+
+QT_USE_NAMESPACE
+
+using namespace Qt::Literals;
+
+QGStreamerPlatformSpecificInterface *tst_QMediaPlayerGStreamer::gstInterface()
+{
+ return dynamic_cast<QGStreamerPlatformSpecificInterface *>(
+ QPlatformMediaIntegration::instance()->platformSpecificInterface());
+}
+
+GstPipeline *tst_QMediaPlayerGStreamer::getGstPipeline()
+{
+ QGStreamerPlatformSpecificInterface *iface = gstInterface();
+ return iface ? iface->gstPipeline(player.get()) : nullptr;
+}
+
+QGstPipeline tst_QMediaPlayerGStreamer::getPipeline()
+{
+ return QGstPipeline{
+ getGstPipeline(),
+ QGstPipeline::NeedsRef,
+ };
+}
+
+void tst_QMediaPlayerGStreamer::dumpGraph(const char *fileNamePrefix)
+{
+ GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(getGstPipeline()),
+ GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_VERBOSE), fileNamePrefix);
+}
+
+tst_QMediaPlayerGStreamer::tst_QMediaPlayerGStreamer()
+{
+ qputenv("QT_MEDIA_BACKEND", "gstreamer");
+}
+
+void tst_QMediaPlayerGStreamer::initTestCase()
+{
+ using namespace std::chrono_literals;
+
+ QMediaPlayer player;
+
+ QVideoSink sink;
+ player.setVideoSink(&sink);
+ player.setSource(QUrl("qrc:/testdata/color_matrix.mp4"));
+
+ for (;;) {
+ QMediaPlayer::MediaStatus status = player.mediaStatus();
+ switch (status) {
+ case QMediaPlayer::MediaStatus::InvalidMedia: {
+ mediaSupported = false;
+ return;
+ }
+ case QMediaPlayer::MediaStatus::NoMedia:
+ case QMediaPlayer::MediaStatus::StalledMedia:
+ case QMediaPlayer::MediaStatus::LoadingMedia:
+ QTest::qWait(20ms);
+ continue;
+
+ default: {
+ mediaSupported = true;
+ return;
+ }
+ }
+ }
+}
+
+void tst_QMediaPlayerGStreamer::init()
+{
+ player = std::make_unique<QMediaPlayer>();
+}
+
+void tst_QMediaPlayerGStreamer::cleanup()
+{
+ player.reset();
+}
+
+void tst_QMediaPlayerGStreamer::constructor_preparesGstPipeline()
+{
+ auto *rawPipeline = getGstPipeline();
+ QVERIFY(rawPipeline);
+
+ QGstPipeline pipeline{
+ rawPipeline,
+ QGstPipeline::NeedsRef,
+ };
+ QVERIFY(pipeline);
+
+ QVERIFY(pipeline.findByName("videoInputSelector"));
+ QVERIFY(pipeline.findByName("audioInputSelector"));
+ QVERIFY(pipeline.findByName("subTitleInputSelector"));
+
+ dumpGraph("constructor_preparesGstPipeline");
+}
+
+void tst_QMediaPlayerGStreamer::videoSink_constructor_overridesConversionElement()
+{
+ if (!mediaSupported)
+ QSKIP("Media playback not supported");
+
+ QScopedEnvironmentVariable convOverride{
+ "QT_GSTREAMER_OVERRIDE_VIDEO_CONVERSION_ELEMENT",
+ "identity name=myConverter",
+ };
+
+ QVideoSink sink;
+ player->setVideoSink(&sink);
+ player->setSource(QUrl("qrc:/testdata/color_matrix.mp4"));
+
+ QGstPipeline pipeline = getPipeline();
+ QTEST_ASSERT(pipeline);
+
+ QTRY_VERIFY(pipeline.findByName("myConverter"));
+
+ dumpGraph("videoSink_constructor_overridesConversionElement");
+}
+
+void tst_QMediaPlayerGStreamer::
+ videoSink_constructor_overridesConversionElement_withMultipleElements()
+{
+ if (!mediaSupported)
+ QSKIP("Media playback not supported");
+
+ QScopedEnvironmentVariable convOverride{
+ "QT_GSTREAMER_OVERRIDE_VIDEO_CONVERSION_ELEMENT",
+ "identity name=myConverter ! identity name=myConverter2",
+ };
+
+ QVideoSink sink;
+ player->setVideoSink(&sink);
+ player->setSource(QUrl("qrc:/testdata/color_matrix.mp4"));
+
+ QGstPipeline pipeline = getPipeline();
+ QTEST_ASSERT(pipeline);
+
+ QTRY_VERIFY(pipeline.findByName("myConverter"));
+ QTRY_VERIFY(pipeline.findByName("myConverter2"));
+
+ dumpGraph("videoSink_constructer_overridesConversionElement_withMultipleElements");
+}
+
+QTEST_GUILESS_MAIN(tst_QMediaPlayerGStreamer)
+
+#include "moc_tst_qmediaplayer_gstreamer.cpp"
diff --git a/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.h b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.h
new file mode 100644
index 000000000..08e958404
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TST_GMEDIAPLAYER_GSTREAMER_H
+#define TST_GMEDIAPLAYER_GSTREAMER_H
+
+#include <QtCore/qtemporaryfile.h>
+#include <QtCore/qstandardpaths.h>
+#include <QtMultimedia/qmediaplayer.h>
+#include <QtQGstreamerMediaPlugin/private/qgstpipeline_p.h>
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+
+#include <memory>
+
+QT_USE_NAMESPACE
+
+class tst_QMediaPlayerGStreamer : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QMediaPlayerGStreamer();
+
+public slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void constructor_preparesGstPipeline();
+ void videoSink_constructor_overridesConversionElement();
+ void videoSink_constructor_overridesConversionElement_withMultipleElements();
+
+private:
+ std::unique_ptr<QMediaPlayer> player;
+
+ static QGStreamerPlatformSpecificInterface *gstInterface();
+
+ GstPipeline *getGstPipeline();
+ QGstPipeline getPipeline();
+ void dumpGraph(const char *fileNamePrefix);
+
+ bool mediaSupported;
+};
+
+#endif // TST_GMEDIAPLAYER_GSTREAMER_H
diff --git a/tests/auto/unit/multimedia/qmediaplaylist/CMakeLists.txt b/tests/auto/unit/multimedia/qmediaplaylist/CMakeLists.txt
index 33d4d6d14..9300394b1 100644
--- a/tests/auto/unit/multimedia/qmediaplaylist/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qmediaplaylist/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qmediaplaylist.pro.
#####################################################################
@@ -13,7 +16,7 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qmediaplaylist
SOURCES
tst_qmediaplaylist.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
TESTDATA ${test_data}
diff --git a/tests/auto/unit/multimedia/qmediaplaylist/tst_qmediaplaylist.cpp b/tests/auto/unit/multimedia/qmediaplaylist/tst_qmediaplaylist.cpp
index 1c641f713..8ef882bbf 100644
--- a/tests/auto/unit/multimedia/qmediaplaylist/tst_qmediaplaylist.cpp
+++ b/tests/auto/unit/multimedia/qmediaplaylist/tst_qmediaplaylist.cpp
@@ -1,37 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
#include "qmediaplaylist.h"
-//TESTED_COMPONENT=src/multimedia
-
QT_USE_NAMESPACE
class tst_QMediaPlaylist : public QObject
diff --git a/tests/auto/unit/multimedia/qmediarecorder/CMakeLists.txt b/tests/auto/unit/multimedia/qmediarecorder/CMakeLists.txt
index 68234d7ab..83e40012a 100644
--- a/tests/auto/unit/multimedia/qmediarecorder/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qmediarecorder/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from QMediaRecorder.pro.
#####################################################################
@@ -9,9 +12,9 @@ qt_internal_add_test(tst_qmediarecorder
tst_qmediarecorder.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimedia/qmediarecorder/tst_qmediarecorder.cpp b/tests/auto/unit/multimedia/qmediarecorder/tst_qmediarecorder.cpp
index 9808d065d..a11f39207 100644
--- a/tests/auto/unit/multimedia/qmediarecorder/tst_qmediarecorder.cpp
+++ b/tests/auto/unit/multimedia/qmediarecorder/tst_qmediarecorder.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
@@ -35,8 +8,10 @@
#include "private/qguiapplication_p.h"
#include <qmediarecorder.h>
#include <qaudioformat.h>
-#include <qmockintegration_p.h>
+#include <qmockintegration.h>
#include <qmediacapturesession.h>
+#include <qscreencapture.h>
+#include <qwindowcapture.h>
#include "qguiapplication_platform.h"
#include "qmockmediacapturesession.h"
@@ -44,6 +19,8 @@
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
class tst_QMediaRecorder : public QObject
{
Q_OBJECT
@@ -55,7 +32,7 @@ public slots:
private slots:
void testBasicSession();
void testNullControls();
- void testDeleteMediaSource();
+ void testDeleteMediaCapture();
void testError();
void testSink();
void testRecord();
@@ -75,7 +52,6 @@ private slots:
void testApplicationInative();
private:
- QMockIntegration *mockIntegration = nullptr;
QMediaCaptureSession *captureSession;
QCamera *object = nullptr;
QMockMediaCaptureSession *service = nullptr;
@@ -85,13 +61,12 @@ private:
void tst_QMediaRecorder::initTestCase()
{
- mockIntegration = new QMockIntegration;
captureSession = new QMediaCaptureSession;
object = new QCamera;
encoder = new QMediaRecorder;
captureSession->setCamera(object);
captureSession->setRecorder(encoder);
- service = mockIntegration->lastCaptureService();
+ service = QMockIntegration::instance()->lastCaptureService();
mock = service->mockControl;
}
@@ -100,7 +75,6 @@ void tst_QMediaRecorder::cleanupTestCase()
delete encoder;
delete object;
delete captureSession;
- delete mockIntegration;
}
void tst_QMediaRecorder::testBasicSession()
@@ -151,56 +125,80 @@ void tst_QMediaRecorder::testNullControls()
QCOMPARE(recorder.mediaFormat().videoCodec(), QMediaFormat::VideoCodec::VP9);
QCOMPARE(recorder.mediaFormat().fileFormat(), QMediaFormat::MPEG4);
- QSignalSpy spy(&recorder, SIGNAL(recorderStateChanged(RecorderState)));
+ QSignalSpy spy(&recorder, &QMediaRecorder::recorderStateChanged);
recorder.record();
QCOMPARE(recorder.recorderState(), QMediaRecorder::StoppedState);
QCOMPARE(recorder.error(), QMediaRecorder::NoError);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
recorder.pause();
QCOMPARE(recorder.recorderState(), QMediaRecorder::StoppedState);
QCOMPARE(recorder.error(), QMediaRecorder::NoError);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
recorder.stop();
QCOMPARE(recorder.recorderState(), QMediaRecorder::StoppedState);
QCOMPARE(recorder.error(), QMediaRecorder::NoError);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
}
-void tst_QMediaRecorder::testDeleteMediaSource()
+void tst_QMediaRecorder::testDeleteMediaCapture()
{
QMediaCaptureSession session;
- QCamera *camera = new QCamera;
- QMediaRecorder *recorder = new QMediaRecorder;
- session.setCamera(camera);
- session.setRecorder(recorder);
+ QMediaRecorder recorder;
+
+ session.setRecorder(&recorder);
+
+ auto checkSourceDeleting = [&](auto setter, auto getter, auto signal) {
+ using Type = std::remove_pointer_t<decltype((session.*getter)())>;
+
+ auto errorPrinter = qScopeGuard(
+ []() { qDebug() << QMetaType::fromType<Type>().name() << "deleting failed"; });
+
+ auto capture = std::make_unique<Type>();
+
+ (session.*setter)(capture.get());
+
+ QVERIFY((session.*getter)() == capture.get());
+
+ QSignalSpy spy(&session, signal);
+ capture.reset();
- QVERIFY(session.camera() == camera);
- QVERIFY(recorder->isAvailable());
+ QCOMPARE(spy.size(), 1);
+ QCOMPARE((session.*getter)(), nullptr);
- delete camera;
+ QVERIFY(recorder.isAvailable());
- QVERIFY(session.camera() == nullptr);
- QVERIFY(recorder->isAvailable());
+ errorPrinter.dismiss();
+ };
- delete recorder;
+ checkSourceDeleting(&QMediaCaptureSession::setImageCapture,
+ &QMediaCaptureSession::imageCapture,
+ &QMediaCaptureSession::imageCaptureChanged);
+ checkSourceDeleting(&QMediaCaptureSession::setCamera, &QMediaCaptureSession::camera,
+ &QMediaCaptureSession::cameraChanged);
+ checkSourceDeleting(&QMediaCaptureSession::setScreenCapture,
+ &QMediaCaptureSession::screenCapture,
+ &QMediaCaptureSession::screenCaptureChanged);
+ checkSourceDeleting(&QMediaCaptureSession::setWindowCapture,
+ &QMediaCaptureSession::windowCapture,
+ &QMediaCaptureSession::windowCaptureChanged);
}
void tst_QMediaRecorder::testError()
{
const QString errorString(QLatin1String("format error"));
- QSignalSpy spy(encoder, SIGNAL(errorOccurred(Error, const QString&)));
+ QSignalSpy spy(encoder, &QMediaRecorder::errorOccurred);
QCOMPARE(encoder->error(), QMediaRecorder::NoError);
QCOMPARE(encoder->errorString(), QString());
- mock->error(QMediaRecorder::FormatError, errorString);
+ mock->updateError(QMediaRecorder::FormatError, errorString);
QCOMPARE(encoder->error(), QMediaRecorder::FormatError);
QCOMPARE(encoder->errorString(), errorString);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.last()[0].value<QMediaRecorder::Error>(), QMediaRecorder::FormatError);
}
@@ -209,14 +207,14 @@ void tst_QMediaRecorder::testSink()
{
encoder->setOutputLocation(QUrl("test.tmp"));
QUrl s = encoder->outputLocation();
- QCOMPARE(s.toString(), QString("test.tmp"));
+ QCOMPARE(s.toString(), QStringLiteral("test.tmp"));
QCOMPARE(encoder->actualLocation(), QUrl());
//the actual location is available after record
encoder->record();
- QCOMPARE(encoder->actualLocation().toString(), QString("test.tmp"));
+ QCOMPARE(encoder->actualLocation().toString(), QStringLiteral("test.tmp"));
encoder->stop();
- QCOMPARE(encoder->actualLocation().toString(), QString("test.tmp"));
+ QCOMPARE(encoder->actualLocation().toString(), QStringLiteral("test.tmp"));
//setOutputLocation resets the actual location
encoder->setOutputLocation(QUrl());
@@ -232,37 +230,37 @@ void tst_QMediaRecorder::testSink()
void tst_QMediaRecorder::testRecord()
{
- QSignalSpy stateSignal(encoder,SIGNAL(recorderStateChanged(RecorderState)));
- QSignalSpy progressSignal(encoder, SIGNAL(durationChanged(qint64)));
+ QSignalSpy stateSignal(encoder, &QMediaRecorder::recorderStateChanged);
+ QSignalSpy progressSignal(encoder, &QMediaRecorder::durationChanged);
encoder->record();
QCOMPARE(encoder->recorderState(), QMediaRecorder::RecordingState);
QCOMPARE(encoder->error(), QMediaRecorder::NoError);
QCOMPARE(encoder->errorString(), QString());
- QCOMPARE(stateSignal.count(), 1);
+ QCOMPARE(stateSignal.size(), 1);
QCOMPARE(stateSignal.last()[0].value<QMediaRecorder::RecorderState>(), QMediaRecorder::RecordingState);
QTestEventLoop::instance().enterLoop(1);
- QVERIFY(progressSignal.count() > 0);
+ QVERIFY(progressSignal.size() > 0);
encoder->pause();
QCOMPARE(encoder->recorderState(), QMediaRecorder::PausedState);
- QCOMPARE(stateSignal.count(), 2);
+ QCOMPARE(stateSignal.size(), 2);
QTestEventLoop::instance().enterLoop(1);
encoder->stop();
QCOMPARE(encoder->recorderState(), QMediaRecorder::StoppedState);
- QCOMPARE(stateSignal.count(), 3);
+ QCOMPARE(stateSignal.size(), 3);
QTestEventLoop::instance().enterLoop(1);
mock->stop();
- QCOMPARE(stateSignal.count(), 3);
+ QCOMPARE(stateSignal.size(), 3);
mock->reset();
}
@@ -388,10 +386,10 @@ void tst_QMediaRecorder::metaData()
QVERIFY(recorder.metaData().isEmpty());
QMediaMetaData data;
- data.insert(QMediaMetaData::Author, QString::fromUtf8("John Doe"));
+ data.insert(QMediaMetaData::Author, QStringLiteral("John Doe"));
recorder.setMetaData(data);
- QCOMPARE(recorder.metaData().value(QMediaMetaData::Author).toString(), QString::fromUtf8("John Doe"));
+ QCOMPARE(recorder.metaData().value(QMediaMetaData::Author).toString(), QStringLiteral("John Doe"));
}
void tst_QMediaRecorder::testIsAvailable()
@@ -415,15 +413,15 @@ void tst_QMediaRecorder::testEnum()
{
const QString errorString(QLatin1String("resource error"));
- QSignalSpy spy(encoder, SIGNAL(errorOccurred(Error, const QString&)));
+ QSignalSpy spy(encoder, &QMediaRecorder::errorOccurred);
QCOMPARE(encoder->error(), QMediaRecorder::NoError);
QCOMPARE(encoder->errorString(), QString());
- emit mock->error(QMediaRecorder::ResourceError, errorString);
+ mock->updateError(QMediaRecorder::ResourceError, errorString);
QCOMPARE(encoder->error(), QMediaRecorder::ResourceError);
QCOMPARE(encoder->errorString(), errorString);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.last()[0].value<QMediaRecorder::Error>(), QMediaRecorder::ResourceError);
}
@@ -473,7 +471,7 @@ void tst_QMediaRecorder::testApplicationInative()
encoder.setQuality(QMediaRecorder::VeryHighQuality);
encoder.setOutputLocation(QUrl("test.tmp"));
- QCOMPARE(encoder.outputLocation().toString(), QString("test.tmp"));
+ QCOMPARE(encoder.outputLocation().toString(), QStringLiteral("test.tmp"));
QCOMPARE(encoder.actualLocation(), QUrl());
encoder.record();
@@ -487,7 +485,7 @@ void tst_QMediaRecorder::testApplicationInative()
encoder.stop();
// the actual location is available after record
- QCOMPARE(encoder.actualLocation().toString(), QString("test.tmp"));
+ QCOMPARE(encoder.actualLocation().toString(), QStringLiteral("test.tmp"));
}
QTEST_GUILESS_MAIN(tst_QMediaRecorder)
diff --git a/tests/auto/unit/multimedia/qmediatimerange/CMakeLists.txt b/tests/auto/unit/multimedia/qmediatimerange/CMakeLists.txt
index a414e2635..507eb16fa 100644
--- a/tests/auto/unit/multimedia/qmediatimerange/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qmediatimerange/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qmediatimerange.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qmediatimerange
SOURCES
tst_qmediatimerange.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/unit/multimedia/qmediatimerange/tst_qmediatimerange.cpp b/tests/auto/unit/multimedia/qmediatimerange/tst_qmediatimerange.cpp
index acccdea08..750b72108 100644
--- a/tests/auto/unit/multimedia/qmediatimerange/tst_qmediatimerange.cpp
+++ b/tests/auto/unit/multimedia/qmediatimerange/tst_qmediatimerange.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/qdebug.h>
@@ -170,7 +143,7 @@ void tst_QMediaTimeRange::testGetters()
// isEmpty + isContinuous + intervals + start + end
QVERIFY(!x.isEmpty());
QVERIFY(!x.isContinuous());
- QVERIFY(x.intervals().count() == 2);
+ QVERIFY(x.intervals().size() == 2);
QVERIFY(x.intervals()[0].start() == 10);
QVERIFY(x.intervals()[0].end() == 20);
QVERIFY(x.intervals()[1].start() == 30);
@@ -316,7 +289,7 @@ void tst_QMediaTimeRange::testAddInterval()
QVERIFY(!x.isEmpty());
QVERIFY(!x.isContinuous());
- QVERIFY(x.intervals().count() == 2);
+ QVERIFY(x.intervals().size() == 2);
QVERIFY(x.intervals()[0].start() == 10);
QVERIFY(x.intervals()[0].end() == 40);
QVERIFY(x.intervals()[1].start() == 50);
@@ -466,7 +439,7 @@ void tst_QMediaTimeRange::testRemoveInterval()
QVERIFY(!x.isEmpty());
QVERIFY(!x.isContinuous());
- QVERIFY(x.intervals().count() == 2);
+ QVERIFY(x.intervals().size() == 2);
QVERIFY(x.intervals()[0].start() == 10);
QVERIFY(x.intervals()[0].end() == 19);
QVERIFY(x.intervals()[1].start() == 41);
@@ -514,7 +487,7 @@ void tst_QMediaTimeRange::testRemoveInterval()
QVERIFY(!x.isEmpty());
QVERIFY(!x.isContinuous());
- QVERIFY(x.intervals().count() == 2);
+ QVERIFY(x.intervals().size() == 2);
QVERIFY(x.intervals()[0].start() == 10);
QVERIFY(x.intervals()[0].end() == 14);
QVERIFY(x.intervals()[1].start() == 36);
@@ -536,7 +509,7 @@ void tst_QMediaTimeRange::testRemoveInterval()
QVERIFY(!x.isEmpty());
QVERIFY(!x.isContinuous());
- QVERIFY(x.intervals().count() == 2);
+ QVERIFY(x.intervals().size() == 2);
QVERIFY(x.intervals()[0].start() == 10);
QVERIFY(x.intervals()[0].end() == 19);
QVERIFY(x.intervals()[1].start() == 41);
@@ -597,7 +570,7 @@ void tst_QMediaTimeRange::testRemoveTimeRange()
QVERIFY(!b.isEmpty());
QVERIFY(!b.isContinuous());
- QVERIFY(b.intervals().count() == 2);
+ QVERIFY(b.intervals().size() == 2);
QVERIFY(b.intervals()[0].start() == 10);
QVERIFY(b.intervals()[0].end() == 19);
QVERIFY(b.intervals()[1].start() == 51);
@@ -618,7 +591,7 @@ void tst_QMediaTimeRange::testRemoveTimeRange()
QVERIFY(!b.isEmpty());
QVERIFY(!b.isContinuous());
- QVERIFY(b.intervals().count() == 2);
+ QVERIFY(b.intervals().size() == 2);
QVERIFY(b.intervals()[0].start() == 10);
QVERIFY(b.intervals()[0].end() == 19);
QVERIFY(b.intervals()[1].start() == 91);
diff --git a/tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt b/tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt
new file mode 100644
index 000000000..2dd805271
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qmultimediautils
+ SOURCES
+ tst_qmultimediautils.cpp
+ LIBRARIES
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp b/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp
new file mode 100644
index 000000000..8ed54ac64
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp
@@ -0,0 +1,184 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QDebug>
+#include <private/qmultimediautils_p.h>
+#include <qvideoframeformat.h>
+
+class tst_QMultimediaUtils : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void fraction_of_0();
+ void fraction_of_negative_1_5();
+ void fraction_of_1_5();
+ void fraction_of_30();
+ void fraction_of_29_97();
+ void fraction_of_lower_boundary();
+ void fraction_of_upper_boundary();
+
+ void qRotatedFrameSize_returnsSizeAccordinglyToRotation();
+
+ void qMediaFromUserInput_addsFilePrefix_whenCalledWithLocalFile();
+
+ void qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold_data();
+ void qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold();
+ void qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold_data();
+ void qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold();
+
+ void qShouldUpdateSwapChainFormat_returnsFalse_whenSwapChainIsNullPointer();
+};
+
+void tst_QMultimediaUtils::fraction_of_0()
+{
+ auto [n, d] = qRealToFraction(0.);
+ QCOMPARE(n, 0);
+ QCOMPARE(d, 1);
+}
+
+void tst_QMultimediaUtils::fraction_of_negative_1_5()
+{
+ auto [n, d] = qRealToFraction(-1.5);
+ QCOMPARE(double(n) / double(d), -1.5);
+ QCOMPARE(n, -3);
+ QCOMPARE(d, 2);
+}
+
+void tst_QMultimediaUtils::fraction_of_1_5()
+{
+ auto [n, d] = qRealToFraction(1.5);
+ QCOMPARE(double(n) / double(d), 1.5);
+ QCOMPARE(n, 3);
+ QCOMPARE(d, 2);
+}
+
+void tst_QMultimediaUtils::fraction_of_30()
+{
+ auto [n, d] = qRealToFraction(30.);
+ QCOMPARE(double(n) / double(d), 30.);
+ QCOMPARE(d, 1);
+}
+
+void tst_QMultimediaUtils::fraction_of_29_97()
+{
+ auto [n, d] = qRealToFraction(29.97);
+ QCOMPARE(double(n) / double(d), 29.97);
+}
+
+void tst_QMultimediaUtils::fraction_of_lower_boundary()
+{
+ double f = 0.000001;
+ auto [n, d] = qRealToFraction(f);
+ QVERIFY(double(n) / double(d) < f);
+ QVERIFY(double(n) / double(d) >= 0.);
+}
+
+void tst_QMultimediaUtils::fraction_of_upper_boundary()
+{
+ double f = 0.999999;
+ auto [n, d] = qRealToFraction(f);
+ QVERIFY(double(n) / double(d) <= 1.);
+ QVERIFY(double(n) / double(d) > f);
+}
+
+void tst_QMultimediaUtils::qRotatedFrameSize_returnsSizeAccordinglyToRotation()
+{
+ QCOMPARE(qRotatedFrameSize({ 10, 22 }, 0), QSize(10, 22));
+ QCOMPARE(qRotatedFrameSize({ 10, 23 }, -180), QSize(10, 23));
+ QCOMPARE(qRotatedFrameSize({ 10, 24 }, 180), QSize(10, 24));
+ QCOMPARE(qRotatedFrameSize({ 10, 25 }, 360), QSize(10, 25));
+ QCOMPARE(qRotatedFrameSize({ 11, 26 }, 540), QSize(11, 26));
+
+ QCOMPARE(qRotatedFrameSize({ 10, 22 }, -90), QSize(22, 10));
+ QCOMPARE(qRotatedFrameSize({ 10, 23 }, 90), QSize(23, 10));
+ QCOMPARE(qRotatedFrameSize({ 10, 24 }, 270), QSize(24, 10));
+ QCOMPARE(qRotatedFrameSize({ 10, 25 }, 450), QSize(25, 10));
+
+ QCOMPARE(qRotatedFrameSize({ 10, 22 }, QtVideo::Rotation::None), QSize(10, 22));
+ QCOMPARE(qRotatedFrameSize({ 10, 22 }, QtVideo::Rotation::Clockwise180), QSize(10, 22));
+
+ QCOMPARE(qRotatedFrameSize({ 11, 22 }, QtVideo::Rotation::Clockwise90), QSize(22, 11));
+ QCOMPARE(qRotatedFrameSize({ 11, 22 }, QtVideo::Rotation::Clockwise270), QSize(22, 11));
+}
+
+void tst_QMultimediaUtils::qMediaFromUserInput_addsFilePrefix_whenCalledWithLocalFile()
+{
+ using namespace Qt::Literals;
+
+ QCOMPARE(qMediaFromUserInput(QUrl(u"/foo/bar/baz"_s)), QUrl(u"file:///foo/bar/baz"_s));
+ QCOMPARE(qMediaFromUserInput(QUrl::fromLocalFile(u"C:/foo/bar/baz"_s)),
+ QUrl(u"file:///C:/foo/bar/baz"_s));
+ QCOMPARE(qMediaFromUserInput(QUrl(u"file:///foo/bar/baz"_s)), QUrl(u"file:///foo/bar/baz"_s));
+ QCOMPARE(qMediaFromUserInput(QUrl(u"http://foo/bar/baz"_s)), QUrl(u"http://foo/bar/baz"_s));
+
+ QCOMPARE(qMediaFromUserInput(QUrl(u"foo/bar/baz"_s)),
+ QUrl::fromLocalFile(QDir::currentPath() + u"/foo/bar/baz"_s));
+}
+
+void tst_QMultimediaUtils::
+ qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold_data()
+{
+ QTest::addColumn<float>("maxLuminance");
+
+ QTest::newRow("0") << 0.0f;
+ QTest::newRow("80") << 80.0f;
+ QTest::newRow("100") << 100.0f;
+}
+
+void tst_QMultimediaUtils::
+ qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold()
+{
+ // Arrange
+ QFETCH(float, maxLuminance);
+
+ QVideoFrameFormat format;
+ format.setMaxLuminance(maxLuminance);
+
+ // Act
+ QRhiSwapChain::Format requiredSwapChainFormat = qGetRequiredSwapChainFormat(format);
+
+ // Assert
+ QCOMPARE(requiredSwapChainFormat, QRhiSwapChain::Format::SDR);
+}
+
+void tst_QMultimediaUtils::
+ qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold_data()
+{
+ QTest::addColumn<float>("maxLuminance");
+
+ QTest::newRow("101") << 101.0f;
+ QTest::newRow("300") << 300.0f;
+ QTest::newRow("1600") << 1600.0f;
+}
+
+void tst_QMultimediaUtils::
+ qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold()
+{
+ // Arrange
+ QVideoFrameFormat format;
+ format.setMaxLuminance(300.0f);
+
+ // Act
+ QRhiSwapChain::Format requiredSwapChainFormat = qGetRequiredSwapChainFormat(format);
+
+ // Assert
+ QCOMPARE(requiredSwapChainFormat, QRhiSwapChain::Format::HDRExtendedSrgbLinear);
+}
+
+void tst_QMultimediaUtils::qShouldUpdateSwapChainFormat_returnsFalse_whenSwapChainIsNullPointer()
+{
+ // Arrange
+ QRhiSwapChain *swapChain = nullptr;
+ QRhiSwapChain::Format requiredSwapChainFormat = QRhiSwapChain::Format::SDR;
+
+ // Act
+ bool shouldUpdate = qShouldUpdateSwapChainFormat(swapChain, requiredSwapChainFormat);
+
+ // Assert
+ QCOMPARE(shouldUpdate, false);
+}
+
+QTEST_MAIN(tst_QMultimediaUtils)
+#include "tst_qmultimediautils.moc"
diff --git a/tests/auto/unit/multimedia/qsamplecache/CMakeLists.txt b/tests/auto/unit/multimedia/qsamplecache/CMakeLists.txt
index 279bd9800..2f58c1f6e 100644
--- a/tests/auto/unit/multimedia/qsamplecache/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qsamplecache/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qsamplecache.pro.
#####################################################################
@@ -13,7 +16,7 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qsamplecache
SOURCES
tst_qsamplecache.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
TESTDATA ${test_data}
diff --git a/tests/auto/unit/multimedia/qsamplecache/tst_qsamplecache.cpp b/tests/auto/unit/multimedia/qsamplecache/tst_qsamplecache.cpp
index 5baea0278..311d05a5a 100644
--- a/tests/auto/unit/multimedia/qsamplecache/tst_qsamplecache.cpp
+++ b/tests/auto/unit/multimedia/qsamplecache/tst_qsamplecache.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <private/qsamplecache_p.h>
diff --git a/tests/auto/unit/multimedia/qscreencapture/CMakeLists.txt b/tests/auto/unit/multimedia/qscreencapture/CMakeLists.txt
new file mode 100644
index 000000000..f5b152034
--- /dev/null
+++ b/tests/auto/unit/multimedia/qscreencapture/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qscreencapture Test:
+#####################################################################
+
+qt_internal_add_test(tst_qscreencapture
+ SOURCES
+ tst_qscreencapture.cpp
+ INCLUDE_DIRECTORIES
+ ../../mockbackend
+ LIBRARIES
+ # Remove: L${CMAKE_CURRENT_SOURCE_DIR}
+ Qt::Gui
+ Qt::MultimediaPrivate
+ MockMultimediaPlugin
+)
diff --git a/tests/auto/unit/multimedia/qscreencapture/tst_qscreencapture.cpp b/tests/auto/unit/multimedia/qscreencapture/tst_qscreencapture.cpp
new file mode 100644
index 000000000..ad574ddf6
--- /dev/null
+++ b/tests/auto/unit/multimedia/qscreencapture/tst_qscreencapture.cpp
@@ -0,0 +1,64 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+// TESTED_COMPONENT=src/multimedia
+
+#include <QtTest/QtTest>
+#include <QDebug>
+
+#include "qmockintegration.h"
+#include "qscreencapture.h"
+#include "qmocksurfacecapture.h"
+#include "qatomic.h"
+
+QT_USE_NAMESPACE
+
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
+class tst_QScreenCapture : public QObject
+{
+ Q_OBJECT
+
+private:
+ // Use custom waiting instead of QSignalSpy since the spy tries copying not sharable object
+ // QVideoFrame to QVariant and gets an assert
+ bool waitForFrame(QPlatformSurfaceCapture &psc)
+ {
+ QAtomicInteger<bool> newFrameReceived = false;
+ QObject o;
+ auto connection = connect(&psc, &QPlatformSurfaceCapture::newVideoFrame, &o,
+ [&newFrameReceived]() { newFrameReceived = true; });
+
+ return QTest::qWaitFor([&newFrameReceived]() { return newFrameReceived; });
+ }
+
+private slots:
+ void destructionOfActiveCapture();
+
+};
+
+void tst_QScreenCapture::destructionOfActiveCapture()
+{
+ // Run a few times in order to catch random UB on deletion
+ for (int i = 0; i < 10; ++i) {
+ auto sc = std::make_unique<QScreenCapture>();
+ QPointer<QPlatformSurfaceCapture> psc = QMockIntegration::instance()->lastScreenCapture();
+ QVERIFY(psc);
+
+ sc->setActive(true);
+
+ QVERIFY(waitForFrame(*psc));
+
+ QSignalSpy spy(sc.get(), &QScreenCapture::activeChanged);
+
+ psc->setParent(nullptr);
+ sc.reset();
+
+ QVERIFY2(spy.empty(), "No signals from QScreenCapture are expected on deletion");
+ QVERIFY2(!psc, "Platform screen capture must be deleted whether or not it has a parent");
+ }
+}
+
+QTEST_MAIN(tst_QScreenCapture)
+
+#include "tst_qscreencapture.moc"
diff --git a/tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt b/tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt
new file mode 100644
index 000000000..765d02c96
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qvideobuffers
+ SOURCES
+ tst_qvideobuffers.cpp
+ LIBRARIES
+ Qt::Multimedia
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp b/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp
new file mode 100644
index 000000000..162620fb6
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp
@@ -0,0 +1,256 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+
+#include <private/qmemoryvideobuffer_p.h>
+#include <private/qimagevideobuffer_p.h>
+#include "qvideoframeformat.h"
+
+using BufferPtr = std::shared_ptr<QAbstractVideoBuffer>;
+using MapModes = std::vector<QtVideo::MapMode>;
+
+static const MapModes validMapModes = { QtVideo::MapMode::ReadOnly, QtVideo::MapMode::WriteOnly, QtVideo::MapMode::ReadWrite };
+
+class tst_QVideoBuffers : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QVideoBuffers() {}
+public slots:
+ void initTestCase();
+
+private slots:
+ void map_returnsProperMappings_whenBufferIsNotMapped_data();
+ void map_returnsProperMappings_whenBufferIsNotMapped();
+
+ void map_returnsProperMappings_whenBufferIsMapped_data();
+ void map_returnsProperMappings_whenBufferIsMapped();
+
+ void mapMemoryOrImageBuffer_detachesDataDependingOnMode_data();
+ void mapMemoryOrImageBuffer_detachesDataDependingOnMode();
+
+ void unmap_resetsMappedState_whenBufferIsMapped_data();
+ void unmap_resetsMappedState_whenBufferIsMapped();
+
+ void imageBuffer_fixesInputImage_data();
+ void imageBuffer_fixesInputImage();
+
+private:
+ QString mapModeToString(QtVideo::MapMode mapMode) const
+ {
+ switch (mapMode) {
+ case QtVideo::MapMode::NotMapped:
+ return QLatin1String("NotMapped");
+ case QtVideo::MapMode::ReadOnly:
+ return QLatin1String("ReadOnly");
+ case QtVideo::MapMode::WriteOnly:
+ return QLatin1String("WriteOnly");
+ case QtVideo::MapMode::ReadWrite:
+ return QLatin1String("ReadWrite");
+ default:
+ return QLatin1String("Unknown");
+ }
+ }
+
+ void generateImageAndMemoryBuffersWithAllModes(const MapModes& modes = validMapModes) const
+ {
+ QTest::addColumn<BufferPtr>("buffer");
+ QTest::addColumn<QtVideo::MapMode>("mapMode");
+ QTest::addColumn<const uint8_t *>("sourcePointer");
+
+ for (auto mode : modes) {
+ QTest::newRow(QStringLiteral("ImageBuffer, %1").arg(mapModeToString(mode)).toLocal8Bit().constData())
+ << createImageBuffer() << mode << m_image.constBits();
+ QTest::newRow(QStringLiteral("MemoryBuffer, %1").arg(mapModeToString(mode)).toLocal8Bit().constData())
+ << createMemoryBuffer() << mode << reinterpret_cast<const uint8_t *>(m_byteArray.constData());
+ }
+ }
+
+ void generateMapModes(const MapModes &modes = validMapModes) const
+ {
+ QTest::addColumn<QtVideo::MapMode>("mapMode");
+
+ for (auto mode : modes)
+ QTest::newRow(mapModeToString(mode).toLocal8Bit().constData()) << mode;
+ }
+
+ BufferPtr createImageBuffer() const
+ {
+ return std::make_shared<QImageVideoBuffer>(m_image);
+ }
+
+ BufferPtr createMemoryBuffer() const
+ {
+ return std::make_shared<QMemoryVideoBuffer>(m_byteArray, m_byteArray.size() / m_image.height());
+ }
+
+ QImage m_image = { QSize(5, 4), QImage::Format_RGBA8888 };
+ QByteArray m_byteArray;
+};
+
+
+void tst_QVideoBuffers::initTestCase()
+{
+ m_image.fill(Qt::gray);
+ m_image.setPixelColor(0, 0, Qt::green);
+ m_image.setPixelColor(m_image.width() - 1, 0, Qt::blue);
+ m_image.setPixelColor(0, m_image.height() - 1, Qt::red);
+
+ m_byteArray.assign(m_image.constBits(), m_image.constBits() + m_image.sizeInBytes());
+}
+
+void tst_QVideoBuffers::map_returnsProperMappings_whenBufferIsNotMapped_data()
+{
+ generateImageAndMemoryBuffersWithAllModes();
+}
+
+void tst_QVideoBuffers::map_returnsProperMappings_whenBufferIsNotMapped()
+{
+ QFETCH(BufferPtr, buffer);
+ QFETCH(QtVideo::MapMode, mapMode);
+
+ auto mappedData = buffer->map(mapMode);
+
+ QCOMPARE(mappedData.planeCount, 1);
+ QVERIFY(mappedData.data[0]);
+ QCOMPARE(mappedData.dataSize[0], 80);
+ QCOMPARE(mappedData.bytesPerLine[0], 20);
+
+ const auto data = reinterpret_cast<const char*>(mappedData.data[0]);
+ QCOMPARE(QByteArray(data, mappedData.dataSize[0]), m_byteArray);
+}
+
+void tst_QVideoBuffers::map_returnsProperMappings_whenBufferIsMapped_data()
+{
+ generateImageAndMemoryBuffersWithAllModes();
+}
+
+void tst_QVideoBuffers::map_returnsProperMappings_whenBufferIsMapped()
+{
+ QFETCH(BufferPtr, buffer);
+ QFETCH(QtVideo::MapMode, mapMode);
+
+ auto mappedData1 = buffer->map(mapMode);
+ auto mappedData2 = buffer->map(mapMode);
+
+ QCOMPARE(mappedData1.planeCount, mappedData2.planeCount);
+ QCOMPARE(mappedData1.data[0], mappedData2.data[0]);
+ QCOMPARE(mappedData1.dataSize[0], mappedData2.dataSize[0]);
+ QCOMPARE(mappedData1.bytesPerLine[0], mappedData2.bytesPerLine[0]);
+}
+
+void tst_QVideoBuffers::mapMemoryOrImageBuffer_detachesDataDependingOnMode_data()
+{
+ generateImageAndMemoryBuffersWithAllModes();
+}
+
+void tst_QVideoBuffers::mapMemoryOrImageBuffer_detachesDataDependingOnMode()
+{
+ QFETCH(BufferPtr, buffer);
+ QFETCH(QtVideo::MapMode, mapMode);
+ QFETCH(const uint8_t *, sourcePointer);
+
+ auto mappedData = buffer->map(mapMode);
+ QCOMPARE(mappedData.planeCount, 1);
+
+ const bool isDetached = mappedData.data[0] != sourcePointer;
+ const bool isWriteMode = (mapMode & QtVideo::MapMode::WriteOnly) == QtVideo::MapMode::WriteOnly;
+ QCOMPARE(isDetached, isWriteMode);
+}
+
+void tst_QVideoBuffers::unmap_resetsMappedState_whenBufferIsMapped_data()
+{
+ generateImageAndMemoryBuffersWithAllModes();
+}
+
+void tst_QVideoBuffers::unmap_resetsMappedState_whenBufferIsMapped()
+{
+ QFETCH(BufferPtr, buffer);
+ QFETCH(QtVideo::MapMode, mapMode);
+
+ buffer->map(mapMode);
+
+ buffer->unmap();
+
+ // Check buffer is valid and it's possible to map again
+ auto mappedData = buffer->map(QtVideo::MapMode::ReadOnly);
+ QCOMPARE(mappedData.planeCount, 1);
+
+ const auto data = reinterpret_cast<const char*>(mappedData.data[0]);
+ QCOMPARE(QByteArray(data, mappedData.dataSize[0]), m_byteArray);
+}
+
+void tst_QVideoBuffers::imageBuffer_fixesInputImage_data()
+{
+ QTest::addColumn<QImage::Format>("inputImageFormat");
+ QTest::addColumn<QImage::Format>("underlyingImageFormat");
+
+ QTest::newRow("Format_RGB32 => Format_RGB32") << QImage::Format_RGB32 << QImage::Format_RGB32;
+ QTest::newRow("Format_ARGB32 => Format_ARGB32")
+ << QImage::Format_ARGB32 << QImage::Format_ARGB32;
+ QTest::newRow("Format_ARGB32_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_ARGB32_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_RGBA8888 => Format_RGBA8888")
+ << QImage::Format_RGBA8888 << QImage::Format_RGBA8888;
+ QTest::newRow("Format_RGBA8888_Premultiplied => Format_RGBA8888_Premultiplied")
+ << QImage::Format_RGBA8888_Premultiplied << QImage::Format_RGBA8888_Premultiplied;
+ QTest::newRow("Format_RGBX8888 => Format_RGBX8888")
+ << QImage::Format_RGBX8888 << QImage::Format_RGBX8888;
+ QTest::newRow("Format_Grayscale8 => Format_Grayscale8")
+ << QImage::Format_Grayscale8 << QImage::Format_Grayscale8;
+ QTest::newRow("Format_Grayscale16 => Format_Grayscale16")
+ << QImage::Format_Grayscale16 << QImage::Format_Grayscale16;
+
+ QTest::newRow("Format_ARGB8565_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_ARGB8565_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_ARGB6666_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_ARGB6666_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_ARGB8555_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_ARGB8555_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_ARGB4444_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_ARGB4444_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_A2BGR30_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_A2BGR30_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_A2RGB30_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_A2RGB30_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_RGBA64_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_RGBA64_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_RGBA16FPx4_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_RGBA16FPx4_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_RGBA32FPx4_Premultiplied => Format_ARGB32_Premultiplied")
+ << QImage::Format_RGBA32FPx4_Premultiplied << QImage::Format_ARGB32_Premultiplied;
+
+ QTest::newRow("Format_Alpha8 => Format_ARGB32")
+ << QImage::Format_Alpha8 << QImage::Format_ARGB32;
+ QTest::newRow("Format_RGBA64 => Format_ARGB32")
+ << QImage::Format_RGBA64 << QImage::Format_ARGB32;
+ QTest::newRow("Format_RGBA16FPx4 => Format_ARGB32")
+ << QImage::Format_RGBA16FPx4 << QImage::Format_ARGB32;
+ QTest::newRow("Format_RGBA32FPx4 => Format_ARGB32")
+ << QImage::Format_RGBA32FPx4 << QImage::Format_ARGB32;
+}
+
+void tst_QVideoBuffers::imageBuffer_fixesInputImage()
+{
+ QFETCH(QImage::Format, inputImageFormat);
+ QFETCH(QImage::Format, underlyingImageFormat);
+
+ m_image.convertTo(inputImageFormat);
+ QImageVideoBuffer buffer(m_image);
+
+ auto underlyingImage = buffer.underlyingImage();
+
+ QCOMPARE(underlyingImage.format(), underlyingImageFormat);
+ QCOMPARE_NE(QVideoFrameFormat::pixelFormatFromImageFormat(underlyingImage.format()),
+ QVideoFrameFormat::Format_Invalid);
+ QCOMPARE(m_image.convertedTo(underlyingImageFormat), underlyingImage);
+
+ if (inputImageFormat == underlyingImageFormat)
+ QCOMPARE(m_image.constBits(), underlyingImage.constBits());
+}
+
+QTEST_APPLESS_MAIN(tst_QVideoBuffers);
+
+#include "tst_qvideobuffers.moc"
diff --git a/tests/auto/unit/multimedia/qvideoframe/CMakeLists.txt b/tests/auto/unit/multimedia/qvideoframe/CMakeLists.txt
index a46bbcc9b..29b8a413e 100644
--- a/tests/auto/unit/multimedia/qvideoframe/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qvideoframe/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qvideoframe.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qvideoframe
SOURCES
tst_qvideoframe.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp b/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp
index cb94c102e..295484a92 100644
--- a/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp
+++ b/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp
@@ -1,41 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <qvideoframe.h>
#include <qvideoframeformat.h>
+#include "QtTest/qtestcase.h"
#include "private/qmemoryvideobuffer_p.h"
+#include "private/qhwvideobuffer_p.h"
+#include "private/qvideoframe_p.h"
#include <QtGui/QImage>
#include <QtCore/QPointer>
#include <QtMultimedia/private/qtmultimedia-config_p.h>
+#include "private/qvideoframeconverter_p.h"
// Adds an enum, and the stringized version
#define ADD_ENUM_TEST(x) \
@@ -44,6 +21,160 @@
<< QString(QLatin1String(#x));
+// Image used for testing conversion from QImage to QVideoFrame
+QImage createTestImage(QImage::Format format)
+{
+ // +---+---+---+
+ // | r | g | b |
+ // | b | r | g |
+ // +---+---+---+
+ QImage image{ { 3, 2 }, QImage::Format_ARGB32 };
+ image.setPixelColor(0, 0, QColor(Qt::red));
+ image.setPixelColor(1, 0, QColor(Qt::green));
+ image.setPixelColor(2, 0, QColor(Qt::blue));
+ image.setPixelColor(0, 1, QColor(Qt::blue));
+ image.setPixelColor(1, 1, QColor(Qt::red));
+ image.setPixelColor(2, 1, QColor(Qt::green));
+ return image.convertToFormat(format);
+}
+
+// clang-format off
+
+// Convert a QVideoFrame pixel value from raw format to QRgb
+// Only works with little-endian byte ordering
+QRgb swizzle(uint value, QVideoFrameFormat::PixelFormat format)
+{
+ switch (format) {
+ case QVideoFrameFormat::Format_ARGB8888:
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ case QVideoFrameFormat::Format_XRGB8888:
+ Q_ASSERT(false); // not implemented
+ return 0;
+ case QVideoFrameFormat::Format_BGRA8888:
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ case QVideoFrameFormat::Format_BGRX8888:
+ return value;
+ case QVideoFrameFormat::Format_ABGR8888:
+ case QVideoFrameFormat::Format_XBGR8888:
+ Q_ASSERT(false); // not implemented
+ return 0;
+ case QVideoFrameFormat::Format_RGBA8888:
+ case QVideoFrameFormat::Format_RGBX8888:
+ return (((value >> 24) & 0xff) << 24) // a -> a
+ | ((value & 0xff) << 16) // b -> r
+ | (((value >> 8) & 0xff) << 8) // g -> g
+ | ((value >> 16) & 0xff); // r -> b
+ default:
+ qWarning() << "Unsupported format";
+ return 0;
+ }
+}
+
+std::vector<QRgb> swizzle(const std::vector<uint> &pixels, QVideoFrameFormat::PixelFormat format)
+{
+ std::vector<QRgb> rgba(pixels.size());
+ std::transform(pixels.begin(), pixels.end(), rgba.begin(),
+ [format](uint value) {
+ return swizzle(value, format);
+ });
+ return rgba;
+}
+
+// clang-format on
+
+std::optional<std::vector<QRgb>> getPixels(QVideoFrame &frame)
+{
+ if (!frame.map(QtVideo::MapMode::ReadOnly))
+ return std::nullopt;
+
+ const uint *mappedPixels = reinterpret_cast<const uint *>(frame.bits(0));
+ const unsigned long long stride = frame.bytesPerLine(0) / sizeof(QRgb);
+
+ std::vector<uint> pixels;
+ for (int j = 0; j < frame.size().height(); ++j) {
+ for (int i = 0; i < frame.size().width(); ++i) {
+ pixels.push_back(mappedPixels[i + j * stride]);
+ }
+ }
+
+ frame.unmap();
+
+ return swizzle(pixels, frame.pixelFormat());
+}
+
+bool compareEq(QVideoFrame &frame, const QImage &image)
+{
+ if (frame.size() != image.size()) {
+ qDebug() << "Size mismatch";
+ return false;
+ }
+
+ const std::vector<QRgb> expectedPixels = { image.pixel(0, 0), image.pixel(1, 0), image.pixel(2, 0),
+ image.pixel(0, 1), image.pixel(1, 1), image.pixel(2, 1) };
+
+ const std::optional<std::vector<QRgb>> actualPixels = getPixels(frame);
+ if (!actualPixels) {
+ qDebug() << "Failed to read pixels from frame";
+ return false;
+ }
+
+ for (size_t i = 0; i < expectedPixels.size(); ++i) {
+ if (expectedPixels[i] != actualPixels->at(i)) {
+ qDebug() << "Pixel difference at element" << i << ":" << Qt::hex << expectedPixels[i]
+ << "vs" << actualPixels->at(i);
+ return false;
+ }
+ }
+ return true;
+}
+
+QSet s_pixelFormats{ QVideoFrameFormat::Format_ARGB8888,
+ QVideoFrameFormat::Format_ARGB8888_Premultiplied,
+ QVideoFrameFormat::Format_XRGB8888,
+ QVideoFrameFormat::Format_BGRA8888,
+ QVideoFrameFormat::Format_BGRA8888_Premultiplied,
+ QVideoFrameFormat::Format_BGRX8888,
+ QVideoFrameFormat::Format_ABGR8888,
+ QVideoFrameFormat::Format_XBGR8888,
+ QVideoFrameFormat::Format_RGBA8888,
+ QVideoFrameFormat::Format_RGBX8888,
+ QVideoFrameFormat::Format_NV12,
+ QVideoFrameFormat::Format_NV21,
+ QVideoFrameFormat::Format_IMC1,
+ QVideoFrameFormat::Format_IMC2,
+ QVideoFrameFormat::Format_IMC3,
+ QVideoFrameFormat::Format_IMC4,
+ QVideoFrameFormat::Format_AYUV,
+ QVideoFrameFormat::Format_AYUV_Premultiplied,
+ QVideoFrameFormat::Format_YV12,
+ QVideoFrameFormat::Format_YUV420P,
+ QVideoFrameFormat::Format_YUV422P,
+ QVideoFrameFormat::Format_UYVY,
+ QVideoFrameFormat::Format_YUYV,
+ QVideoFrameFormat::Format_Y8,
+ QVideoFrameFormat::Format_Y16,
+ QVideoFrameFormat::Format_P010,
+ QVideoFrameFormat::Format_P016,
+ QVideoFrameFormat::Format_YUV420P10 };
+
+bool isSupportedPixelFormat(QVideoFrameFormat::PixelFormat pixelFormat)
+{
+#ifdef Q_OS_ANDROID
+ // TODO: QTBUG-125238
+ switch (pixelFormat) {
+ case QVideoFrameFormat::Format_Y16:
+ case QVideoFrameFormat::Format_P010:
+ case QVideoFrameFormat::Format_P016:
+ case QVideoFrameFormat::Format_YUV420P10:
+ return false;
+ default:
+ return true;
+ }
+#else
+ return true;
+#endif
+}
+
class tst_QVideoFrame : public QObject
{
Q_OBJECT
@@ -66,7 +197,8 @@ private slots:
void createFromBuffer();
void createFromImage_data();
void createNull();
- void destructor();
+ void destructor_deletesVideoBuffer();
+ void destructorOfPrivateData_unmapsAndDeletesVideoBuffer_whenNoMoreFramesCopies();
void copy_data();
void copy();
void assign_data();
@@ -78,6 +210,9 @@ private slots:
void formatConversion_data();
void formatConversion();
+ void qImageFromVideoFrame_doesNotCrash_whenCalledWithEvenAndOddSizedFrames_data();
+ void qImageFromVideoFrame_doesNotCrash_whenCalledWithEvenAndOddSizedFrames();
+
void isMapped();
void isReadable();
void isWritable();
@@ -86,59 +221,53 @@ private slots:
void image();
void emptyData();
-};
-
-class QtTestDummyVideoBuffer : public QObject, public QAbstractVideoBuffer
-{
- Q_OBJECT
-public:
- QtTestDummyVideoBuffer()
- : QAbstractVideoBuffer(QVideoFrame::NoHandle) {}
- explicit QtTestDummyVideoBuffer(QVideoFrame::HandleType type)
- : QAbstractVideoBuffer(type) {}
-
- [[nodiscard]] QVideoFrame::MapMode mapMode() const override { return QVideoFrame::NotMapped; }
- MapData map(QVideoFrame::MapMode) override { return {}; }
- void unmap() override {}
+ void mirrored_takesValue_fromVideoFrameFormat();
+ void rotation_takesValue_fromVideoFrameFormat();
+ void streamFrameRate_takesValue_fromVideoFrameFormat();
+
+ void constructor_createsInvalidFrame_whenCalledWithNullImage();
+ void constructor_createsInvalidFrame_whenCalledWithEmptyImage();
+ void constructor_createsInvalidFrame_whenCalledWithInvalidImageFormat();
+ void constructor_createsFrameWithCorrectFormat_whenCalledWithSupportedImageFormats_data();
+ void constructor_createsFrameWithCorrectFormat_whenCalledWithSupportedImageFormats();
+ void constructor_copiesImageData_whenCalledWithRGBFormats_data();
+ void constructor_copiesImageData_whenCalledWithRGBFormats();
};
-class QtTestVideoBuffer : public QAbstractVideoBuffer
+class QtTestVideoBuffer : public QObject, public QHwVideoBuffer
{
+ Q_OBJECT
public:
- QtTestVideoBuffer()
- : QAbstractVideoBuffer(QVideoFrame::NoHandle)
- {}
- explicit QtTestVideoBuffer(QVideoFrame::HandleType type)
- : QAbstractVideoBuffer(type)
- {}
-
- [[nodiscard]] QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
+ QtTestVideoBuffer() : QHwVideoBuffer(QVideoFrame::NoHandle) { }
+ explicit QtTestVideoBuffer(QVideoFrame::HandleType type) : QHwVideoBuffer(type) { }
+ ~QtTestVideoBuffer() override { QTEST_ASSERT(!m_mapObject); }
- MapData map(QVideoFrame::MapMode mode) override
+ MapData map(QtVideo::MapMode) override
{
- m_mapMode = mode;
+ m_mapObject = std::make_unique<QObject>();
MapData mapData;
int nBytes = m_numBytes;
- mapData.nPlanes = m_planeCount;
+ mapData.planeCount = m_planeCount;
for (int i = 0; i < m_planeCount; ++i) {
mapData.data[i] = m_data[i];
mapData.bytesPerLine[i] = m_bytesPerLine[i];
if (i) {
- mapData.size[i-1] = m_data[i] - m_data[i-1];
- nBytes -= mapData.size[i-1];
+ mapData.dataSize[i-1] = m_data[i] - m_data[i-1];
+ nBytes -= mapData.dataSize[i-1];
}
- mapData.size[i] = nBytes;
+ mapData.dataSize[i] = nBytes;
}
return mapData;
}
- void unmap() override { m_mapMode = QVideoFrame::NotMapped; }
+
+ void unmap() override { m_mapObject.reset(); }
uchar *m_data[4];
int m_bytesPerLine[4];
- int m_planeCount = 0;
+ int m_planeCount = 1;
int m_numBytes;
- QVideoFrame::MapMode m_mapMode = QVideoFrame::NotMapped;
+ std::unique_ptr<QObject> m_mapObject;
};
tst_QVideoFrame::tst_QVideoFrame()
@@ -169,33 +298,43 @@ void tst_QVideoFrame::create_data()
{
QTest::addColumn<QSize>("size");
QTest::addColumn<QVideoFrameFormat::PixelFormat>("pixelFormat");
- QTest::addColumn<int>("bytes");
QTest::addColumn<int>("bytesPerLine");
QTest::newRow("64x64 ARGB32")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_ARGB8888;
+ << QVideoFrameFormat::Format_ARGB8888
+ << 64*4;
QTest::newRow("32x256 YUV420P")
<< QSize(32, 256)
- << QVideoFrameFormat::Format_YUV420P;
+ << QVideoFrameFormat::Format_YUV420P
+ << 32;
+ QTest::newRow("32x256 UYVY")
+ << QSize(32, 256)
+ << QVideoFrameFormat::Format_UYVY
+ << 32*2;
}
void tst_QVideoFrame::create()
{
QFETCH(QSize, size);
QFETCH(QVideoFrameFormat::PixelFormat, pixelFormat);
+ QFETCH(int, bytesPerLine);
QVideoFrame frame(QVideoFrameFormat(size, pixelFormat));
QVERIFY(frame.isValid());
QCOMPARE(frame.handleType(), QVideoFrame::NoHandle);
- QCOMPARE(frame.textureHandle(0), 0u);
+ QCOMPARE(QVideoFramePrivate::hwBuffer(frame), nullptr);
+ QCOMPARE_NE(QVideoFramePrivate::buffer(frame), nullptr);
QCOMPARE(frame.pixelFormat(), pixelFormat);
QCOMPARE(frame.size(), size);
QCOMPARE(frame.width(), size.width());
QCOMPARE(frame.height(), size.height());
QCOMPARE(frame.startTime(), qint64(-1));
QCOMPARE(frame.endTime(), qint64(-1));
+ frame.map(QtVideo::MapMode::ReadOnly);
+ QCOMPARE(frame.bytesPerLine(0), bytesPerLine);
+ frame.unmap();
}
void tst_QVideoFrame::createInvalid_data()
@@ -220,7 +359,7 @@ void tst_QVideoFrame::createInvalid()
QVERIFY(!frame.isValid());
QCOMPARE(frame.handleType(), QVideoFrame::NoHandle);
- QCOMPARE(frame.textureHandle(0), 0u);
+ QCOMPARE(QVideoFramePrivate::buffer(frame), nullptr);
QCOMPARE(frame.pixelFormat(), pixelFormat);
QCOMPARE(frame.size(), size);
QCOMPARE(frame.width(), size.width());
@@ -251,7 +390,8 @@ void tst_QVideoFrame::createFromBuffer()
QFETCH(QSize, size);
QFETCH(QVideoFrameFormat::PixelFormat, pixelFormat);
- QVideoFrame frame(new QtTestDummyVideoBuffer(handleType), QVideoFrameFormat(size, pixelFormat));
+ QVideoFrame frame = QVideoFramePrivate::createFrame(
+ std::make_unique<QtTestVideoBuffer>(handleType), QVideoFrameFormat(size, pixelFormat));
QVERIFY(frame.isValid());
QCOMPARE(frame.handleType(), handleType);
@@ -293,10 +433,10 @@ void tst_QVideoFrame::createNull()
QCOMPARE(frame.height(), -1);
QCOMPARE(frame.startTime(), qint64(-1));
QCOMPARE(frame.endTime(), qint64(-1));
- QCOMPARE(frame.mapMode(), QVideoFrame::NotMapped);
- QVERIFY(!frame.map(QVideoFrame::ReadOnly));
- QVERIFY(!frame.map(QVideoFrame::ReadWrite));
- QVERIFY(!frame.map(QVideoFrame::WriteOnly));
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), QtVideo::MapMode::NotMapped);
+ QVERIFY(!frame.map(QtVideo::MapMode::ReadOnly));
+ QVERIFY(!frame.map(QtVideo::MapMode::ReadWrite));
+ QVERIFY(!frame.map(QtVideo::MapMode::WriteOnly));
QCOMPARE(frame.isMapped(), false);
frame.unmap(); // Shouldn't crash
QCOMPARE(frame.isReadable(), false);
@@ -305,7 +445,9 @@ void tst_QVideoFrame::createNull()
// Null buffer (shouldn't crash)
{
- QVideoFrame frame(nullptr, QVideoFrameFormat(QSize(1024,768), QVideoFrameFormat::Format_ARGB8888));
+ QVideoFrame frame = QVideoFramePrivate::createFrame(
+ std::unique_ptr<QHwVideoBuffer>(),
+ QVideoFrameFormat(QSize(1024, 768), QVideoFrameFormat::Format_ARGB8888));
QVERIFY(!frame.isValid());
QCOMPARE(frame.handleType(), QVideoFrame::NoHandle);
QCOMPARE(frame.pixelFormat(), QVideoFrameFormat::Format_ARGB8888);
@@ -314,10 +456,10 @@ void tst_QVideoFrame::createNull()
QCOMPARE(frame.height(), 768);
QCOMPARE(frame.startTime(), qint64(-1));
QCOMPARE(frame.endTime(), qint64(-1));
- QCOMPARE(frame.mapMode(), QVideoFrame::NotMapped);
- QVERIFY(!frame.map(QVideoFrame::ReadOnly));
- QVERIFY(!frame.map(QVideoFrame::ReadWrite));
- QVERIFY(!frame.map(QVideoFrame::WriteOnly));
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), QtVideo::MapMode::NotMapped);
+ QVERIFY(!frame.map(QtVideo::MapMode::ReadOnly));
+ QVERIFY(!frame.map(QtVideo::MapMode::ReadWrite));
+ QVERIFY(!frame.map(QtVideo::MapMode::WriteOnly));
QCOMPARE(frame.isMapped(), false);
frame.unmap(); // Shouldn't crash
QCOMPARE(frame.isReadable(), false);
@@ -325,17 +467,55 @@ void tst_QVideoFrame::createNull()
}
}
-void tst_QVideoFrame::destructor()
+void tst_QVideoFrame::destructor_deletesVideoBuffer()
{
- QPointer<QtTestDummyVideoBuffer> buffer = new QtTestDummyVideoBuffer;
+ QPointer buffer(new QtTestVideoBuffer);
{
- QVideoFrame frame(buffer, QVideoFrameFormat(QSize(4, 1), QVideoFrameFormat::Format_ARGB8888));
+ QVideoFrame frame = QVideoFramePrivate::createFrame(
+ std::unique_ptr<QHwVideoBuffer>(buffer),
+ QVideoFrameFormat(QSize(4, 1), QVideoFrameFormat::Format_ARGB8888));
}
QVERIFY(buffer.isNull());
}
+void tst_QVideoFrame::destructorOfPrivateData_unmapsAndDeletesVideoBuffer_whenNoMoreFramesCopies()
+{
+ uchar bufferData[16] = {
+ 0,
+ };
+
+ QPointer buffer(new QtTestVideoBuffer);
+ buffer->m_data[0] = bufferData;
+ buffer->m_bytesPerLine[0] = 16;
+ buffer->m_planeCount = 1;
+ buffer->m_numBytes = sizeof(bufferData);
+
+ QVideoFrame frame1 = QVideoFramePrivate::createFrame(
+ std::unique_ptr<QHwVideoBuffer>(buffer),
+ QVideoFrameFormat(QSize(4, 1), QVideoFrameFormat::Format_ARGB8888));
+
+ frame1.map(QtVideo::MapMode::ReadOnly);
+
+ QVERIFY(buffer);
+ QPointer mapObject(buffer->m_mapObject.get());
+
+ QVideoFrame frame2 = frame1;
+
+ frame1 = {};
+
+ // check if the buffer and the map object are still alive
+ QVERIFY(mapObject);
+ QVERIFY(buffer);
+
+ frame2 = {};
+
+ // check if the buffer and the map object have been deleted
+ QVERIFY(!mapObject);
+ QVERIFY(!buffer);
+}
+
void tst_QVideoFrame::copy_data()
{
QTest::addColumn<QVideoFrame::HandleType>("handleType");
@@ -384,10 +564,11 @@ void tst_QVideoFrame::copy()
QFETCH(qint64, startTime);
QFETCH(qint64, endTime);
- QPointer<QtTestDummyVideoBuffer> buffer = new QtTestDummyVideoBuffer(handleType);
+ QPointer<QtTestVideoBuffer> buffer = new QtTestVideoBuffer(handleType);
{
- QVideoFrame frame(buffer, QVideoFrameFormat(size, pixelFormat));
+ QVideoFrame frame = QVideoFramePrivate::createFrame(std::unique_ptr<QHwVideoBuffer>(buffer),
+ QVideoFrameFormat(size, pixelFormat));
frame.setStartTime(startTime);
frame.setEndTime(endTime);
@@ -473,11 +654,12 @@ void tst_QVideoFrame::assign()
QFETCH(qint64, startTime);
QFETCH(qint64, endTime);
- QPointer<QtTestDummyVideoBuffer> buffer = new QtTestDummyVideoBuffer(handleType);
+ QPointer<QtTestVideoBuffer> buffer = new QtTestVideoBuffer(handleType);
QVideoFrame frame;
{
- QVideoFrame otherFrame(buffer, QVideoFrameFormat(size, pixelFormat));
+ QVideoFrame otherFrame = QVideoFramePrivate::createFrame(
+ std::unique_ptr<QHwVideoBuffer>(buffer), QVideoFrameFormat(size, pixelFormat));
otherFrame.setStartTime(startTime);
otherFrame.setEndTime(endTime);
@@ -537,44 +719,44 @@ void tst_QVideoFrame::map_data()
{
QTest::addColumn<QSize>("size");
QTest::addColumn<QVideoFrameFormat::PixelFormat>("pixelFormat");
- QTest::addColumn<QVideoFrame::MapMode>("mode");
+ QTest::addColumn<QtVideo::MapMode>("mode");
QTest::newRow("read-only")
<< QSize(64, 64)
<< QVideoFrameFormat::Format_ARGB8888
- << QVideoFrame::ReadOnly;
+ << QtVideo::MapMode::ReadOnly;
QTest::newRow("write-only")
<< QSize(64, 64)
<< QVideoFrameFormat::Format_ARGB8888
- << QVideoFrame::WriteOnly;
+ << QtVideo::MapMode::WriteOnly;
QTest::newRow("read-write")
<< QSize(64, 64)
<< QVideoFrameFormat::Format_ARGB8888
- << QVideoFrame::ReadWrite;
+ << QtVideo::MapMode::ReadWrite;
}
void tst_QVideoFrame::map()
{
QFETCH(QSize, size);
QFETCH(QVideoFrameFormat::PixelFormat, pixelFormat);
- QFETCH(QVideoFrame::MapMode, mode);
+ QFETCH(QtVideo::MapMode, mode);
QVideoFrame frame(QVideoFrameFormat(size, pixelFormat));
QVERIFY(!frame.bits(0));
QCOMPARE(frame.mappedBytes(0), 0);
QCOMPARE(frame.bytesPerLine(0), 0);
- QCOMPARE(frame.mapMode(), QVideoFrame::NotMapped);
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), QtVideo::MapMode::NotMapped);
QVERIFY(frame.map(mode));
// Mapping multiple times is allowed in ReadOnly mode
- if (mode == QVideoFrame::ReadOnly) {
+ if (mode == QtVideo::MapMode::ReadOnly) {
const uchar *bits = frame.bits(0);
- QVERIFY(frame.map(QVideoFrame::ReadOnly));
+ QVERIFY(frame.map(QtVideo::MapMode::ReadOnly));
QVERIFY(frame.isMapped());
QCOMPARE(frame.bits(0), bits);
@@ -584,34 +766,39 @@ void tst_QVideoFrame::map()
QCOMPARE(frame.bits(0), bits);
//re-mapping in Write or ReadWrite modes should fail
- QVERIFY(!frame.map(QVideoFrame::WriteOnly));
- QVERIFY(!frame.map(QVideoFrame::ReadWrite));
+ QVERIFY(!frame.map(QtVideo::MapMode::WriteOnly));
+ QVERIFY(!frame.map(QtVideo::MapMode::ReadWrite));
} else {
// Mapping twice in ReadWrite or WriteOnly modes should fail, but leave it mapped (and the mode is ignored)
QVERIFY(!frame.map(mode));
- QVERIFY(!frame.map(QVideoFrame::ReadOnly));
+ QVERIFY(!frame.map(QtVideo::MapMode::ReadOnly));
}
QVERIFY(frame.bits(0));
- QCOMPARE(frame.mapMode(), mode);
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), mode);
frame.unmap();
QVERIFY(!frame.bits(0));
QCOMPARE(frame.mappedBytes(0), 0);
QCOMPARE(frame.bytesPerLine(0), 0);
- QCOMPARE(frame.mapMode(), QVideoFrame::NotMapped);
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), QtVideo::MapMode::NotMapped);
}
void tst_QVideoFrame::mapPlanes_data()
{
QTest::addColumn<QVideoFrame>("frame");
+
+ // Distance between subsequent lines within a color plane in bytes
QTest::addColumn<QList<int> >("strides");
+
+ // Distance from first pixel of first color plane to first pixel
+ // of n'th plane in bytes
QTest::addColumn<QList<int> >("offsets");
static uchar bufferData[1024];
- QtTestVideoBuffer *planarBuffer = new QtTestVideoBuffer;
+ auto planarBuffer = std::make_unique<QtTestVideoBuffer>();
planarBuffer->m_data[0] = bufferData;
planarBuffer->m_data[1] = bufferData + 512;
planarBuffer->m_data[2] = bufferData + 765;
@@ -621,14 +808,18 @@ void tst_QVideoFrame::mapPlanes_data()
planarBuffer->m_planeCount = 3;
planarBuffer->m_numBytes = sizeof(bufferData);
- QTest::newRow("Planar")
- << QVideoFrame(planarBuffer, QVideoFrameFormat(QSize(64, 64), QVideoFrameFormat::Format_YUV420P))
- << (QList<int>() << 64 << 36 << 36)
- << (QList<int>() << 512 << 765);
+ QTest::newRow("Planar") << QVideoFramePrivate::createFrame(
+ std::move(planarBuffer),
+ QVideoFrameFormat(QSize(64, 64), QVideoFrameFormat::Format_YUV420P))
+ << (QList<int>() << 64 << 36 << 36) << (QList<int>() << 512 << 765);
QTest::newRow("Format_YUV420P")
<< QVideoFrame(QVideoFrameFormat(QSize(60, 64), QVideoFrameFormat::Format_YUV420P))
<< (QList<int>() << 64 << 32 << 32)
<< (QList<int>() << 4096 << 5120);
+ QTest::newRow("Format_YUV422P")
+ << QVideoFrame(QVideoFrameFormat(QSize(60, 64), QVideoFrameFormat::Format_YUV422P))
+ << (QList<int>() << 64 << 64 / 2 << 64 / 2)
+ << (QList<int>() << 64 * 64 << 64 * 64 + 64 / 2 * 64);
QTest::newRow("Format_YV12")
<< QVideoFrame(QVideoFrameFormat(QSize(60, 64), QVideoFrameFormat::Format_YV12))
<< (QList<int>() << 64 << 32 << 32)
@@ -669,24 +860,24 @@ void tst_QVideoFrame::mapPlanes()
QFETCH(QList<int>, strides);
QFETCH(QList<int>, offsets);
- QCOMPARE(strides.count(), offsets.count() + 1);
+ QCOMPARE(strides.size(), offsets.size() + 1);
- QCOMPARE(frame.map(QVideoFrame::ReadOnly), true);
- QCOMPARE(frame.planeCount(), strides.count());
+ QCOMPARE(frame.map(QtVideo::MapMode::ReadOnly), true);
+ QCOMPARE(frame.planeCount(), strides.size());
- QVERIFY(strides.count() > 0);
+ QVERIFY(strides.size() > 0);
QCOMPARE(frame.bytesPerLine(0), strides.at(0));
QVERIFY(frame.bits(0));
- if (strides.count() > 1) {
+ if (strides.size() > 1) {
QCOMPARE(frame.bytesPerLine(1), strides.at(1));
QCOMPARE(int(frame.bits(1) - frame.bits(0)), offsets.at(0));
}
- if (strides.count() > 2) {
+ if (strides.size() > 2) {
QCOMPARE(frame.bytesPerLine(2), strides.at(2));
QCOMPARE(int(frame.bits(2) - frame.bits(0)), offsets.at(1));
}
- if (strides.count() > 3) {
+ if (strides.size() > 3) {
QCOMPARE(frame.bytesPerLine(3), strides.at(3));
QCOMPARE(int(frame.bits(3) - frame.bits(0)), offsets.at(0));
}
@@ -803,6 +994,11 @@ void tst_QVideoFrame::formatConversion_data()
QTest::newRow("QVideoFrameFormat::Format_Jpeg")
<< QImage::Format_Invalid
<< QVideoFrameFormat::Format_Jpeg;
+ QTest::newRow("QVideoFrameFormat::Format_RGBX8888")
+ << QImage::Format_RGBX8888 << QVideoFrameFormat::Format_RGBX8888;
+ QTest::newRow("QImage::Format_RGBA8888_Premultiplied => QVideoFrameFormat::Format_RGBX8888 "
+ "(workaround)")
+ << QImage::Format_RGBA8888_Premultiplied << QVideoFrameFormat::Format_RGBX8888;
}
void tst_QVideoFrame::formatConversion()
@@ -813,17 +1009,86 @@ void tst_QVideoFrame::formatConversion()
if (imageFormat != QImage::Format_Invalid)
QCOMPARE(QVideoFrameFormat::pixelFormatFromImageFormat(imageFormat), pixelFormat);
+ if (imageFormat == QImage::Format_RGBA8888_Premultiplied) {
+ qWarning() << "Workaround: convert QImage::Format_RGBA8888_Premultiplied to "
+ "QVideoFrameFormat::Format_RGBX8888; to be removed in 6.8";
+ return;
+ }
+
if (pixelFormat != QVideoFrameFormat::Format_Invalid)
QCOMPARE(QVideoFrameFormat::imageFormatFromPixelFormat(pixelFormat), imageFormat);
}
+void tst_QVideoFrame::qImageFromVideoFrame_doesNotCrash_whenCalledWithEvenAndOddSizedFrames_data() {
+ QTest::addColumn<QSize>("size");
+ QTest::addColumn<QVideoFrameFormat::PixelFormat>("pixelFormat");
+ QTest::addColumn<bool>("forceCpuConversion");
+ QTest::addColumn<bool>("supportedOnPlatform");
+
+ const std::vector<QSize> sizes{
+ // Even sized
+ { 2, 2 },
+ { 2, 10 },
+ { 10, 2 },
+ { 640, 480 },
+ { 4096, 2160 },
+ // Odd sized
+ { 0, 0 },
+ { 3, 3 },
+ { 2, 3 },
+ { 3, 2 },
+ { 641, 480 },
+ { 640, 481 },
+ // TODO: Crashes
+ // { 1, 1 } // TODO: Division by zero in QVideoFrame::map (Debug)
+ // { 1, 2 } // TODO: D3D validation error in QRhiD3D11::executeCommandBuffer
+ // { 2, 1 } // TODO: D3D validation error in QRhiD3D11::executeCommandBuffer
+ };
+
+ for (const QSize &size : sizes) {
+ for (const QVideoFrameFormat::PixelFormat pixelFormat : s_pixelFormats) {
+ for (const bool forceCpu : { false, true }) {
+
+ if (pixelFormat == QVideoFrameFormat::Format_YUV420P10 && forceCpu)
+ continue; // TODO: Cpu conversion not implemented
+
+ QString name = QStringLiteral("%1x%2_%3%4")
+ .arg(size.width())
+ .arg(size.height())
+ .arg(QVideoFrameFormat::pixelFormatToString(pixelFormat))
+ .arg(forceCpu ? "_cpu" : "");
+
+ QTest::addRow("%s", name.toLatin1().data())
+ << size << pixelFormat << forceCpu << isSupportedPixelFormat(pixelFormat);
+ }
+ }
+ }
+}
+
+void tst_QVideoFrame::qImageFromVideoFrame_doesNotCrash_whenCalledWithEvenAndOddSizedFrames() {
+ QFETCH(const QSize, size);
+ QFETCH(const QVideoFrameFormat::PixelFormat, pixelFormat);
+ QFETCH(const bool, forceCpuConversion);
+ QFETCH(const bool, supportedOnPlatform);
+
+ const QVideoFrameFormat format{ size, pixelFormat };
+ const QVideoFrame frame{ format };
+ const QImage actual = qImageFromVideoFrame(frame, QtVideo::Rotation::None, false, false,
+ forceCpuConversion);
+
+ if (supportedOnPlatform)
+ QCOMPARE_EQ(actual.isNull(), size.isEmpty());
+ // Otherwise, we don't expect an image being produced, although it might.
+ // TODO: Investigate why 16 bit formats fail on some Android flavors.
+}
+
#define TEST_MAPPED(frame, mode) \
do { \
QVERIFY(frame.bits(0)); \
QVERIFY(frame.isMapped()); \
QCOMPARE(frame.mappedBytes(0), 16384); \
QCOMPARE(frame.bytesPerLine(0), 256); \
- QCOMPARE(frame.mapMode(), mode); \
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), mode); \
} while (0)
#define TEST_UNMAPPED(frame) \
@@ -832,7 +1097,7 @@ do { \
QVERIFY(!frame.isMapped()); \
QCOMPARE(frame.mappedBytes(0), 0); \
QCOMPARE(frame.bytesPerLine(0), 0); \
- QCOMPARE(frame.mapMode(), QVideoFrame::NotMapped); \
+ QCOMPARE(static_cast<QtVideo::MapMode>(frame.mapMode()), QtVideo::MapMode::NotMapped); \
} while (0)
void tst_QVideoFrame::isMapped()
@@ -843,23 +1108,23 @@ void tst_QVideoFrame::isMapped()
TEST_UNMAPPED(frame);
TEST_UNMAPPED(constFrame);
- QVERIFY(frame.map(QVideoFrame::ReadOnly));
- TEST_MAPPED(frame, QVideoFrame::ReadOnly);
- TEST_MAPPED(constFrame, QVideoFrame::ReadOnly);
+ QVERIFY(frame.map(QtVideo::MapMode::ReadOnly));
+ TEST_MAPPED(frame, QtVideo::MapMode::ReadOnly);
+ TEST_MAPPED(constFrame, QtVideo::MapMode::ReadOnly);
frame.unmap();
TEST_UNMAPPED(frame);
TEST_UNMAPPED(constFrame);
- QVERIFY(frame.map(QVideoFrame::WriteOnly));
- TEST_MAPPED(frame, QVideoFrame::WriteOnly);
- TEST_MAPPED(constFrame, QVideoFrame::WriteOnly);
+ QVERIFY(frame.map(QtVideo::MapMode::WriteOnly));
+ TEST_MAPPED(frame, QtVideo::MapMode::WriteOnly);
+ TEST_MAPPED(constFrame, QtVideo::MapMode::WriteOnly);
frame.unmap();
TEST_UNMAPPED(frame);
TEST_UNMAPPED(constFrame);
- QVERIFY(frame.map(QVideoFrame::ReadWrite));
- TEST_MAPPED(frame, QVideoFrame::ReadWrite);
- TEST_MAPPED(constFrame, QVideoFrame::ReadWrite);
+ QVERIFY(frame.map(QtVideo::MapMode::ReadWrite));
+ TEST_MAPPED(frame, QtVideo::MapMode::ReadWrite);
+ TEST_MAPPED(constFrame, QtVideo::MapMode::ReadWrite);
frame.unmap();
TEST_UNMAPPED(frame);
TEST_UNMAPPED(constFrame);
@@ -872,17 +1137,17 @@ void tst_QVideoFrame::isReadable()
QVERIFY(!frame.isMapped());
QVERIFY(!frame.isReadable());
- QVERIFY(frame.map(QVideoFrame::ReadOnly));
+ QVERIFY(frame.map(QtVideo::MapMode::ReadOnly));
QVERIFY(frame.isMapped());
QVERIFY(frame.isReadable());
frame.unmap();
- QVERIFY(frame.map(QVideoFrame::WriteOnly));
+ QVERIFY(frame.map(QtVideo::MapMode::WriteOnly));
QVERIFY(frame.isMapped());
QVERIFY(!frame.isReadable());
frame.unmap();
- QVERIFY(frame.map(QVideoFrame::ReadWrite));
+ QVERIFY(frame.map(QtVideo::MapMode::ReadWrite));
QVERIFY(frame.isMapped());
QVERIFY(frame.isReadable());
frame.unmap();
@@ -895,17 +1160,17 @@ void tst_QVideoFrame::isWritable()
QVERIFY(!frame.isMapped());
QVERIFY(!frame.isWritable());
- QVERIFY(frame.map(QVideoFrame::ReadOnly));
+ QVERIFY(frame.map(QtVideo::MapMode::ReadOnly));
QVERIFY(frame.isMapped());
QVERIFY(!frame.isWritable());
frame.unmap();
- QVERIFY(frame.map(QVideoFrame::WriteOnly));
+ QVERIFY(frame.map(QtVideo::MapMode::WriteOnly));
QVERIFY(frame.isMapped());
QVERIFY(frame.isWritable());
frame.unmap();
- QVERIFY(frame.map(QVideoFrame::ReadWrite));
+ QVERIFY(frame.map(QtVideo::MapMode::ReadWrite));
QVERIFY(frame.isMapped());
QVERIFY(frame.isWritable());
frame.unmap();
@@ -915,94 +1180,284 @@ void tst_QVideoFrame::image_data()
{
QTest::addColumn<QSize>("size");
QTest::addColumn<QVideoFrameFormat::PixelFormat>("pixelFormat");
- QTest::addColumn<QImage::Format>("imageFormat");
QTest::newRow("64x64 ARGB32")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_ARGB8888
- << QImage::Format_ARGB32_Premultiplied;
+ << QVideoFrameFormat::Format_ARGB8888;
QTest::newRow("64x64 ARGB32_Premultiplied")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_ARGB8888_Premultiplied
- << QImage::Format_ARGB32_Premultiplied;
+ << QVideoFrameFormat::Format_ARGB8888_Premultiplied;
QTest::newRow("64x64 RGB32")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_XRGB8888
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_XRGB8888;
QTest::newRow("64x64 BGRA32")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_BGRA8888
- << QImage::Format_ARGB32_Premultiplied;
+ << QVideoFrameFormat::Format_BGRA8888;
QTest::newRow("64x64 BGRA32_Premultiplied")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_BGRA8888_Premultiplied
- << QImage::Format_ARGB32_Premultiplied;
+ << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
QTest::newRow("64x64 BGR32")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_XBGR8888
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_XBGR8888;
QTest::newRow("64x64 AYUV")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_AYUV
- << QImage::Format_ARGB32_Premultiplied;
+ << QVideoFrameFormat::Format_AYUV;
QTest::newRow("64x64 YUV420P")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_YUV420P
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_YUV420P;
QTest::newRow("64x64 YV12")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_YV12
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_YV12;
QTest::newRow("64x64 UYVY")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_UYVY
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_UYVY;
QTest::newRow("64x64 YUYV")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_YUYV
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_YUYV;
QTest::newRow("64x64 NV12")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_NV12
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_NV12;
QTest::newRow("64x64 NV21")
<< QSize(64, 64)
- << QVideoFrameFormat::Format_NV21
- << QImage::Format_RGB32;
+ << QVideoFrameFormat::Format_NV21;
}
void tst_QVideoFrame::image()
{
QFETCH(QSize, size);
QFETCH(QVideoFrameFormat::PixelFormat, pixelFormat);
- QFETCH(QImage::Format, imageFormat);
QVideoFrame frame(QVideoFrameFormat(size, pixelFormat));
QImage img = frame.toImage();
QVERIFY(!img.isNull());
- QCOMPARE(img.format(), imageFormat);
QCOMPARE(img.size(), size);
}
void tst_QVideoFrame::emptyData()
{
QByteArray data(nullptr, 0);
- QVideoFrame f(new QMemoryVideoBuffer(data, 600),
- QVideoFrameFormat(QSize(800, 600), QVideoFrameFormat::Format_ARGB8888));
- QVERIFY(!f.map(QVideoFrame::ReadOnly));
+ QVideoFrame f = QVideoFramePrivate::createFrame(
+ std::make_unique<QMemoryVideoBuffer>(data, 600),
+ QVideoFrameFormat(QSize(800, 600), QVideoFrameFormat::Format_ARGB8888));
+ QVERIFY(!f.map(QtVideo::MapMode::ReadOnly));
+}
+
+void tst_QVideoFrame::mirrored_takesValue_fromVideoFrameFormat()
+{
+ QVideoFrameFormat format(QSize(10, 20), QVideoFrameFormat::Format_ARGB8888);
+ format.setMirrored(true);
+
+ QVideoFrame frame(format);
+ QVERIFY(frame.mirrored());
+
+ frame.setMirrored(false);
+ frame.setRotation(QtVideo::Rotation::Clockwise180);
+ QVERIFY(!frame.mirrored());
+ QVERIFY(!frame.surfaceFormat().isMirrored());
+}
+
+void tst_QVideoFrame::rotation_takesValue_fromVideoFrameFormat()
+{
+ QVideoFrameFormat format(QSize(10, 20), QVideoFrameFormat::Format_ARGB8888);
+ format.setRotation(QtVideo::Rotation::Clockwise270);
+
+ QVideoFrame frame(format);
+ QCOMPARE(frame.rotation(), QtVideo::Rotation::Clockwise270);
+
+ frame.setRotation(QtVideo::Rotation::Clockwise180);
+
+ QCOMPARE(frame.rotation(), QtVideo::Rotation::Clockwise180);
+ QCOMPARE(frame.surfaceFormat().rotation(), QtVideo::Rotation::Clockwise180);
+}
+
+void tst_QVideoFrame::streamFrameRate_takesValue_fromVideoFrameFormat()
+{
+ QVideoFrameFormat format(QSize(10, 20), QVideoFrameFormat::Format_ARGB8888);
+ format.setStreamFrameRate(20.);
+
+ QVideoFrame frame(format);
+ QCOMPARE(frame.streamFrameRate(), 20.);
+
+ frame.setStreamFrameRate(25.);
+
+ QCOMPARE(frame.streamFrameRate(), 25.);
+ QCOMPARE(frame.surfaceFormat().streamFrameRate(), 25.);
+}
+
+void tst_QVideoFrame::constructor_createsInvalidFrame_whenCalledWithNullImage()
+{
+ const QVideoFrame frame{ QImage{} };
+ QVERIFY(!frame.isValid());
+}
+
+void tst_QVideoFrame::constructor_createsInvalidFrame_whenCalledWithEmptyImage()
+{
+ {
+ const QImage image{ QSize{}, QImage::Format_RGB32 };
+ const QVideoFrame frame{ image };
+
+ QVERIFY(!frame.isValid());
+ }
+
+ {
+ const QImage image{ { 0, 0 }, QImage::Format_RGB32 };
+ const QVideoFrame frame{ image };
+
+ QVERIFY(!frame.isValid());
+ }
+
+ {
+ const QImage image{ { 1, 0 }, QImage::Format_RGB32 };
+ const QVideoFrame frame{ image };
+
+ QVERIFY(!frame.isValid());
+ }
+
+ {
+ const QImage image{ { 0, 1 }, QImage::Format_RGB32 };
+ const QVideoFrame frame{ image };
+
+ QVERIFY(!frame.isValid());
+ }
+}
+
+void tst_QVideoFrame::constructor_createsInvalidFrame_whenCalledWithInvalidImageFormat()
+{
+ const QImage image{ { 1, 1 }, QImage::Format_Invalid};
+ const QVideoFrame frame{ image };
+
+ QVERIFY(!frame.isValid());
+}
+
+// clang-format off
+void tst_QVideoFrame::constructor_createsFrameWithCorrectFormat_whenCalledWithSupportedImageFormats_data()
+{
+ QTest::addColumn<QImage::Format>("imageFormat");
+ QTest::addColumn<QVideoFrameFormat::PixelFormat>("expectedFrameFormat");
+
+ // Formats that do not require conversion
+ QTest::newRow("Format_RGB32") << QImage::Format_RGB32 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32 << QVideoFrameFormat::Format_BGRA8888;
+ QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_RGBA8888") << QImage::Format_RGBA8888 << QVideoFrameFormat::Format_RGBA8888;
+ QTest::newRow("Format_RGBA8888_Premultiplied") << QImage::Format_RGBA8888_Premultiplied << QVideoFrameFormat::Format_RGBX8888;
+ QTest::newRow("Format_RGBX8888") << QImage::Format_RGBX8888 << QVideoFrameFormat::Format_RGBX8888;
+ QTest::newRow("Format_Grayscale8") << QImage::Format_Grayscale8 << QVideoFrameFormat::Format_Y8;
+ QTest::newRow("Format_Grayscale16") << QImage::Format_Grayscale16 << QVideoFrameFormat::Format_Y16;
+
+ // Formats that require conversion of input image
+ QTest::newRow("Format_Mono") << QImage::Format_Mono << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_MonoLSB") << QImage::Format_MonoLSB << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_RGB16") << QImage::Format_RGB16 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_RGB666") << QImage::Format_RGB666 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_ARGB6666_Premultiplied") << QImage::Format_ARGB6666_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_RGB555") << QImage::Format_RGB555 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_RGB888") << QImage::Format_RGB888 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_RGB444") << QImage::Format_RGB444 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_BGR30") << QImage::Format_BGR30 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_A2BGR30_Premultiplied") << QImage::Format_A2BGR30_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_RGB30") << QImage::Format_RGB30 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_A2RGB30_Premultiplied") << QImage::Format_A2RGB30_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_Alpha8") << QImage::Format_Alpha8 << QVideoFrameFormat::Format_BGRA8888;
+ QTest::newRow("Format_RGBX64") << QImage::Format_RGBX64 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_RGBA64") << QImage::Format_RGBA64 << QVideoFrameFormat::Format_BGRA8888;
+ QTest::newRow("Format_RGBA64_Premultiplied") << QImage::Format_RGBA64_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_BGR888") << QImage::Format_BGR888 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_RGBX16FPx4") << QImage::Format_RGBX16FPx4 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_RGBA16FPx4") << QImage::Format_RGBA16FPx4 << QVideoFrameFormat::Format_BGRA8888;
+ QTest::newRow("Format_RGBA16FPx4_Premultiplied") << QImage::Format_RGBA16FPx4_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+ QTest::newRow("Format_RGBX32FPx4") << QImage::Format_RGBX32FPx4 << QVideoFrameFormat::Format_BGRX8888;
+ QTest::newRow("Format_RGBA32FPx4") << QImage::Format_RGBA32FPx4 << QVideoFrameFormat::Format_BGRA8888;
+ QTest::newRow("Format_RGBA32FPx4_Premultiplied") << QImage::Format_RGBA32FPx4_Premultiplied << QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+}
+// clang-format on
+
+void tst_QVideoFrame::constructor_createsFrameWithCorrectFormat_whenCalledWithSupportedImageFormats()
+{
+ QFETCH(const QImage::Format, imageFormat);
+ QFETCH(QVideoFrameFormat::PixelFormat, expectedFrameFormat);
+
+ const QImage image{ { 1, 1 }, imageFormat };
+ const QVideoFrame frame{ image };
+
+ QVERIFY(frame.isValid());
+ QCOMPARE_EQ(frame.pixelFormat(), expectedFrameFormat);
+}
+
+// clang-format off
+void tst_QVideoFrame::constructor_copiesImageData_whenCalledWithRGBFormats_data()
+{
+ QTest::addColumn<QImage::Format>("imageFormat");
+
+ // Formats that do not require image conversion
+ QTest::newRow("Format_RGB32") << QImage::Format_RGB32;
+ QTest::newRow("Format_RGBX8888") << QImage::Format_RGBX8888;
+ QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32;
+ QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_RGBA8888") << QImage::Format_RGBA8888;
+ QTest::newRow("Format_RGBA8888_Premultiplied") << QImage::Format_RGBA8888_Premultiplied;
+
+ // Formats that require image conversion
+ QTest::newRow("Format_Mono") << QImage::Format_Mono;
+ QTest::newRow("Format_MonoLSB") << QImage::Format_MonoLSB;
+ QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8;
+ QTest::newRow("Format_RGB16") << QImage::Format_RGB16;
+ QTest::newRow("Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied;
+ QTest::newRow("Format_RGB666") << QImage::Format_RGB666;
+ QTest::newRow("Format_ARGB6666_Premultiplied") << QImage::Format_ARGB6666_Premultiplied;
+ QTest::newRow("Format_RGB555") << QImage::Format_RGB555;
+ QTest::newRow("Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied;
+ QTest::newRow("Format_RGB888") << QImage::Format_RGB888;
+ QTest::newRow("Format_RGB444") << QImage::Format_RGB444;
+ QTest::newRow("Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied;
+ QTest::newRow("Format_BGR30") << QImage::Format_BGR30;
+ QTest::newRow("Format_A2BGR30_Premultiplied") << QImage::Format_A2BGR30_Premultiplied;
+ QTest::newRow("Format_RGB30") << QImage::Format_RGB30;
+ QTest::newRow("Format_A2RGB30_Premultiplied") << QImage::Format_A2RGB30_Premultiplied;
+ QTest::newRow("Format_Alpha8") << QImage::Format_Alpha8;
+ QTest::newRow("Format_RGBX64") << QImage::Format_RGBX64;
+ QTest::newRow("Format_RGBA64") << QImage::Format_RGBA64;
+ QTest::newRow("Format_RGBA64_Premultiplied") << QImage::Format_RGBA64_Premultiplied;
+ QTest::newRow("Format_BGR888") << QImage::Format_BGR888;
+ QTest::newRow("Format_RGBX16FPx4") << QImage::Format_RGBX16FPx4;
+ QTest::newRow("Format_RGBA16FPx4") << QImage::Format_RGBA16FPx4;
+ QTest::newRow("Format_RGBA16FPx4_Premultiplied") << QImage::Format_RGBA16FPx4_Premultiplied;
+ QTest::newRow("Format_RGBX32FPx4") << QImage::Format_RGBX32FPx4;
+ QTest::newRow("Format_RGBA32FPx4") << QImage::Format_RGBA32FPx4;
+ QTest::newRow("Format_RGBA32FPx4_Premultiplied") << QImage::Format_RGBA32FPx4_Premultiplied;
+}
+
+// clang-format on
+
+void tst_QVideoFrame::constructor_copiesImageData_whenCalledWithRGBFormats()
+{
+ QFETCH(const QImage::Format, imageFormat);
+
+ // Arrange
+ const QImage image{ createTestImage(imageFormat) };
+
+ // Act
+ QVideoFrame frame{ image };
+
+ // Assert
+ QVERIFY(compareEq(frame, image));
}
QTEST_MAIN(tst_QVideoFrame)
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/CMakeLists.txt b/tests/auto/unit/multimedia/qvideoframecolormanagement/CMakeLists.txt
new file mode 100644
index 000000000..d2e3086d2
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ testdata/*)
+list(APPEND testdata_resource_files ${test_data_glob})
+
+qt_internal_add_test(tst_qvideoframecolormanagement
+ SOURCES
+ tst_qvideoframecolormanagement.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::MultimediaPrivate
+ BUILTIN_TESTDATA
+ TESTDATA ${testdata_resource_files}
+)
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg
new file mode 100644
index 000000000..52b0f620b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full.png
new file mode 100644
index 000000000..d6d461f5d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video.png
new file mode 100644
index 000000000..2a4f7d8a7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full.png
new file mode 100644
index 000000000..d291f62bb
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video.png
new file mode 100644
index 000000000..35296fc03
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full.png
new file mode 100644
index 000000000..64e5eb6dc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video.png
new file mode 100644
index 000000000..9f6bdd1ea
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full.png
new file mode 100644
index 000000000..90b2b3601
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video.png
new file mode 100644
index 000000000..90b2b3601
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full.png
new file mode 100644
index 000000000..2e78cfc31
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video.png
new file mode 100644
index 000000000..d673b7ce5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full.png
new file mode 100644
index 000000000..8be30a706
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video.png
new file mode 100644
index 000000000..1f64ea0f1
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full.png
new file mode 100644
index 000000000..24fb9065e
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video.png
new file mode 100644
index 000000000..f737d8602
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full.png
new file mode 100644
index 000000000..d6d461f5d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video.png
new file mode 100644
index 000000000..2a4f7d8a7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full.png
new file mode 100644
index 000000000..d291f62bb
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video.png
new file mode 100644
index 000000000..35296fc03
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full.png
new file mode 100644
index 000000000..64e5eb6dc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video.png
new file mode 100644
index 000000000..9f6bdd1ea
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full.png
new file mode 100644
index 000000000..6efa73ea2
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video.png
new file mode 100644
index 000000000..6efa73ea2
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full.png
new file mode 100644
index 000000000..8d6a36a1c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video.png
new file mode 100644
index 000000000..dab23bf0d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full.png
new file mode 100644
index 000000000..36e787cef
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video.png
new file mode 100644
index 000000000..01e6ab967
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full.png
new file mode 100644
index 000000000..22beff2e8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video.png
new file mode 100644
index 000000000..c2af074b8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full.png
new file mode 100644
index 000000000..d6d461f5d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video.png
new file mode 100644
index 000000000..2a4f7d8a7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full.png
new file mode 100644
index 000000000..d291f62bb
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video.png
new file mode 100644
index 000000000..35296fc03
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full.png
new file mode 100644
index 000000000..64e5eb6dc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video.png
new file mode 100644
index 000000000..9f6bdd1ea
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full.png
new file mode 100644
index 000000000..d6d461f5d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video.png
new file mode 100644
index 000000000..2a4f7d8a7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full.png
new file mode 100644
index 000000000..d291f62bb
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video.png
new file mode 100644
index 000000000..35296fc03
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full.png
new file mode 100644
index 000000000..64e5eb6dc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video.png
new file mode 100644
index 000000000..9f6bdd1ea
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full.png
new file mode 100644
index 000000000..71e107b8a
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full_cpu.png
new file mode 100644
index 000000000..1242dd25b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video.png
new file mode 100644
index 000000000..71e107b8a
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video_cpu.png
new file mode 100644
index 000000000..1242dd25b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full.png
new file mode 100644
index 000000000..58a7ebc92
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full_cpu.png
new file mode 100644
index 000000000..4286840f8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video.png
new file mode 100644
index 000000000..d8756caac
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video_cpu.png
new file mode 100644
index 000000000..fb6d356f8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full.png
new file mode 100644
index 000000000..905568bf9
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full_cpu.png
new file mode 100644
index 000000000..d819e478c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video.png
new file mode 100644
index 000000000..f374df207
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video_cpu.png
new file mode 100644
index 000000000..2fbc2225c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full.png
new file mode 100644
index 000000000..d2ee0f8e2
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full_cpu.png
new file mode 100644
index 000000000..d819e478c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video.png
new file mode 100644
index 000000000..740de7f79
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video_cpu.png
new file mode 100644
index 000000000..d19223883
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full.png
new file mode 100644
index 000000000..ad76d393a
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full_cpu.png
new file mode 100644
index 000000000..68509c232
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video.png
new file mode 100644
index 000000000..ad76d393a
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video_cpu.png
new file mode 100644
index 000000000..68509c232
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full.png
new file mode 100644
index 000000000..a6e47132c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full_cpu.png
new file mode 100644
index 000000000..2cb927d35
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video.png
new file mode 100644
index 000000000..d9760b9c9
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video_cpu.png
new file mode 100644
index 000000000..3f65f27db
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full.png
new file mode 100644
index 000000000..04ae5e1cd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full_cpu.png
new file mode 100644
index 000000000..299548d61
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video.png
new file mode 100644
index 000000000..9faa15fad
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video_cpu.png
new file mode 100644
index 000000000..d544f8767
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full.png
new file mode 100644
index 000000000..84b04ff9e
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full_cpu.png
new file mode 100644
index 000000000..299548d61
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video.png
new file mode 100644
index 000000000..505752c10
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video_cpu.png
new file mode 100644
index 000000000..7da761925
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video_cpu.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full.png
new file mode 100644
index 000000000..c5243c441
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full_cpu.png
new file mode 100644
index 000000000..6a0cb7dd8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video.png
new file mode 100644
index 000000000..c5243c441
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video_cpu.png
new file mode 100644
index 000000000..6a0cb7dd8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full.png
new file mode 100644
index 000000000..0a9874943
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full_cpu.png
new file mode 100644
index 000000000..126744377
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video.png
new file mode 100644
index 000000000..7318c1e99
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video_cpu.png
new file mode 100644
index 000000000..908b28c2f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full.png
new file mode 100644
index 000000000..68789bef5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full_cpu.png
new file mode 100644
index 000000000..7ef68b58b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video.png
new file mode 100644
index 000000000..bfd6396ec
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video_cpu.png
new file mode 100644
index 000000000..03e337184
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full.png
new file mode 100644
index 000000000..704c59cf9
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full_cpu.png
new file mode 100644
index 000000000..7ef68b58b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video.png
new file mode 100644
index 000000000..d9ad9c239
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video_cpu.png
new file mode 100644
index 000000000..0030ce5bc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video.png
new file mode 100644
index 000000000..682e999cc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video_cpu.png
new file mode 100644
index 000000000..7d1d73109
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full.png
new file mode 100644
index 000000000..b1dc781f2
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full_cpu.png
new file mode 100644
index 000000000..584ad4c25
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video.png
new file mode 100644
index 000000000..b1dc781f2
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video_cpu.png
new file mode 100644
index 000000000..584ad4c25
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full.png
new file mode 100644
index 000000000..619ee36a4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full_cpu.png
new file mode 100644
index 000000000..16445be0c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video.png
new file mode 100644
index 000000000..881f6be33
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video_cpu.png
new file mode 100644
index 000000000..9c7e87238
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full.png
new file mode 100644
index 000000000..b1d3111df
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full_cpu.png
new file mode 100644
index 000000000..1a3025e2d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video.png
new file mode 100644
index 000000000..e4d1ce940
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video_cpu.png
new file mode 100644
index 000000000..614b71e3e
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full.png
new file mode 100644
index 000000000..b1d3111df
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full_cpu.png
new file mode 100644
index 000000000..1a3025e2d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video.png
new file mode 100644
index 000000000..df8df3edd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video_cpu.png
new file mode 100644
index 000000000..d6bed0482
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full.png
new file mode 100644
index 000000000..130a3b541
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full_cpu.png
new file mode 100644
index 000000000..61d2c6ca0
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video.png
new file mode 100644
index 000000000..130a3b541
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video_cpu.png
new file mode 100644
index 000000000..61d2c6ca0
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full.png
new file mode 100644
index 000000000..21ed2218a
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full_cpu.png
new file mode 100644
index 000000000..188efe1d9
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video.png
new file mode 100644
index 000000000..f60f53d02
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video_cpu.png
new file mode 100644
index 000000000..512c467b6
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full.png
new file mode 100644
index 000000000..df59b71e7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full_cpu.png
new file mode 100644
index 000000000..bfc57d849
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video.png
new file mode 100644
index 000000000..dbca71c70
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video_cpu.png
new file mode 100644
index 000000000..52f4b0223
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full.png
new file mode 100644
index 000000000..df59b71e7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full_cpu.png
new file mode 100644
index 000000000..bfc57d849
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video.png
new file mode 100644
index 000000000..3479bb890
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video_cpu.png
new file mode 100644
index 000000000..b3a488e2f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_full.png
new file mode 100644
index 000000000..20b24da65
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_video.png
new file mode 100644
index 000000000..20b24da65
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_full.png
new file mode 100644
index 000000000..b96379a0b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_video.png
new file mode 100644
index 000000000..c77645b59
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_full.png
new file mode 100644
index 000000000..a1b8b62da
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_video.png
new file mode 100644
index 000000000..7a69f6afa
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_full.png
new file mode 100644
index 000000000..644b083fe
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_video.png
new file mode 100644
index 000000000..d4e9debd7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full.png
new file mode 100644
index 000000000..d6d461f5d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video.png
new file mode 100644
index 000000000..2a4f7d8a7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full.png
new file mode 100644
index 000000000..d291f62bb
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video.png
new file mode 100644
index 000000000..35296fc03
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full.png
new file mode 100644
index 000000000..64e5eb6dc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video.png
new file mode 100644
index 000000000..9f6bdd1ea
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full.png
new file mode 100644
index 000000000..3e255af2f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full_cpu.png
new file mode 100644
index 000000000..6a0cb7dd8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video.png
new file mode 100644
index 000000000..3e255af2f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video_cpu.png
new file mode 100644
index 000000000..6a0cb7dd8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full.png
new file mode 100644
index 000000000..74fd12726
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full_cpu.png
new file mode 100644
index 000000000..126744377
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video.png
new file mode 100644
index 000000000..e358d16d8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video_cpu.png
new file mode 100644
index 000000000..908b28c2f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full.png
new file mode 100644
index 000000000..cb1cbbd34
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full_cpu.png
new file mode 100644
index 000000000..7ef68b58b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video.png
new file mode 100644
index 000000000..6dd95a078
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video_cpu.png
new file mode 100644
index 000000000..03e337184
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full.png
new file mode 100644
index 000000000..3e92f3695
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full_cpu.png
new file mode 100644
index 000000000..7ef68b58b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video.png
new file mode 100644
index 000000000..e94891e1c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video_cpu.png
new file mode 100644
index 000000000..0030ce5bc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full.png
new file mode 100644
index 000000000..c5243c441
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full_cpu.png
new file mode 100644
index 000000000..6a0cb7dd8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video.png
new file mode 100644
index 000000000..c5243c441
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video_cpu.png
new file mode 100644
index 000000000..6a0cb7dd8
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full.png
new file mode 100644
index 000000000..0a9874943
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full_cpu.png
new file mode 100644
index 000000000..126744377
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video.png
new file mode 100644
index 000000000..7318c1e99
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video_cpu.png
new file mode 100644
index 000000000..908b28c2f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full.png
new file mode 100644
index 000000000..68789bef5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full_cpu.png
new file mode 100644
index 000000000..7ef68b58b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video.png
new file mode 100644
index 000000000..bfd6396ec
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video_cpu.png
new file mode 100644
index 000000000..03e337184
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full.png
new file mode 100644
index 000000000..704c59cf9
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full_cpu.png
new file mode 100644
index 000000000..7ef68b58b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video.png
new file mode 100644
index 000000000..d9ad9c239
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video_cpu.png
new file mode 100644
index 000000000..0030ce5bc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video.png
new file mode 100644
index 000000000..2af7cdaa4
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video_cpu.png
new file mode 100644
index 000000000..12685832f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_adobergb_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full.png
new file mode 100644
index 000000000..d6d461f5d
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full_cpu.png
new file mode 100644
index 000000000..2138f7b91
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video.png
new file mode 100644
index 000000000..2a4f7d8a7
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video_cpu.png
new file mode 100644
index 000000000..0de0ffbc5
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt2020_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full.png
new file mode 100644
index 000000000..d291f62bb
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video.png
new file mode 100644
index 000000000..35296fc03
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video_cpu.png
new file mode 100644
index 000000000..7b198e19b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt601_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full.png
new file mode 100644
index 000000000..64e5eb6dc
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full_cpu.png
new file mode 100644
index 000000000..33229f55f
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_full_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video.png
new file mode 100644
index 000000000..9f6bdd1ea
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video_cpu.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video_cpu.png
new file mode 100644
index 000000000..74b3efccd
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_bt709_video_cpu.png
Binary files differ
diff --git a/tests/auto/unit/multimedia/qvideoframecolormanagement/tst_qvideoframecolormanagement.cpp b/tests/auto/unit/multimedia/qvideoframecolormanagement/tst_qvideoframecolormanagement.cpp
new file mode 100644
index 000000000..ad221e54e
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/tst_qvideoframecolormanagement.cpp
@@ -0,0 +1,475 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+
+#include <qvideoframe.h>
+#include <qvideoframeformat.h>
+#include "private/qmemoryvideobuffer_p.h"
+#include "private/qvideoframeconverter_p.h"
+#include "private/qplatformmediaintegration_p.h"
+#include "private/qimagevideobuffer_p.h"
+#include "private/qvideoframe_p.h"
+#include <QtGui/QColorSpace>
+#include <QtGui/QImage>
+#include <QtCore/QPointer>
+
+#include "../../../integration/shared/mediabackendutils.h"
+
+QT_USE_NAMESPACE
+
+namespace {
+
+struct TestParams
+{
+ QString fileName;
+ QVideoFrameFormat::PixelFormat pixelFormat;
+ QVideoFrameFormat::ColorSpace colorSpace;
+ QVideoFrameFormat::ColorRange colorRange;
+ bool forceCpu;
+};
+
+QString toString(QVideoFrameFormat::ColorRange r)
+{
+ switch (r) {
+ case QVideoFrameFormat::ColorRange_Video:
+ return "Video";
+ case QVideoFrameFormat::ColorRange_Full:
+ return "Full";
+ default:
+ Q_ASSERT(false);
+ return "";
+ }
+}
+
+std::vector<QVideoFrameFormat::ColorRange> colorRanges()
+{
+ return {
+ QVideoFrameFormat::ColorRange_Video,
+ QVideoFrameFormat::ColorRange_Full,
+ };
+}
+
+const QSet s_formats{ QVideoFrameFormat::Format_ARGB8888,
+ QVideoFrameFormat::Format_ARGB8888_Premultiplied,
+ QVideoFrameFormat::Format_XRGB8888,
+ QVideoFrameFormat::Format_BGRA8888,
+ QVideoFrameFormat::Format_BGRA8888_Premultiplied,
+ QVideoFrameFormat::Format_BGRX8888,
+ QVideoFrameFormat::Format_ABGR8888,
+ QVideoFrameFormat::Format_XBGR8888,
+ QVideoFrameFormat::Format_RGBA8888,
+ QVideoFrameFormat::Format_RGBX8888,
+ QVideoFrameFormat::Format_NV12,
+ QVideoFrameFormat::Format_NV21,
+ QVideoFrameFormat::Format_IMC1,
+ QVideoFrameFormat::Format_IMC2,
+ QVideoFrameFormat::Format_IMC3,
+ QVideoFrameFormat::Format_IMC4,
+ QVideoFrameFormat::Format_AYUV,
+ QVideoFrameFormat::Format_AYUV_Premultiplied,
+ QVideoFrameFormat::Format_YV12,
+ QVideoFrameFormat::Format_YUV420P,
+ QVideoFrameFormat::Format_YUV422P,
+ QVideoFrameFormat::Format_UYVY,
+ QVideoFrameFormat::Format_YUYV,
+ QVideoFrameFormat::Format_Y8,
+ QVideoFrameFormat::Format_Y16,
+ QVideoFrameFormat::Format_P010,
+ QVideoFrameFormat::Format_P016,
+ QVideoFrameFormat::Format_YUV420P10 };
+
+bool hasCorrespondingFFmpegFormat(QVideoFrameFormat::PixelFormat format)
+{
+ return format != QVideoFrameFormat::Format_AYUV
+ && format != QVideoFrameFormat::Format_AYUV_Premultiplied;
+}
+
+bool supportsCpuConversion(QVideoFrameFormat::PixelFormat format)
+{
+ return format != QVideoFrameFormat::Format_YUV420P10;
+}
+
+QString toString(QVideoFrameFormat::PixelFormat f)
+{
+ return QVideoFrameFormat::pixelFormatToString(f);
+}
+
+QSet<QVideoFrameFormat::PixelFormat> pixelFormats()
+{
+ return s_formats;
+}
+
+bool isSupportedPixelFormat(QVideoFrameFormat::PixelFormat pixelFormat)
+{
+#ifdef Q_OS_ANDROID
+ // TODO: QTBUG-125238
+ switch (pixelFormat) {
+ case QVideoFrameFormat::Format_Y16:
+ case QVideoFrameFormat::Format_P010:
+ case QVideoFrameFormat::Format_P016:
+ case QVideoFrameFormat::Format_YUV420P10:
+ return false;
+ default:
+ return true;
+ }
+#else
+ return true;
+#endif
+}
+
+
+QString toString(QVideoFrameFormat::ColorSpace s)
+{
+ switch (s) {
+ case QVideoFrameFormat::ColorSpace_BT601:
+ return "BT601";
+ case QVideoFrameFormat::ColorSpace_BT709:
+ return "BT709";
+ case QVideoFrameFormat::ColorSpace_AdobeRgb:
+ return "AdobeRgb";
+ case QVideoFrameFormat::ColorSpace_BT2020:
+ return "BT2020";
+ default:
+ Q_ASSERT(false);
+ return "";
+ }
+}
+
+std::vector<QVideoFrameFormat::ColorSpace> colorSpaces()
+{
+ return { QVideoFrameFormat::ColorSpace_BT601, QVideoFrameFormat::ColorSpace_BT709,
+ QVideoFrameFormat::ColorSpace_AdobeRgb, QVideoFrameFormat::ColorSpace_BT2020 };
+}
+
+QString name(const TestParams &p)
+{
+ QString name = QStringLiteral("%1_%2_%3_%4%5")
+ .arg(p.fileName)
+ .arg(toString(p.pixelFormat))
+ .arg(toString(p.colorSpace))
+ .arg(toString(p.colorRange))
+ .arg(p.forceCpu ? "_cpu" : "")
+ .toLower();
+ name.replace(" ", "_");
+ return name;
+}
+
+QString path(const QTemporaryDir &dir, const TestParams &param, const QString &suffix = ".png")
+{
+ return dir.filePath(name(param) + suffix);
+}
+
+QVideoFrame createTestFrame(const TestParams &params, const QImage &image)
+{
+ QVideoFrameFormat format(image.size(), params.pixelFormat);
+ format.setColorRange(params.colorRange);
+ format.setColorSpace(params.colorSpace);
+ format.setColorTransfer(QVideoFrameFormat::ColorTransfer_Unknown);
+
+ auto buffer = std::make_unique<QImageVideoBuffer>(image);
+ QVideoFrameFormat imageFormat = {
+ image.size(), QVideoFrameFormat::pixelFormatFromImageFormat(image.format())
+ };
+
+ QVideoFrame source = QVideoFramePrivate::createFrame(std::move(buffer), imageFormat);
+ return QPlatformMediaIntegration::instance()->convertVideoFrame(source, format);
+}
+
+struct ImageDiffReport
+{
+ int DiffCountAboveThreshold; // Number of channel differences above threshold
+ int MaxDiff; // Maximum difference between two images (max across channels)
+ int PixelCount; // Number of pixels in the image
+ QImage DiffImage; // The difference image (absolute per-channel difference)
+};
+
+double aboveThresholdDiffRatio(const ImageDiffReport &report)
+{
+ return static_cast<double>(report.DiffCountAboveThreshold) / report.PixelCount;
+}
+
+int maxChannelDiff(QRgb lhs, QRgb rhs)
+{
+ // clang-format off
+ return std::max({ std::abs(qRed(lhs) - qRed(rhs)),
+ std::abs(qGreen(lhs) - qGreen(rhs)),
+ std::abs(qBlue(lhs) - qBlue(rhs)) });
+ // clang-format on
+}
+
+int clampedAbsDiff(int lhs, int rhs)
+{
+ return std::clamp(std::abs(lhs - rhs), 0, 255);
+}
+
+QRgb pixelDiff(QRgb lhs, QRgb rhs)
+{
+ return qRgb(clampedAbsDiff(qRed(lhs), qRed(rhs)), clampedAbsDiff(qGreen(lhs), qGreen(rhs)),
+ clampedAbsDiff(qBlue(lhs), qBlue(rhs)));
+}
+
+std::optional<ImageDiffReport> compareImagesRgb32(const QImage &computed, const QImage &baseline,
+ int channelThreshold)
+{
+ Q_ASSERT(baseline.format() == QImage::Format_RGB32);
+
+ if (computed.size() != baseline.size())
+ return {};
+
+ if (computed.format() != baseline.format())
+ return {};
+
+ if (computed.colorSpace() != baseline.colorSpace())
+ return {};
+
+ const QSize size = baseline.size();
+
+ ImageDiffReport report{};
+ report.PixelCount = size.width() * size.height();
+ report.DiffImage = QImage(size, baseline.format());
+
+ // Iterate over all pixels and update report
+ for (int l = 0; l < size.height(); l++) {
+ const QRgb *colorComputed = reinterpret_cast<const QRgb *>(computed.constScanLine(l));
+ const QRgb *colorBaseline = reinterpret_cast<const QRgb *>(baseline.constScanLine(l));
+ QRgb *colorDiff = reinterpret_cast<QRgb *>(report.DiffImage.scanLine(l));
+
+ int w = size.width();
+ while (w--) {
+ *colorDiff = pixelDiff(*colorComputed, *colorBaseline);
+ if (*colorComputed != *colorBaseline) {
+ const int diff = maxChannelDiff(*colorComputed, *colorBaseline);
+
+ if (diff > report.MaxDiff)
+ report.MaxDiff = diff;
+
+ if (diff > channelThreshold)
+ ++report.DiffCountAboveThreshold;
+ }
+
+ ++colorComputed;
+ ++colorBaseline;
+ ++colorDiff;
+ }
+ }
+ return report;
+}
+
+bool copyAllFiles(const QDir &source, const QDir &dest)
+{
+ if (!source.exists() || !dest.exists())
+ return false;
+
+ QDirIterator it(source);
+ while (it.hasNext()) {
+ QFileInfo file{ it.next() };
+ if (file.isFile()) {
+ const QString destination = dest.absolutePath() + "/" + file.fileName();
+ QFile::copy(file.absoluteFilePath(), destination);
+ }
+ }
+
+ return true;
+}
+
+class ReferenceData
+{
+public:
+ ReferenceData()
+ {
+ m_testdataDir = QTest::qExtractTestData("testdata");
+ if (!m_testdataDir)
+ m_testdataDir = QSharedPointer<QTemporaryDir>(new QTemporaryDir);
+ }
+
+ ~ReferenceData()
+ {
+ if (m_testdataDir->autoRemove())
+ return;
+
+ QString resultPath = m_testdataDir->path();
+ if (qEnvironmentVariableIsSet("COIN_CTEST_RESULTSDIR")) {
+ const QDir sourceDir = m_testdataDir->path();
+ const QDir resultsDir{ qEnvironmentVariable("COIN_CTEST_RESULTSDIR") };
+ if (!copyAllFiles(sourceDir, resultsDir)) {
+ qDebug() << "Failed to copy files to COIN_CTEST_RESULTSDIR";
+ } else {
+ resultPath = resultsDir.path();
+ }
+ }
+
+ qDebug() << "Images with differences were found. The output images with differences"
+ << "can be found in" << resultPath << ". Review the images and if the"
+ << "differences are expected, please update the testdata with the new"
+ << "output images";
+ }
+
+ QImage getReference(const TestParams &param) const
+ {
+ const QString referenceName = name(param);
+ const QString referencePath = m_testdataDir->filePath(referenceName + ".png");
+ QImage result;
+ if (result.load(referencePath))
+ return result;
+ return {};
+ }
+
+ void saveNewReference(const QImage &reference, const TestParams &params) const
+ {
+ const QString filename = path(*m_testdataDir, params);
+ if (!reference.save(filename)) {
+ qDebug() << "Failed to save reference file";
+ Q_ASSERT(false);
+ }
+
+ m_testdataDir->setAutoRemove(false);
+ }
+
+ bool saveComputedImage(const TestParams &params, const QImage &image, const QString& suffix) const
+ {
+ if (!image.save(path(*m_testdataDir, params, suffix))) {
+ qDebug() << "Unexpectedly failed to save actual image to file";
+ Q_ASSERT(false);
+ return false;
+ }
+ m_testdataDir->setAutoRemove(false);
+ return true;
+ }
+
+ QImage getTestdata(const QString &name)
+ {
+ const QString filePath = m_testdataDir->filePath(name);
+ QImage image;
+ if (image.load(filePath))
+ return image;
+ return {};
+ }
+
+private:
+ QSharedPointer<QTemporaryDir> m_testdataDir;
+};
+
+std::optional<ImageDiffReport> compareToReference(const TestParams &params, const QImage &actual,
+ const ReferenceData &references,
+ int maxChannelThreshold)
+{
+ const QImage expected = references.getReference(params);
+ if (expected.isNull()) {
+ // Reference image does not exist. Create one. Adding this to
+ // testdata directory is a manual job.
+ references.saveNewReference(actual, params);
+ qDebug() << "Reference image is missing. Please update testdata directory with the missing "
+ "reference image";
+ return {};
+ }
+
+ // Convert to RGB32 to simplify image comparison
+ const QImage computed = actual.convertToFormat(QImage::Format_RGB32);
+ const QImage baseline = expected.convertToFormat(QImage::Format_RGB32);
+
+ std::optional<ImageDiffReport> diffReport = compareImagesRgb32(computed, baseline, maxChannelThreshold);
+ if (!diffReport)
+ return {};
+
+ if (diffReport->MaxDiff > 0) {
+ // Images are not equal, and may require manual inspection
+ if (!references.saveComputedImage(params, computed, "_actual.png"))
+ return {};
+ if (!references.saveComputedImage(params, diffReport->DiffImage, "_diff.png"))
+ return {};
+ }
+
+ return diffReport;
+}
+
+} // namespace
+
+class tst_qvideoframecolormanagement : public QObject
+{
+ Q_OBJECT
+private slots:
+ void initTestCase()
+ {
+ if (!isFFMPEGPlatform())
+ QSKIP("This test requires the ffmpeg backend to create test frames");
+ }
+
+ void qImageFromVideoFrame_returnsQImageWithCorrectColors_data()
+ {
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<TestParams>("params");
+ for (const char *file : { "umbrellas.jpg" }) {
+ for (const QVideoFrameFormat::PixelFormat pixelFormat : pixelFormats()) {
+ for (const QVideoFrameFormat::ColorSpace colorSpace : colorSpaces()) {
+ for (const QVideoFrameFormat::ColorRange colorRange : colorRanges()) {
+ for (const bool forceCpu : { false, true }) {
+
+ if (!isSupportedPixelFormat(pixelFormat))
+ continue;
+
+ if (forceCpu && !supportsCpuConversion(pixelFormat))
+ continue; // TODO: CPU Conversion not implemented
+
+ if (!hasCorrespondingFFmpegFormat(pixelFormat))
+ continue;
+
+ TestParams param{
+ file, pixelFormat, colorSpace, colorRange, forceCpu,
+ };
+ QTest::addRow("%s", name(param).toLatin1().data()) << file << param;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // This test is a regression test for the QMultimedia display pipeline.
+ // It compares rendered output (as created by qImageFromVideoFrame)
+ // against reference images stored to file. The reference images were
+ // created by the test itself, and does not verify correctness, just
+ // changes to render output.
+ void qImageFromVideoFrame_returnsQImageWithCorrectColors()
+ {
+ QFETCH(const QString, fileName);
+ QFETCH(const TestParams, params);
+
+ const QImage templateImage = m_reference.getTestdata(fileName);
+ QVERIFY(!templateImage.isNull());
+
+ const QVideoFrame frame = createTestFrame(params, templateImage);
+
+ // Act
+ const QImage actual =
+ qImageFromVideoFrame(frame, QtVideo::Rotation::None, false, false, params.forceCpu);
+
+ // Assert
+ constexpr int diffThreshold = 4;
+ std::optional<ImageDiffReport> result =
+ compareToReference(params, actual, m_reference, diffThreshold);
+
+ // Sanity checks
+ QVERIFY(result.has_value());
+ QCOMPARE_GT(result->PixelCount, 0);
+
+ // Verify that images are similar
+ const double ratioAboveThreshold =
+ static_cast<double>(result->DiffCountAboveThreshold) / result->PixelCount;
+
+ // These thresholds are empirically determined to allow tests to pass in CI.
+ // If tests fail, review the difference between the reference and actual
+ // output to determine if it is a platform dependent inaccuracy before
+ // adjusting the limits
+ QCOMPARE_LT(ratioAboveThreshold, 0.01); // Fraction of pixels with larger differences
+ QCOMPARE_LT(result->MaxDiff, 6); // Maximum per-channel difference
+ }
+
+
+private:
+ ReferenceData m_reference;
+};
+
+QTEST_MAIN(tst_qvideoframecolormanagement)
+
+#include "tst_qvideoframecolormanagement.moc"
diff --git a/tests/auto/unit/multimedia/qvideoframeformat/CMakeLists.txt b/tests/auto/unit/multimedia/qvideoframeformat/CMakeLists.txt
index af14e67b0..0d1b92d55 100644
--- a/tests/auto/unit/multimedia/qvideoframeformat/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qvideoframeformat/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qvideoframeformat.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_qvideoframeformat
SOURCES
tst_qvideoframeformat.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
)
diff --git a/tests/auto/unit/multimedia/qvideoframeformat/tst_qvideoframeformat.cpp b/tests/auto/unit/multimedia/qvideoframeformat/tst_qvideoframeformat.cpp
index e2ab89a41..41d54de0d 100644
--- a/tests/auto/unit/multimedia/qvideoframeformat/tst_qvideoframeformat.cpp
+++ b/tests/auto/unit/multimedia/qvideoframeformat/tst_qvideoframeformat.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -57,6 +30,8 @@ private slots:
void construct();
void frameSize_data();
void frameSize();
+ void planeCount_returnsNumberOfColorPlanesDictatedByPixelFormat_data() const;
+ void planeCount_returnsNumberOfColorPlanesDictatedByPixelFormat() const;
void viewport_data();
void viewport();
void scanLineDirection_data();
@@ -109,7 +84,7 @@ void tst_QVideoFrameFormat::constructNull()
QCOMPARE(format.frameHeight(), -1);
QCOMPARE(format.viewport(), QRect());
QCOMPARE(format.scanLineDirection(), QVideoFrameFormat::TopToBottom);
- QCOMPARE(format.frameRate(), 0.0);
+ QCOMPARE(format.streamFrameRate(), 0.0);
QCOMPARE(format.colorSpace(), QVideoFrameFormat::ColorSpace_Undefined);
}
@@ -157,7 +132,7 @@ void tst_QVideoFrameFormat::construct()
QCOMPARE(format.isValid(), valid);
QCOMPARE(format.viewport(), viewport);
QCOMPARE(format.scanLineDirection(), QVideoFrameFormat::TopToBottom);
- QCOMPARE(format.frameRate(), 0.0);
+ QCOMPARE(format.streamFrameRate(), 0.0);
QCOMPARE(format.colorSpace(), QVideoFrameFormat::ColorSpace_Undefined);
}
@@ -191,6 +166,59 @@ void tst_QVideoFrameFormat::frameSize()
QCOMPARE(format.frameHeight(), newSize.height());
}
+void tst_QVideoFrameFormat::planeCount_returnsNumberOfColorPlanesDictatedByPixelFormat_data() const {
+ QTest::addColumn<QVideoFrameFormat::PixelFormat>("pixelFormat");
+ QTest::addColumn<int>("colorPlanes"); // Number of planes as specified by QVideoFrameFormat::PixelFormat documentation
+
+ QTest::newRow("ARGB8888") << QVideoFrameFormat::Format_ARGB8888 << 1;
+ QTest::newRow("ARGB8888_Premultiplied") << QVideoFrameFormat::Format_ARGB8888_Premultiplied << 1;
+ QTest::newRow("XRGB8888") << QVideoFrameFormat::Format_XRGB8888 << 1;
+ QTest::newRow("BGRA8888") << QVideoFrameFormat::Format_BGRA8888 << 1;
+ QTest::newRow("BGRA8888_Premultiplied") << QVideoFrameFormat::Format_BGRA8888_Premultiplied << 1;
+ QTest::newRow("BGRX8888") << QVideoFrameFormat::Format_BGRX8888 << 1;
+ QTest::newRow("ABGR8888") << QVideoFrameFormat::Format_ABGR8888 << 1;
+ QTest::newRow("XBGR8888") << QVideoFrameFormat::Format_XBGR8888 << 1;
+ QTest::newRow("RGBA8888") << QVideoFrameFormat::Format_RGBA8888 << 1;
+ QTest::newRow("RGBX8888") << QVideoFrameFormat::Format_RGBX8888 << 1;
+
+ QTest::newRow("AUYVY") << QVideoFrameFormat::Format_AYUV << 1;
+ QTest::newRow("AYUV_Premultiplied") << QVideoFrameFormat::Format_AYUV_Premultiplied << 1;
+ QTest::newRow("YUV420P") << QVideoFrameFormat::Format_YUV420P << 3;
+ QTest::newRow("YUV422P") << QVideoFrameFormat::Format_YUV422P << 3;
+ QTest::newRow("YV12") << QVideoFrameFormat::Format_YV12 << 3;
+
+ QTest::newRow("UYVY") << QVideoFrameFormat::Format_UYVY << 1;
+ QTest::newRow("YUYV") << QVideoFrameFormat::Format_YUYV << 1;
+ QTest::newRow("NV12") << QVideoFrameFormat::Format_NV12 << 2;
+ QTest::newRow("NV21") << QVideoFrameFormat::Format_NV21 << 2;
+
+ QTest::newRow("IMC1") << QVideoFrameFormat::Format_IMC1 << 3;
+ QTest::newRow("IMC2") << QVideoFrameFormat::Format_IMC2 << 2;
+ QTest::newRow("IMC3") << QVideoFrameFormat::Format_IMC3 << 3;
+ QTest::newRow("IMC4") << QVideoFrameFormat::Format_IMC4 << 2;
+
+ QTest::newRow("Y8") << QVideoFrameFormat::Format_Y8 << 1;
+ QTest::newRow("Y16") << QVideoFrameFormat::Format_Y16 << 1;
+
+ QTest::newRow("P010") << QVideoFrameFormat::Format_P010 << 2;
+ QTest::newRow("P016") << QVideoFrameFormat::Format_P016 << 2;
+
+ QTest::newRow("SamplerExternalOES") << QVideoFrameFormat::Format_SamplerExternalOES << 1;
+ QTest::newRow("Jpeg") << QVideoFrameFormat::Format_Jpeg << 1;
+ QTest::newRow("SamplerRect") << QVideoFrameFormat::Format_SamplerRect << 1;
+
+ QTest::newRow("YUV420P10") << QVideoFrameFormat::Format_YUV420P10 << 3;
+}
+
+void tst_QVideoFrameFormat::planeCount_returnsNumberOfColorPlanesDictatedByPixelFormat() const {
+ QFETCH(QVideoFrameFormat::PixelFormat, pixelFormat);
+ QFETCH(int, colorPlanes);
+
+ const QVideoFrameFormat frameFormat = QVideoFrameFormat({}, pixelFormat);
+
+ QCOMPARE_EQ(frameFormat.planeCount(), colorPlanes);
+}
+
void tst_QVideoFrameFormat::viewport_data()
{
QTest::addColumn<QSize>("initialSize");
@@ -307,9 +335,9 @@ void tst_QVideoFrameFormat::frameRate()
QVideoFrameFormat format(QSize(64, 64), QVideoFrameFormat::Format_XRGB8888);
- format.setFrameRate(frameRate);
+ format.setStreamFrameRate(frameRate);
- QCOMPARE(format.frameRate(), frameRate);
+ QCOMPARE(format.streamFrameRate(), frameRate);
}
void tst_QVideoFrameFormat::compare()
@@ -367,13 +395,13 @@ void tst_QVideoFrameFormat::compare()
QCOMPARE(format1 == format2, true);
QCOMPARE(format1 != format2, false);
- format1.setFrameRate(7.5);
+ format1.setStreamFrameRate(7.5);
// Not equal frame rate differs.
QCOMPARE(format1 == format2, false);
QCOMPARE(format1 != format2, true);
- format2.setFrameRate(qreal(7.50001));
+ format2.setStreamFrameRate(qreal(7.50001));
// Equal.
QCOMPARE(format1 == format2, true);
@@ -478,7 +506,7 @@ void tst_QVideoFrameFormat::copyAllParameters()
original.setScanLineDirection(QVideoFrameFormat::BottomToTop);
original.setViewport(QRect(0, 0, 1024, 1024));
- original.setFrameRate(qreal(15.0));
+ original.setStreamFrameRate(qreal(15.0));
original.setColorSpace(QVideoFrameFormat::ColorSpace_BT709);
/* Copy the original instance to copy and verify if both the instances
@@ -489,7 +517,7 @@ void tst_QVideoFrameFormat::copyAllParameters()
QCOMPARE(copy.frameSize(), QSize(1024, 768));
QCOMPARE(copy.scanLineDirection(), QVideoFrameFormat::BottomToTop);
QCOMPARE(copy.viewport(), QRect(0, 0, 1024, 1024));
- QCOMPARE(copy.frameRate(), qreal(15.0));
+ QCOMPARE(copy.streamFrameRate(), qreal(15.0));
QCOMPARE(copy.colorSpace(), QVideoFrameFormat::ColorSpace_BT709);
/* Verify if both the instances are eqaul */
@@ -505,7 +533,7 @@ void tst_QVideoFrameFormat::assignAllParameters()
QSize(64, 64), QVideoFrameFormat::Format_AYUV);
copy.setScanLineDirection(QVideoFrameFormat::TopToBottom);
copy.setViewport(QRect(0, 0, 640, 320));
- copy.setFrameRate(qreal(7.5));
+ copy.setStreamFrameRate(qreal(7.5));
copy.setColorSpace(QVideoFrameFormat::ColorSpace_BT601);
/* Create the instance and set all the parameters. */
@@ -513,7 +541,7 @@ void tst_QVideoFrameFormat::assignAllParameters()
QSize(1024, 768), QVideoFrameFormat::Format_ARGB8888);
original.setScanLineDirection(QVideoFrameFormat::BottomToTop);
original.setViewport(QRect(0, 0, 1024, 1024));
- original.setFrameRate(qreal(15.0));
+ original.setStreamFrameRate(qreal(15.0));
original.setColorSpace(QVideoFrameFormat::ColorSpace_BT709);
/* Assign the original instance to copy and verify if both the instancess
@@ -524,7 +552,7 @@ void tst_QVideoFrameFormat::assignAllParameters()
QCOMPARE(copy.frameSize(), QSize(1024, 768));
QCOMPARE(copy.scanLineDirection(), QVideoFrameFormat::BottomToTop);
QCOMPARE(copy.viewport(), QRect(0, 0, 1024, 1024));
- QCOMPARE(copy.frameRate(), qreal(15.0));
+ QCOMPARE(copy.streamFrameRate(), qreal(15.0));
QCOMPARE(copy.colorSpace(), QVideoFrameFormat::ColorSpace_BT709);
/* Verify if both the instances are eqaul */
diff --git a/tests/auto/unit/multimedia/qvideotexturehelper/CMakeLists.txt b/tests/auto/unit/multimedia/qvideotexturehelper/CMakeLists.txt
new file mode 100644
index 000000000..a47b46d5b
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideotexturehelper/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qvideotexturehelper
+ SOURCES
+ tst_qvideotexturehelper.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/unit/multimedia/qvideotexturehelper/tst_qvideotexturehelper.cpp b/tests/auto/unit/multimedia/qvideotexturehelper/tst_qvideotexturehelper.cpp
new file mode 100644
index 000000000..aa166af54
--- /dev/null
+++ b/tests/auto/unit/multimedia/qvideotexturehelper/tst_qvideotexturehelper.cpp
@@ -0,0 +1,260 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/qbytearray.h>
+#include <QtTest/qtest.h>
+
+#include <private/qvideotexturehelper_p.h>
+#include <qvideoframe.h>
+
+#include "qvideoframeformat.h"
+
+QT_USE_NAMESPACE
+
+struct ColorSpaceCoeff
+{
+ float a;
+ float b;
+ float c;
+};
+
+// Coefficients used in ITU-R BT.709-6 Table 3 - Signal format
+constexpr ColorSpaceCoeff BT709Coefficients = {
+ 0.2126f, 0.7152f, 0.0722f // E_g' = 0.2126 * E_R' + 0.7152 * E_G' + 0.0722 * E_B'
+ //
+ // Note that the other coefficients can be derived from a and c
+ // to re-normalize the values, see ITU-R BT.601-7, section 2.5.2
+ //
+ // E_CB' = (E_B' - E_g') / 1.8556 -> 1.8556 == (1-0.0722) * 2
+ // E_CR' = (E_R' - E_g') / 1.5748 -> 1.5748 == (1-0.2126) * 2
+};
+
+// Coefficients used in ITU-R BT.2020-2 Table 4 - Signal format
+constexpr ColorSpaceCoeff BT2020Coefficients = {
+ 0.2627f, 0.6780f, 0.0593f // Y_c' = (0.2627 R + 0.6780 G + 0.05938 B)'
+ // C_B' = (B' - Y') / 1.8814 -> 1.8814 == 2*(1-0.0593)
+ // C_R' = (R' - Y') / 1.4746 -> 1.4746 == 2*(1-0.2627)
+};
+
+struct ColorSpaceEntry
+{
+ QVideoFrameFormat::ColorSpace colorSpace;
+ QVideoFrameFormat::ColorRange colorRange;
+ ColorSpaceCoeff coefficients;
+};
+
+// clang-format off
+const std::vector<ColorSpaceEntry> colorSpaces = {
+ {
+ QVideoFrameFormat::ColorSpace_BT709,
+ QVideoFrameFormat::ColorRange_Video,
+ BT709Coefficients
+ },
+ {
+ QVideoFrameFormat::ColorSpace_BT709,
+ QVideoFrameFormat::ColorRange_Full,
+ BT709Coefficients
+ },
+ {
+ QVideoFrameFormat::ColorSpace_BT2020,
+ QVideoFrameFormat::ColorRange_Video,
+ BT2020Coefficients
+ },
+ {
+ QVideoFrameFormat::ColorSpace_BT2020,
+ QVideoFrameFormat::ColorRange_Full,
+ BT2020Coefficients
+ }
+};
+
+ColorSpaceCoeff getColorSpaceCoef(QVideoFrameFormat::ColorSpace colorSpace,
+ QVideoFrameFormat::ColorRange range)
+{
+ const auto it = std::find_if(colorSpaces.begin(), colorSpaces.end(),
+ [&](const ColorSpaceEntry &p) {
+ return p.colorSpace == colorSpace && p.colorRange == range;
+ });
+
+ if (it != colorSpaces.end())
+ return it->coefficients;
+
+ Q_ASSERT(false);
+
+ return {};
+}
+
+QMatrix4x4 yuv2rgb(QVideoFrameFormat::ColorSpace colorSpace, QVideoFrameFormat::ColorRange range)
+{
+ constexpr float max8bit = static_cast<float>(255);
+ constexpr float uvOffset = -128.0f/max8bit; // Really -0.5, but carried over from fixed point
+
+ QMatrix4x4 normalizeYUV;
+
+ if (range == QVideoFrameFormat::ColorRange_Video) {
+ // YUV signal is assumed to be in limited range 8 bit representation,
+ // where Y is in range [16..235] and U and V are in range [16..240].
+ // Shaders use floats in [0..1], so we scale the values accordingly.
+ constexpr float yRange = (235 - 16) / max8bit;
+ constexpr float yOffset = -16 / max8bit;
+ constexpr float uvRange = (240 - 16) / max8bit;
+
+ // Second, stretch limited range YUV signals to full range
+ normalizeYUV.scale(1/yRange, 1/uvRange, 1/uvRange);
+
+ // First, pull limited range signals down so that they start on 0
+ normalizeYUV.translate(yOffset, uvOffset, uvOffset);
+ } else {
+ normalizeYUV.translate(0.0f, uvOffset, uvOffset);
+ }
+
+ const auto [a, b, c] = getColorSpaceCoef(colorSpace, range);
+
+ // Re-normalization coefficients that restores the color difference
+ // signals to (-0.5..0.5)
+ const auto d = 2 * (1.0f - c);
+ const auto e = 2 * (1.0f - a);
+
+ // Color matrix from ITU-R BT.709-6 Table 3 - Signal Format
+ // Same as ITU-R BT.2020-2 Table 4 - Signal format
+ const QMatrix4x4 rgb2yuv {
+ a, b, c, 0.0f, // Item 3.2: E_g' = a * E_R' + b * E_G' + c * E_B'
+ -a/d, -b/d, (1-c)/d, 0.0f, // Item 3.3: E_CB' = (E_B' - E_g')/d
+ (1-a)/e, -b/e, -c/e, 0.0f, // Item 3.3: E_CR' = (E_R' - E_g')/e
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+
+ const QMatrix4x4 yuv2rgb = rgb2yuv.inverted();
+
+ // Read backwards:
+ // 1. Offset and scale YUV signal to be in range [0..1]
+ // 3. Convert to RGB in range [0..1]
+ return yuv2rgb * normalizeYUV;
+}
+
+// clang-format on
+
+bool fuzzyCompareWithTolerance(const QMatrix4x4 &computed, const QMatrix4x4 &baseline,
+ float tolerance)
+{
+ const float *computedData = computed.data();
+ const float *baselineData = baseline.data();
+ for (int i = 0; i < 16; ++i) {
+ const float c = computedData[i];
+ const float b = baselineData[i];
+
+ bool difference = false;
+ if (qFuzzyIsNull(c) && qFuzzyIsNull(b))
+ continue;
+
+ difference = 2 * (std::abs(c - b) / (c + b)) > tolerance;
+
+ if (difference) {
+ qDebug() << "Mismatch at index" << i << c << "vs" << b;
+ qDebug() << "Computed:";
+ qDebug() << computed;
+ qDebug() << "Baseline:";
+ qDebug() << baseline;
+
+ return false;
+ }
+ }
+ return true;
+}
+
+bool fuzzyCompareWithTolerance(const QVector3D &computed, const QVector3D &baseline,
+ float tolerance)
+{
+ auto fuzzyCompare = [](float c, float b, float tolerance) {
+ if (std::abs(c) < tolerance && std::abs(b) < tolerance)
+ return true;
+
+ return 2 * std::abs(c - b) / (c + b) < tolerance;
+ };
+
+ const bool equal = fuzzyCompare(computed.x(), baseline.x(), tolerance)
+ && fuzzyCompare(computed.y(), baseline.y(), tolerance)
+ && fuzzyCompare(computed.z(), baseline.z(), tolerance);
+
+ if (!equal) {
+ qDebug() << "Vectors are different. Computed:";
+ qDebug() << computed;
+ qDebug() << "Baseline:";
+ qDebug() << baseline;
+ }
+
+ return equal;
+}
+
+QMatrix4x4 getColorMatrix(const QByteArray &uniformDataBytes)
+{
+ const auto uniformData =
+ reinterpret_cast<const QVideoTextureHelper::UniformData *>(uniformDataBytes.data());
+ const auto colorMatrixData = reinterpret_cast<const float *>(uniformData->colorMatrix);
+
+ return QMatrix4x4{ colorMatrixData }.transposed();
+};
+
+class tst_qvideotexturehelper : public QObject
+{
+ Q_OBJECT
+public:
+private slots:
+ void updateUniformData_populatesYUV2RGBColorMatrix_data()
+ {
+ QTest::addColumn<QVideoFrameFormat::ColorSpace>("colorSpace");
+ QTest::addColumn<QVideoFrameFormat::ColorRange>("colorRange");
+
+ QTest::addRow("BT709_full")
+ << QVideoFrameFormat::ColorSpace_BT709 << QVideoFrameFormat::ColorRange_Full;
+
+ QTest::addRow("BT709_video")
+ << QVideoFrameFormat::ColorSpace_BT709 << QVideoFrameFormat::ColorRange_Video;
+
+ QTest::addRow("BT2020_full")
+ << QVideoFrameFormat::ColorSpace_BT2020 << QVideoFrameFormat::ColorRange_Full;
+
+ QTest::addRow("BT2020_video")
+ << QVideoFrameFormat::ColorSpace_BT2020 << QVideoFrameFormat::ColorRange_Video;
+ }
+
+ void updateUniformData_populatesYUV2RGBColorMatrix()
+ {
+ QFETCH(const QVideoFrameFormat::ColorSpace, colorSpace);
+ QFETCH(const QVideoFrameFormat::ColorRange, colorRange);
+
+ // Arrange
+ QVideoFrameFormat format{ {}, QVideoFrameFormat::Format_NV12 };
+ format.setColorSpace(colorSpace);
+ format.setColorRange(colorRange);
+
+ const QMatrix4x4 expected = yuv2rgb(colorSpace, colorRange);
+
+ // Act
+ QByteArray data;
+ QVideoTextureHelper::updateUniformData(&data, format, {}, {}, 0.0);
+ const QMatrix4x4 actual = getColorMatrix(data);
+
+ // Assert
+ QVERIFY(fuzzyCompareWithTolerance(actual, expected, 1e-3f));
+
+ { // Sanity check: Color matrix maps white to white
+ constexpr QVector3D expectedWhiteRgb{ 1.0f, 1.0f, 1.0f };
+ const QVector3D whiteYuv = expected.inverted().map(expectedWhiteRgb);
+
+ const QVector3D actualWhiteRgb = actual.map(whiteYuv);
+ QVERIFY(fuzzyCompareWithTolerance(actualWhiteRgb, expectedWhiteRgb, 5e-4f));
+ }
+
+ { // Sanity check: Color matrix maps black to black
+ constexpr QVector3D expectedBlackRgb{ 0.0f, 0.0f, 0.0f };
+ const QVector3D blackYuv = expected.inverted().map(expectedBlackRgb);
+
+ const QVector3D actualBlackRgb = actual.map(blackYuv);
+ QVERIFY(fuzzyCompareWithTolerance(actualBlackRgb, expectedBlackRgb, 5e-4f));
+ }
+ }
+};
+
+QTEST_MAIN(tst_qvideotexturehelper)
+
+#include "tst_qvideotexturehelper.moc"
diff --git a/tests/auto/unit/multimedia/qwavedecoder/CMakeLists.txt b/tests/auto/unit/multimedia/qwavedecoder/CMakeLists.txt
index 29db70754..4567e95ac 100644
--- a/tests/auto/unit/multimedia/qwavedecoder/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qwavedecoder/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qwavedecoder.pro.
#####################################################################
@@ -13,7 +16,7 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qwavedecoder
SOURCES
tst_qwavedecoder.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
Qt::Network
diff --git a/tests/auto/unit/multimedia/qwavedecoder/data/gendata.sh b/tests/auto/unit/multimedia/qwavedecoder/data/gendata.sh
index c799e6f9f..99a04129b 100755
--- a/tests/auto/unit/multimedia/qwavedecoder/data/gendata.sh
+++ b/tests/auto/unit/multimedia/qwavedecoder/data/gendata.sh
@@ -1,31 +1,6 @@
#!/bin/bash
-#############################################################################
-##
-## Copyright (C) 2016 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is the build configuration utility of the Qt Toolkit.
-##
-## $QT_BEGIN_LICENSE:GPL-EXCEPT$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 3 as published by the Free Software
-## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
+# Copyright (C) 2016 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
# Generate some simple test data. Uses "sox".
diff --git a/tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_even_bext.wav b/tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_even_bext.wav
new file mode 100644
index 000000000..531b0ee58
--- /dev/null
+++ b/tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_even_bext.wav
Binary files differ
diff --git a/tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_odd_bext.wav b/tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_odd_bext.wav
new file mode 100644
index 000000000..467be6312
--- /dev/null
+++ b/tests/auto/unit/multimedia/qwavedecoder/data/isawav_1_8_8000_odd_bext.wav
Binary files differ
diff --git a/tests/auto/unit/multimedia/qwavedecoder/tst_qwavedecoder.cpp b/tests/auto/unit/multimedia/qwavedecoder/tst_qwavedecoder.cpp
index d4fa9e5b8..079f98075 100644
--- a/tests/auto/unit/multimedia/qwavedecoder/tst_qwavedecoder.cpp
+++ b/tests/auto/unit/multimedia/qwavedecoder/tst_qwavedecoder.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <qwavedecoder.h>
@@ -85,7 +58,7 @@ void tst_QWaveDecoder::cleanupTestCase()
static QString testFilePath(const char *filename)
{
- QString path = QString("data/%1").arg(filename);
+ QString path = QStringLiteral("data/%1").arg(filename);
return QFINDTESTDATA(path);
}
@@ -96,33 +69,35 @@ void tst_QWaveDecoder::file_data()
QTest::addColumn<int>("channels");
QTest::addColumn<int>("samplesize");
QTest::addColumn<int>("samplerate");
- QTest::addColumn<QAudioFormat::Endian>("byteorder");
-
- QTest::newRow("File is empty") << testFilePath("empty.wav") << tst_QWaveDecoder::NotAWav << -1 << -1 << -1 << QAudioFormat::LittleEndian;
- QTest::newRow("File is one byte") << testFilePath("onebyte.wav") << tst_QWaveDecoder::NotAWav << -1 << -1 << -1 << QAudioFormat::LittleEndian;
- QTest::newRow("File is not a wav(text)") << testFilePath("notawav.wav") << tst_QWaveDecoder::NotAWav << -1 << -1 << -1 << QAudioFormat::LittleEndian;
- QTest::newRow("Wav file has no sample data") << testFilePath("nosampledata.wav") << tst_QWaveDecoder::NoSampleData << -1 << -1 << -1 << QAudioFormat::LittleEndian;
- QTest::newRow("corrupt fmt chunk descriptor") << testFilePath("corrupt_fmtdesc_1_16_8000.le.wav") << tst_QWaveDecoder::FormatDescriptor << -1 << -1 << -1 << QAudioFormat::LittleEndian;
- QTest::newRow("corrupt fmt string") << testFilePath("corrupt_fmtstring_1_16_8000.le.wav") << tst_QWaveDecoder::FormatString << -1 << -1 << -1 << QAudioFormat::LittleEndian;
- QTest::newRow("corrupt data chunk descriptor") << testFilePath("corrupt_datadesc_1_16_8000.le.wav") << tst_QWaveDecoder::DataDescriptor << -1 << -1 << -1 << QAudioFormat::LittleEndian;
-
- QTest::newRow("File isawav_1_8_8000.wav") << testFilePath("isawav_1_8_8000.wav") << tst_QWaveDecoder::None << 1 << 8 << 8000 << QAudioFormat::LittleEndian;
- QTest::newRow("File isawav_1_8_44100.wav") << testFilePath("isawav_1_8_44100.wav") << tst_QWaveDecoder::None << 1 << 8 << 44100 << QAudioFormat::LittleEndian;
- QTest::newRow("File isawav_2_8_8000.wav") << testFilePath("isawav_2_8_8000.wav") << tst_QWaveDecoder::None << 2 << 8 << 8000 << QAudioFormat::LittleEndian;
- QTest::newRow("File isawav_2_8_44100.wav") << testFilePath("isawav_2_8_44100.wav") << tst_QWaveDecoder::None << 2 << 8 << 44100 << QAudioFormat::LittleEndian;
-
- QTest::newRow("File isawav_1_16_8000_le.wav") << testFilePath("isawav_1_16_8000_le.wav") << tst_QWaveDecoder::None << 1 << 16 << 8000 << QAudioFormat::LittleEndian;
- QTest::newRow("File isawav_1_16_44100_le.wav") << testFilePath("isawav_1_16_44100_le.wav") << tst_QWaveDecoder::None << 1 << 16 << 44100 << QAudioFormat::LittleEndian;
- QTest::newRow("File isawav_2_16_8000_be.wav") << testFilePath("isawav_2_16_8000_be.wav") << tst_QWaveDecoder::None << 2 << 16 << 8000 << QAudioFormat::BigEndian;
- QTest::newRow("File isawav_2_16_44100_be.wav") << testFilePath("isawav_2_16_44100_be.wav") << tst_QWaveDecoder::None << 2 << 16 << 44100 << QAudioFormat::BigEndian;
- // The next file has extra data in the wave header.
- QTest::newRow("File isawav_1_16_44100_le_2.wav") << testFilePath("isawav_1_16_44100_le_2.wav") << tst_QWaveDecoder::None << 1 << 16 << 44100 << QAudioFormat::LittleEndian;
+ QTest::newRow("File is empty") << testFilePath("empty.wav") << tst_QWaveDecoder::NotAWav << -1 << -1 << -1;
+ QTest::newRow("File is one byte") << testFilePath("onebyte.wav") << tst_QWaveDecoder::NotAWav << -1 << -1 << -1;
+ QTest::newRow("File is not a wav(text)") << testFilePath("notawav.wav") << tst_QWaveDecoder::NotAWav << -1 << -1 << -1;
+ QTest::newRow("Wav file has no sample data") << testFilePath("nosampledata.wav") << tst_QWaveDecoder::NoSampleData << -1 << -1 << -1;
+ QTest::newRow("corrupt fmt chunk descriptor") << testFilePath("corrupt_fmtdesc_1_16_8000.le.wav") << tst_QWaveDecoder::FormatDescriptor << -1 << -1 << -1;
+ QTest::newRow("corrupt fmt string") << testFilePath("corrupt_fmtstring_1_16_8000.le.wav") << tst_QWaveDecoder::FormatString << -1 << -1 << -1;
+ QTest::newRow("corrupt data chunk descriptor") << testFilePath("corrupt_datadesc_1_16_8000.le.wav") << tst_QWaveDecoder::DataDescriptor << -1 << -1 << -1;
+
+ QTest::newRow("File isawav_1_8_8000.wav") << testFilePath("isawav_1_8_8000.wav") << tst_QWaveDecoder::None << 1 << 8 << 8000;
+ QTest::newRow("File isawav_1_8_44100.wav") << testFilePath("isawav_1_8_44100.wav") << tst_QWaveDecoder::None << 1 << 8 << 44100;
+ QTest::newRow("File isawav_2_8_8000.wav") << testFilePath("isawav_2_8_8000.wav") << tst_QWaveDecoder::None << 2 << 8 << 8000;
+ QTest::newRow("File isawav_2_8_44100.wav") << testFilePath("isawav_2_8_44100.wav") << tst_QWaveDecoder::None << 2 << 8 << 44100;
+
+ QTest::newRow("File isawav_1_16_8000_le.wav") << testFilePath("isawav_1_16_8000_le.wav") << tst_QWaveDecoder::None << 1 << 16 << 8000;
+ QTest::newRow("File isawav_1_16_44100_le.wav") << testFilePath("isawav_1_16_44100_le.wav") << tst_QWaveDecoder::None << 1 << 16 << 44100;
+ QTest::newRow("File isawav_2_16_8000_be.wav") << testFilePath("isawav_2_16_8000_be.wav") << tst_QWaveDecoder::None << 2 << 16 << 8000;
+ QTest::newRow("File isawav_2_16_44100_be.wav") << testFilePath("isawav_2_16_44100_be.wav") << tst_QWaveDecoder::None << 2 << 16 << 44100;
+ // The next file has extra data in the wave header.
+ QTest::newRow("File isawav_1_16_44100_le_2.wav") << testFilePath("isawav_1_16_44100_le_2.wav") << tst_QWaveDecoder::None << 1 << 16 << 44100;
+ // The next file has embedded bext chunk with odd payload (QTBUG-122193)
+ QTest::newRow("File isawav_1_8_8000_odd_bext.wav") << testFilePath("isawav_1_8_8000_odd_bext.wav") << tst_QWaveDecoder::None << 1 << 8 << 8000;
+ // The next file has embedded bext chunk with even payload
+ QTest::newRow("File isawav_1_8_8000_even_bext.wav") << testFilePath("isawav_1_8_8000_even_bext.wav") << tst_QWaveDecoder::None << 1 << 8 << 8000;
// 32 bit waves are not supported
- QTest::newRow("File isawav_1_32_8000_le.wav") << testFilePath("isawav_1_32_8000_le.wav") << tst_QWaveDecoder::FormatDescriptor << 1 << 32 << 8000 << QAudioFormat::LittleEndian;
- QTest::newRow("File isawav_1_32_44100_le.wav") << testFilePath("isawav_1_32_44100_le.wav") << tst_QWaveDecoder::FormatDescriptor << 1 << 32 << 44100 << QAudioFormat::LittleEndian;
- QTest::newRow("File isawav_2_32_8000_be.wav") << testFilePath("isawav_2_32_8000_be.wav") << tst_QWaveDecoder::FormatDescriptor << 2 << 32 << 8000 << QAudioFormat::BigEndian;
- QTest::newRow("File isawav_2_32_44100_be.wav") << testFilePath("isawav_2_32_44100_be.wav") << tst_QWaveDecoder::FormatDescriptor << 2 << 32 << 44100 << QAudioFormat::BigEndian;
+ QTest::newRow("File isawav_1_32_8000_le.wav") << testFilePath("isawav_1_32_8000_le.wav") << tst_QWaveDecoder::FormatDescriptor << 1 << 32 << 8000;
+ QTest::newRow("File isawav_1_32_44100_le.wav") << testFilePath("isawav_1_32_44100_le.wav") << tst_QWaveDecoder::FormatDescriptor << 1 << 32 << 44100;
+ QTest::newRow("File isawav_2_32_8000_be.wav") << testFilePath("isawav_2_32_8000_be.wav") << tst_QWaveDecoder::FormatDescriptor << 2 << 32 << 8000;
+ QTest::newRow("File isawav_2_32_44100_be.wav") << testFilePath("isawav_2_32_44100_be.wav") << tst_QWaveDecoder::FormatDescriptor << 2 << 32 << 44100;
}
void tst_QWaveDecoder::file()
@@ -132,7 +107,6 @@ void tst_QWaveDecoder::file()
QFETCH(int, channels);
QFETCH(int, samplesize);
QFETCH(int, samplerate);
- QFETCH(QAudioFormat::Endian, byteorder);
QFile stream;
stream.setFileName(file);
@@ -141,8 +115,10 @@ void tst_QWaveDecoder::file()
QVERIFY(stream.isOpen());
QWaveDecoder waveDecoder(&stream);
- QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown()));
- QSignalSpy parsingErrorSpy(&waveDecoder, SIGNAL(parsingError()));
+ QSignalSpy validFormatSpy(&waveDecoder, &QWaveDecoder::formatKnown);
+ QSignalSpy parsingErrorSpy(&waveDecoder, &QWaveDecoder::parsingError);
+
+ QVERIFY(waveDecoder.open(QIODeviceBase::ReadOnly));
if (corruption == NotAWav) {
QSKIP("Not all failures detected correctly yet");
@@ -174,11 +150,8 @@ void tst_QWaveDecoder::file()
QAudioFormat format = waveDecoder.audioFormat();
QVERIFY(format.isValid());
QVERIFY(format.channelCount() == channels);
- QVERIFY(format.sampleSize() == samplesize);
+ QCOMPARE(format.bytesPerSample() * 8, samplesize);
QVERIFY(format.sampleRate() == samplerate);
- if (format.sampleSize() != 8) {
- QVERIFY(format.byteOrder() == byteorder);
- }
}
stream.close();
@@ -191,7 +164,6 @@ void tst_QWaveDecoder::http()
QFETCH(int, channels);
QFETCH(int, samplesize);
QFETCH(int, samplerate);
- QFETCH(QAudioFormat::Endian, byteorder);
QFile stream;
stream.setFileName(file);
@@ -204,8 +176,10 @@ void tst_QWaveDecoder::http()
QNetworkReply *reply = nam.get(QNetworkRequest(QUrl::fromLocalFile(file)));
QWaveDecoder waveDecoder(reply);
- QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown()));
- QSignalSpy parsingErrorSpy(&waveDecoder, SIGNAL(parsingError()));
+ QSignalSpy validFormatSpy(&waveDecoder, &QWaveDecoder::formatKnown);
+ QSignalSpy parsingErrorSpy(&waveDecoder, &QWaveDecoder::parsingError);
+
+ QVERIFY(waveDecoder.open(QIODeviceBase::ReadOnly));
if (corruption == NotAWav) {
QSKIP("Not all failures detected correctly yet");
@@ -237,11 +211,8 @@ void tst_QWaveDecoder::http()
QAudioFormat format = waveDecoder.audioFormat();
QVERIFY(format.isValid());
QVERIFY(format.channelCount() == channels);
- QVERIFY(format.sampleSize() == samplesize);
+ QCOMPARE(format.bytesPerSample() * 8, samplesize);
QVERIFY(format.sampleRate() == samplerate);
- if (format.sampleSize() != 8) {
- QVERIFY(format.byteOrder() == byteorder);
- }
}
delete reply;
@@ -256,7 +227,9 @@ void tst_QWaveDecoder::readAllAtOnce()
QVERIFY(stream.isOpen());
QWaveDecoder waveDecoder(&stream);
- QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown()));
+ QSignalSpy validFormatSpy(&waveDecoder, &QWaveDecoder::formatKnown);
+
+ QVERIFY(waveDecoder.open(QIODeviceBase::ReadOnly));
QTRY_COMPARE(validFormatSpy.count(), 1);
QVERIFY(waveDecoder.size() > 0);
@@ -282,7 +255,9 @@ void tst_QWaveDecoder::readPerByte()
QVERIFY(stream.isOpen());
QWaveDecoder waveDecoder(&stream);
- QSignalSpy validFormatSpy(&waveDecoder, SIGNAL(formatKnown()));
+ QSignalSpy validFormatSpy(&waveDecoder, &QWaveDecoder::formatKnown);
+
+ QVERIFY(waveDecoder.open(QIODeviceBase::ReadOnly));
QTRY_COMPARE(validFormatSpy.count(), 1);
QVERIFY(waveDecoder.size() > 0);
diff --git a/tests/auto/unit/multimediawidgets/CMakeLists.txt b/tests/auto/unit/multimediawidgets/CMakeLists.txt
index 336488835..87adc0190 100644
--- a/tests/auto/unit/multimediawidgets/CMakeLists.txt
+++ b/tests/auto/unit/multimediawidgets/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from multimediawidgets.pro.
add_subdirectory(qcamerawidgets)
diff --git a/tests/auto/unit/multimediawidgets/qcamerawidgets/CMakeLists.txt b/tests/auto/unit/multimediawidgets/qcamerawidgets/CMakeLists.txt
index 9df51a5b1..486f34690 100644
--- a/tests/auto/unit/multimediawidgets/qcamerawidgets/CMakeLists.txt
+++ b/tests/auto/unit/multimediawidgets/qcamerawidgets/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qcamerawidgets.pro.
#####################################################################
@@ -9,11 +12,11 @@ qt_internal_add_test(tst_qcamerawidgets
tst_qcamerawidgets.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
Qt::MultimediaWidgetsPrivate
Qt::Widgets
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimediawidgets/qcamerawidgets/tst_qcamerawidgets.cpp b/tests/auto/unit/multimediawidgets/qcamerawidgets/tst_qcamerawidgets.cpp
index 7db456190..6c31a4b66 100644
--- a/tests/auto/unit/multimediawidgets/qcamerawidgets/tst_qcamerawidgets.cpp
+++ b/tests/auto/unit/multimediawidgets/qcamerawidgets/tst_qcamerawidgets.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
@@ -42,10 +15,11 @@
#include <qvideosink.h>
#include "qmockmediacapturesession.h"
-#include "qmockintegration_p.h"
+#include "qmockintegration.h"
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
class tst_QCameraWidgets: public QObject
{
@@ -58,9 +32,6 @@ public slots:
private slots:
void testCameraEncodingProperyChange();
void testSetVideoOutput();
-
-private:
- QMockIntegration mockIntegration;
};
void tst_QCameraWidgets::initTestCase()
@@ -80,12 +51,12 @@ void tst_QCameraWidgets::testCameraEncodingProperyChange()
session.setCamera(&camera);
session.setImageCapture(&imageCapture);
- QSignalSpy activeChangedSignal(&camera, SIGNAL(activeChanged(bool)));
+ QSignalSpy activeChangedSignal(&camera, &QCamera::activeChanged);
camera.start();
QCOMPARE(camera.isActive(), true);
- QCOMPARE(activeChangedSignal.count(), 1);
+ QCOMPARE(activeChangedSignal.size(), 1);
}
void tst_QCameraWidgets::testSetVideoOutput()
diff --git a/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/CMakeLists.txt b/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/CMakeLists.txt
index 227eb18ff..599042725 100644
--- a/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/CMakeLists.txt
+++ b/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qgraphicsvideoitem.pro.
#####################################################################
@@ -9,10 +12,10 @@ qt_internal_add_test(tst_qgraphicsvideoitem
tst_qgraphicsvideoitem.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
Qt::MultimediaWidgetsPrivate
Qt::Widgets
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp b/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp
index 583115f99..0cda11de1 100644
--- a/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp
+++ b/tests/auto/unit/multimediawidgets/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtmultimediaglobal.h>
#include "qgraphicsvideoitem.h"
@@ -41,9 +14,12 @@
#include <QtWidgets/qgraphicsscene.h>
#include <QtWidgets/qgraphicsview.h>
-#include <qmockintegration_p.h>
+#include <qmockintegration.h>
QT_USE_NAMESPACE
+
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
class tst_QGraphicsVideoItem : public QObject
{
Q_OBJECT
@@ -66,9 +42,6 @@ private slots:
void boundingRect();
void paint();
-
-public:
- QMockIntegration integration;
};
class QtTestGraphicsVideoItem : public QGraphicsVideoItem
@@ -241,7 +214,7 @@ void tst_QGraphicsVideoItem::nativeSize()
QCOMPARE(item.nativeSize(), QSizeF());
- QSignalSpy spy(&item, SIGNAL(nativeSizeChanged(QSizeF)));
+ QSignalSpy spy(&item, &QGraphicsVideoItem::nativeSizeChanged);
QVideoFrameFormat format(frameSize, QVideoFrameFormat::Format_ARGB8888);
format.setViewport(viewport);
@@ -250,7 +223,7 @@ void tst_QGraphicsVideoItem::nativeSize()
QCoreApplication::processEvents();
QCOMPARE(item.nativeSize(), nativeSize);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.last().first().toSizeF(), nativeSize);
}
@@ -402,7 +375,7 @@ void tst_QGraphicsVideoItem::paint()
QVideoFrameFormat format(QSize(2, 2), QVideoFrameFormat::Format_XRGB8888);
QVideoFrame frame(format);
- frame.map(QVideoFrame::WriteOnly);
+ frame.map(QtVideo::MapMode::WriteOnly);
memcpy(frame.bits(0), rgb32ImageData, frame.mappedBytes(0));
frame.unmap();
diff --git a/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/CMakeLists.txt b/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/CMakeLists.txt
index b1859fb39..7c54e67b9 100644
--- a/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/CMakeLists.txt
+++ b/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qmediaplayerwidgets.pro.
#####################################################################
@@ -9,12 +12,12 @@ qt_internal_add_test(tst_qmediaplayerwidgets
tst_qmediaplayerwidgets.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
# Remove: L${CMAKE_CURRENT_SOURCE_DIR}
Qt::Gui
Qt::MultimediaPrivate
Qt::MultimediaWidgetsPrivate
Qt::Network
Qt::Widgets
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/tst_qmediaplayerwidgets.cpp b/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/tst_qmediaplayerwidgets.cpp
index a8fafc86b..e0f23d477 100644
--- a/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/tst_qmediaplayerwidgets.cpp
+++ b/tests/auto/unit/multimediawidgets/qmediaplayerwidgets/tst_qmediaplayerwidgets.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/qdebug.h>
@@ -38,47 +11,22 @@
#include <private/qplatformmediaplayer_p.h>
#include "qvideosink.h"
-#include "qmockintegration_p.h"
+#include "qmockintegration.h"
QT_USE_NAMESPACE
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
class tst_QMediaPlayerWidgets: public QObject
{
Q_OBJECT
-public slots:
- void initTestCase();
- void cleanupTestCase();
- void init();
- void cleanup();
-
private slots:
void testSetVideoOutput();
void testSetVideoOutputNoService();
void testSetVideoOutputNoControl();
-
-private:
- QMockIntegration *mockIntegration;
};
-void tst_QMediaPlayerWidgets::initTestCase()
-{
- mockIntegration = new QMockIntegration;
-}
-
-void tst_QMediaPlayerWidgets::cleanupTestCase()
-{
- delete mockIntegration;
-}
-
-void tst_QMediaPlayerWidgets::init()
-{
-}
-
-void tst_QMediaPlayerWidgets::cleanup()
-{
-}
-
void tst_QMediaPlayerWidgets::testSetVideoOutput()
{
QVideoWidget widget;
@@ -128,9 +76,9 @@ void tst_QMediaPlayerWidgets::testSetVideoOutputNoService()
QGraphicsVideoItem item;
QVideoSink surface;
- mockIntegration->setFlags(QMockIntegration::NoPlayerInterface);
+ QMockIntegration::instance()->setFlags(QMockIntegration::NoPlayerInterface);
QMediaPlayer player;
- mockIntegration->setFlags({});
+ QMockIntegration::instance()->setFlags({});
player.setVideoOutput(&widget);
diff --git a/tests/auto/unit/multimediawidgets/qvideowidget/BLACKLIST b/tests/auto/unit/multimediawidgets/qvideowidget/BLACKLIST
new file mode 100644
index 000000000..2ce9e48fa
--- /dev/null
+++ b/tests/auto/unit/multimediawidgets/qvideowidget/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-110453
+[fullScreen]
+android
diff --git a/tests/auto/unit/multimediawidgets/qvideowidget/CMakeLists.txt b/tests/auto/unit/multimediawidgets/qvideowidget/CMakeLists.txt
index 673cd7ff6..b179b0b3b 100644
--- a/tests/auto/unit/multimediawidgets/qvideowidget/CMakeLists.txt
+++ b/tests/auto/unit/multimediawidgets/qvideowidget/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qvideowidget.pro.
#####################################################################
@@ -9,10 +12,10 @@ qt_internal_add_test(tst_qvideowidget
tst_qvideowidget.cpp
INCLUDE_DIRECTORIES
../../mockbackend
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::MultimediaPrivate
Qt::MultimediaWidgetsPrivate
Qt::Widgets
- QtMultimediaMockBackend
+ MockMultimediaPlugin
)
diff --git a/tests/auto/unit/multimediawidgets/qvideowidget/tst_qvideowidget.cpp b/tests/auto/unit/multimediawidgets/qvideowidget/tst_qvideowidget.cpp
index 1f43a2be4..b999020a4 100644
--- a/tests/auto/unit/multimediawidgets/qvideowidget/tst_qvideowidget.cpp
+++ b/tests/auto/unit/multimediawidgets/qvideowidget/tst_qvideowidget.cpp
@@ -1,32 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtmultimediaglobal.h>
#include <QtTest/QtTest>
@@ -40,13 +13,19 @@
#include <QtWidgets/qapplication.h>
-#include <qmockintegration_p.h>
+#include <qmockintegration.h>
#include <qmockvideosink.h>
QT_USE_NAMESPACE
+
+Q_ENABLE_MOCK_MULTIMEDIA_PLUGIN
+
class tst_QVideoWidget : public QObject
{
Q_OBJECT
+public slots:
+ void initTestCase();
+
private slots:
void nullObject();
@@ -82,6 +61,15 @@ public:
}
};
+void tst_QVideoWidget::initTestCase()
+{
+#ifdef Q_OS_MACOS
+ if (qEnvironmentVariable("QTEST_ENVIRONMENT").toLower() == "ci")
+ QSKIP("SKIP on macOS CI since metal is not supported, otherwise it often crashes. To be "
+ "fixed.");
+#endif
+}
+
void tst_QVideoWidget::nullObject()
{
QtTestVideoWidget widget;
@@ -117,8 +105,8 @@ void tst_QVideoWidget::show()
void tst_QVideoWidget::aspectRatio()
{
- QMediaPlayer player;
QtTestVideoWidget widget;
+ QMediaPlayer player;
player.setVideoOutput(&widget);
// Test the aspect ratio defaults to keeping the aspect ratio.
@@ -172,11 +160,11 @@ void tst_QVideoWidget::sizeHint()
// QFETCH(QRect, viewport);
QFETCH(QSize, expectedSize);
- QMockIntegration mock;
- QMediaPlayer player;
QtTestVideoWidget widget;
+ QMediaPlayer player;
+
player.setVideoOutput(&widget);
- auto mockSink = mock.lastVideoSink();
+ auto mockSink = QMockIntegration::instance()->lastVideoSink();
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
@@ -188,28 +176,28 @@ void tst_QVideoWidget::sizeHint()
void tst_QVideoWidget::fullScreen()
{
- QMediaPlayer player;
QtTestVideoWidget widget;
+ QMediaPlayer player;
player.setVideoOutput(&widget);
widget.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
Qt::WindowFlags windowFlags = widget.windowFlags();
- QSignalSpy spy(&widget, SIGNAL(fullScreenChanged(bool)));
+ QSignalSpy spy(&widget, &QVideoWidget::fullScreenChanged);
// Test showing full screen with setFullScreen(true).
widget.setFullScreen(true);
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QCOMPARE(widget.isFullScreen(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.value(0).value(0).toBool(), true);
// Test returning to normal with setFullScreen(false).
widget.setFullScreen(false);
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QCOMPARE(widget.isFullScreen(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(spy.value(1).value(0).toBool(), false);
QCOMPARE(widget.windowFlags(), windowFlags);
@@ -217,35 +205,35 @@ void tst_QVideoWidget::fullScreen()
widget.showFullScreen();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QCOMPARE(widget.isFullScreen(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
QCOMPARE(spy.value(2).value(0).toBool(), true);
// Test returning to normal with showNormal().
widget.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QCOMPARE(widget.isFullScreen(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
QCOMPARE(spy.value(3).value(0).toBool(), false);
QCOMPARE(widget.windowFlags(), windowFlags);
// Test setFullScreen(false) and showNormal() do nothing when isFullScreen() == false.
widget.setFullScreen(false);
QCOMPARE(widget.isFullScreen(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
widget.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QCOMPARE(widget.isFullScreen(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
// Test setFullScreen(true) and showFullScreen() do nothing when isFullScreen() == true.
widget.showFullScreen();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
widget.setFullScreen(true);
QCOMPARE(widget.isFullScreen(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
widget.showFullScreen();
QCOMPARE(widget.isFullScreen(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
}
static const uchar rgb32ImageData[] =
@@ -256,8 +244,8 @@ static const uchar rgb32ImageData[] =
void tst_QVideoWidget::paint()
{
- QMediaPlayer player;
QtTestVideoWidget widget;
+ QMediaPlayer player;
player.setVideoOutput(&widget);
widget.resize(640,480);
widget.show();
@@ -265,7 +253,7 @@ void tst_QVideoWidget::paint()
QVideoFrameFormat format(QSize(2, 2), QVideoFrameFormat::Format_XRGB8888);
QVideoFrame frame(format);
- QVERIFY(frame.map(QVideoFrame::ReadWrite));
+ QVERIFY(frame.map(QtVideo::MapMode::ReadWrite));
uchar *data = frame.bits(0);
memcpy(data, rgb32ImageData, sizeof(rgb32ImageData));
frame.unmap();
diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt
new file mode 100644
index 000000000..b37b86192
--- /dev/null
+++ b/tests/manual/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_subdirectory(audiodecoder)
+add_subdirectory(devices)
+add_subdirectory(mediaformats)
+add_subdirectory(minimal-player)
+add_subdirectory(wasm)
+
+if(QT_FEATURE_gstreamer)
+ add_subdirectory(gstreamer-custom-camera)
+ add_subdirectory(gstreamer-custom-camera-rtp)
+endif()
+
+if(TARGET Qt::Quick)
+ add_subdirectory(qml-minimal-camera)
+ add_subdirectory(qml-minimal-player)
+
+ if(QT_FEATURE_gstreamer)
+ add_subdirectory(qml-gstreamer-rtp)
+ endif()
+endif()
diff --git a/tests/manual/audiodecoder/CMakeLists.txt b/tests/manual/audiodecoder/CMakeLists.txt
new file mode 100644
index 000000000..758c3a913
--- /dev/null
+++ b/tests/manual/audiodecoder/CMakeLists.txt
@@ -0,0 +1,45 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(audiodecoder LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/audiodecoder")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Multimedia Widgets)
+
+if(ANDROID)
+
+endif()
+
+qt_add_executable(audiodecoder
+ audiodecoder.cpp audiodecoder.h
+ main.cpp
+)
+
+set_target_properties(audiodecoder PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(audiodecoder PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Multimedia
+)
+
+if(ANDROID)
+ target_link_libraries(audiodecoder PUBLIC Qt::Widgets)
+endif()
+
+install(TARGETS audiodecoder
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/audiodecoder/audiodecoder.cpp b/tests/manual/audiodecoder/audiodecoder.cpp
new file mode 100644
index 000000000..a8d127ab5
--- /dev/null
+++ b/tests/manual/audiodecoder/audiodecoder.cpp
@@ -0,0 +1,162 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "audiodecoder.h"
+
+#include <QFile>
+
+#include <stdio.h>
+
+AudioDecoder::AudioDecoder(bool isPlayback, bool isDelete, const QString &targetFileName)
+ : m_cout(stdout, QIODevice::WriteOnly), m_targetFilename(targetFileName)
+{
+ m_isPlayback = isPlayback;
+ m_isDelete = isDelete;
+
+ connect(&m_decoder, &QAudioDecoder::bufferReady, this, &AudioDecoder::bufferReady);
+ connect(&m_decoder, QOverload<QAudioDecoder::Error>::of(&QAudioDecoder::error), this,
+ QOverload<QAudioDecoder::Error>::of(&AudioDecoder::error));
+ connect(&m_decoder, &QAudioDecoder::isDecodingChanged, this, &AudioDecoder::isDecodingChanged);
+ connect(&m_decoder, &QAudioDecoder::finished, this, &AudioDecoder::finished);
+ connect(&m_decoder, &QAudioDecoder::positionChanged, this, &AudioDecoder::updateProgress);
+ connect(&m_decoder, &QAudioDecoder::durationChanged, this, &AudioDecoder::updateProgress);
+
+ connect(&m_soundEffect, &QSoundEffect::statusChanged, this,
+ &AudioDecoder::playbackStatusChanged);
+ connect(&m_soundEffect, &QSoundEffect::playingChanged, this, &AudioDecoder::playingChanged);
+
+ m_progress = -1.0;
+}
+
+AudioDecoder::~AudioDecoder()
+{
+ delete m_waveDecoder;
+}
+
+void AudioDecoder::setSource(const QString &fileName)
+{
+ m_decoder.setSource(QUrl::fromLocalFile(fileName));
+}
+
+void AudioDecoder::start()
+{
+ m_decoder.start();
+}
+
+void AudioDecoder::stop()
+{
+ m_decoder.stop();
+}
+
+QAudioDecoder::Error AudioDecoder::getError()
+{
+ return m_decoder.error();
+}
+
+void AudioDecoder::setTargetFilename(const QString &fileName)
+{
+ m_targetFilename = fileName;
+}
+
+void AudioDecoder::bufferReady()
+{
+ // read a buffer from audio decoder
+ QAudioBuffer buffer = m_decoder.read();
+ if (!buffer.isValid())
+ return;
+
+ if (!m_waveDecoder) {
+ QIODevice *target = new QFile(m_targetFilename, this);
+ if (!target->open(QIODevice::WriteOnly)) {
+ qWarning() << "target file is not writable";
+ m_decoder.stop();
+ return;
+ }
+ m_waveDecoder = new QWaveDecoder(target, buffer.format());
+ }
+
+ if (!m_waveDecoder
+ || (!m_waveDecoder->isOpen() && !m_waveDecoder->open(QIODevice::WriteOnly))) {
+ m_decoder.stop();
+ return;
+ }
+
+ m_waveDecoder->write(buffer.constData<char>(), buffer.byteCount());
+}
+
+void AudioDecoder::error(QAudioDecoder::Error error)
+{
+ switch (error) {
+ case QAudioDecoder::NoError:
+ return;
+ case QAudioDecoder::ResourceError:
+ m_cout << "Resource error\n";
+ break;
+ case QAudioDecoder::FormatError:
+ m_cout << "Format error\n";
+ break;
+ case QAudioDecoder::AccessDeniedError:
+ m_cout << "Access denied error\n";
+ break;
+ case QAudioDecoder::NotSupportedError:
+ m_cout << "Service missing error\n";
+ break;
+ }
+
+ emit done();
+}
+
+void AudioDecoder::isDecodingChanged(bool isDecoding)
+{
+ if (isDecoding)
+ m_cout << "Decoding...\n";
+ else
+ m_cout << "Decoding stopped\n";
+}
+
+void AudioDecoder::finished()
+{
+ m_waveDecoder->close();
+ m_cout << "Decoding finished\n";
+
+ if (m_isPlayback) {
+ m_cout << "Starting playback\n";
+ m_soundEffect.setSource(QUrl::fromLocalFile(m_targetFilename));
+ m_soundEffect.play();
+ } else {
+ emit done();
+ }
+}
+
+void AudioDecoder::playbackStatusChanged()
+{
+ if (m_soundEffect.status() == QSoundEffect::Error) {
+ m_cout << "Playback error\n";
+ emit done();
+ }
+}
+
+void AudioDecoder::playingChanged()
+{
+ if (!m_soundEffect.isPlaying()) {
+ m_cout << "Playback finished\n";
+ if (m_isDelete)
+ QFile::remove(m_targetFilename);
+ emit done();
+ }
+}
+
+void AudioDecoder::updateProgress()
+{
+ qint64 position = m_decoder.position();
+ qint64 duration = m_decoder.duration();
+ qreal progress = m_progress;
+ if (position >= 0 && duration > 0)
+ progress = position / (qreal)duration;
+
+ if (progress > m_progress + 0.1) {
+ m_cout << "Decoding progress: " << (int)(progress * 100.0) << "%\n";
+ m_progress = progress;
+ }
+}
+
diff --git a/tests/manual/audiodecoder/audiodecoder.h b/tests/manual/audiodecoder/audiodecoder.h
new file mode 100644
index 000000000..25ce6501b
--- /dev/null
+++ b/tests/manual/audiodecoder/audiodecoder.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef AUDIODECODER_H
+#define AUDIODECODER_H
+
+#include <QAudioDecoder>
+#include <QSoundEffect>
+#include <QTextStream>
+#include <QWaveDecoder>
+
+class AudioDecoder : public QObject
+{
+ Q_OBJECT
+
+public:
+ AudioDecoder(bool isPlayback, bool isDelete, const QString &targetFileName);
+ ~AudioDecoder();
+
+ void setSource(const QString &fileName);
+ void start();
+ void stop();
+ QAudioDecoder::Error getError();
+
+ void setTargetFilename(const QString &fileName);
+
+signals:
+ void done();
+
+public slots:
+ void bufferReady();
+ void error(QAudioDecoder::Error error);
+ void isDecodingChanged(bool isDecoding);
+ void finished();
+
+ void playbackStatusChanged();
+ void playingChanged();
+
+private slots:
+ void updateProgress();
+
+private:
+ bool m_isPlayback;
+ bool m_isDelete;
+ QAudioDecoder m_decoder;
+ QTextStream m_cout;
+
+ QString m_targetFilename;
+ QWaveDecoder *m_waveDecoder = nullptr;
+ QSoundEffect m_soundEffect;
+
+ qreal m_progress;
+};
+
+#endif // AUDIODECODER_H
diff --git a/tests/manual/audiodecoder/audiodecoder.pro b/tests/manual/audiodecoder/audiodecoder.pro
new file mode 100644
index 000000000..7870d340e
--- /dev/null
+++ b/tests/manual/audiodecoder/audiodecoder.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+TARGET = audiodecoder
+
+HEADERS = \
+ audiodecoder.h
+SOURCES = main.cpp \
+ audiodecoder.cpp
+
+QT += multimedia
+CONFIG += console
+
+target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audiodecoder
+INSTALLS += target
diff --git a/tests/manual/audiodecoder/main.cpp b/tests/manual/audiodecoder/main.cpp
new file mode 100644
index 000000000..c02bdfabf
--- /dev/null
+++ b/tests/manual/audiodecoder/main.cpp
@@ -0,0 +1,83 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "audiodecoder.h"
+
+#include <QCoreApplication>
+#include <QDir>
+#include <QFileInfo>
+#include <QTextStream>
+#ifdef Q_OS_ANDROID
+# include <QApplication>
+# include <QFileDialog>
+# include <QMessageBox>
+# include <QStandardPaths>
+#endif
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#ifdef Q_OS_ANDROID
+ QApplication app(argc, argv);
+#else
+ QCoreApplication app(argc, argv);
+#endif
+
+ QFileInfo sourceFile;
+ QFileInfo targetFile;
+ bool isPlayback = false;
+ bool isDelete = false;
+
+#ifndef Q_OS_ANDROID
+ QTextStream cout(stdout, QIODevice::WriteOnly);
+ if (app.arguments().size() < 2) {
+ cout << "Usage: audiodecoder [-p] [-pd] SOURCEFILE [TARGETFILE]\n";
+ cout << "Set -p option if you want to play output file.\n";
+ cout << "Set -pd option if you want to play output file and delete it after successful "
+ "playback.\n";
+ cout << "Default TARGETFILE name is \"out.wav\" in the same directory as the source "
+ "file.\n";
+ return 0;
+ }
+
+ if (app.arguments().at(1) == "-p")
+ isPlayback = true;
+ else if (app.arguments().at(1) == "-pd") {
+ isPlayback = true;
+ isDelete = true;
+ }
+
+ int sourceFileIndex = (isPlayback || isDelete) ? 2 : 1;
+ if (app.arguments().size() <= sourceFileIndex) {
+ cout << "Error: source filename is not specified.\n";
+ return 0;
+ }
+
+ sourceFile.setFile(app.arguments().at(sourceFileIndex));
+ if (app.arguments().size() > sourceFileIndex + 1)
+ targetFile.setFile(app.arguments().at(sourceFileIndex + 1));
+ else
+ targetFile.setFile(sourceFile.dir().absoluteFilePath("out.wav"));
+
+#else
+
+ const QString message = "You will be prompted to select an audio file (e.g. mp3 or ogg format) "
+ "which will be decoded and played back to you.";
+ QMessageBox messageBox(QMessageBox::Information, "Audio Decoder", message, QMessageBox::Ok);
+ messageBox.exec();
+ sourceFile =
+ QFileInfo(QFileDialog::getOpenFileName(messageBox.parentWidget(), "Select Audio File"));
+ auto musicPath = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
+ targetFile = QFileInfo(musicPath.append("/out.wav"));
+ isPlayback = true;
+#endif
+ AudioDecoder decoder(isPlayback, isDelete, targetFile.absoluteFilePath());
+ QObject::connect(&decoder, &AudioDecoder::done, &app, &QCoreApplication::quit);
+ decoder.setSource(sourceFile.absoluteFilePath());
+ decoder.start();
+ if (decoder.getError() != QAudioDecoder::NoError)
+ return 0;
+
+ return app.exec();
+}
diff --git a/tests/manual/devices/CMakeLists.txt b/tests/manual/devices/CMakeLists.txt
new file mode 100644
index 000000000..cae0c577f
--- /dev/null
+++ b/tests/manual/devices/CMakeLists.txt
@@ -0,0 +1,40 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(devices LANGUAGES CXX)
+
+if(ANDROID OR IOS)
+ message(FATAL_ERROR "This is a commandline tool that is not supported on mobile platforms")
+endif()
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/devices")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Multimedia)
+
+qt_add_executable(devices
+ main.cpp
+)
+
+set_target_properties(devices PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(devices PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Multimedia
+)
+
+install(TARGETS devices
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/devices/devices.pro b/tests/manual/devices/devices.pro
new file mode 100644
index 000000000..bbc5ecea8
--- /dev/null
+++ b/tests/manual/devices/devices.pro
@@ -0,0 +1,12 @@
+android|ios: error("This is a commandline tool that is not supported on mobile platforms")
+
+TEMPLATE = app
+TARGET = devices
+
+SOURCES = main.cpp
+
+QT += multimedia
+CONFIG += console
+
+target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/devices
+INSTALLS += target
diff --git a/tests/manual/devices/main.cpp b/tests/manual/devices/main.cpp
new file mode 100644
index 000000000..67b277812
--- /dev/null
+++ b/tests/manual/devices/main.cpp
@@ -0,0 +1,136 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QAudioDevice>
+#include <QAudioFormat>
+#include <QCameraDevice>
+#include <QCoreApplication>
+#include <QMediaDevices>
+#include <QString>
+#include <QTextStream>
+
+#include <stdio.h>
+
+static QString formatToString(QAudioFormat::SampleFormat sampleFormat)
+{
+ switch (sampleFormat) {
+ case QAudioFormat::UInt8:
+ return "UInt8";
+ case QAudioFormat::Int16:
+ return "Int16";
+ case QAudioFormat::Int32:
+ return "Int32";
+ case QAudioFormat::Float:
+ return "Float";
+ default:
+ return "Unknown";
+ }
+}
+
+static QString positionToString(QCameraDevice::Position position)
+{
+ switch (position) {
+ case QCameraDevice::BackFace:
+ return "BackFace";
+ case QCameraDevice::FrontFace:
+ return "FrontFace";
+ default:
+ return "Unspecified";
+ }
+}
+
+static void printAudioDeviceInfo(QTextStream &out, const QAudioDevice &deviceInfo)
+{
+ const auto isDefault = deviceInfo.isDefault() ? "Yes" : "No";
+ const auto preferredFormat = deviceInfo.preferredFormat();
+ const auto supportedFormats = deviceInfo.supportedSampleFormats();
+ out.setFieldWidth(30);
+ out.setFieldAlignment(QTextStream::AlignLeft);
+ out << "Name: " << deviceInfo.description() << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Id: " << QString::fromLatin1(deviceInfo.id()) << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Default: " << isDefault << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Preferred Format: " << formatToString(preferredFormat.sampleFormat())
+ << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Preferred Rate: " << preferredFormat.sampleRate() << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Preferred Channels: " << preferredFormat.channelCount() << qSetFieldWidth(0)
+ << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Supported Formats: ";
+ for (auto &format : supportedFormats)
+ out << qSetFieldWidth(0) << formatToString(format) << " ";
+ out << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Supported Rates: " << qSetFieldWidth(0) << deviceInfo.minimumSampleRate() << " - "
+ << deviceInfo.maximumSampleRate() << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Supported Channels: " << qSetFieldWidth(0) << deviceInfo.minimumChannelCount() << " - "
+ << deviceInfo.maximumChannelCount() << Qt::endl;
+
+ out << Qt::endl;
+}
+
+static void printVideoDeviceInfo(QTextStream &out, const QCameraDevice &cameraDevice)
+{
+ const auto isDefault = cameraDevice.isDefault() ? "Yes" : "No";
+ const auto position = cameraDevice.position();
+ const auto photoResolutions = cameraDevice.photoResolutions();
+ const auto videoFormats = cameraDevice.videoFormats();
+
+ out.setFieldWidth(30);
+ out.setFieldAlignment(QTextStream::AlignLeft);
+ out << "Name: " << cameraDevice.description() << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Id: " << QString::fromLatin1(cameraDevice.id()) << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Default: " << isDefault << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Position: " << positionToString(position) << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Photo Resolutions: ";
+ for (auto &resolution : photoResolutions) {
+ QString s = QStringLiteral("%1x%2").arg(resolution.width()).arg(resolution.height());
+ out << qSetFieldWidth(0) << s << ", ";
+ }
+ out.setFieldWidth(10);
+ out << Qt::endl << Qt::endl;
+ out << "Supported Video Formats: " << qSetFieldWidth(0) << Qt::endl;
+ for (auto &format : videoFormats) {
+ out.setFieldWidth(30);
+ QString s =
+ QStringLiteral("%1x%2").arg(format.resolution().width()).arg(format.resolution().height());
+ out << "Resolution: " << s << qSetFieldWidth(0) << Qt::endl;
+ out.setFieldWidth(30);
+ out << "Frame Rate: " << qSetFieldWidth(0) << "Min:" << format.minFrameRate()
+ << " Max:" << format.maxFrameRate() << Qt::endl;
+ }
+
+ out << Qt::endl;
+}
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv); // QtMultimedia needs an application singleton
+
+ QTextStream out(stdout);
+
+ const auto audioInputDevices = QMediaDevices::audioInputs();
+ const auto audioOutputDevices = QMediaDevices::audioOutputs();
+ const auto videoInputDevices = QMediaDevices::videoInputs();
+
+ out << "Audio devices detected: " << Qt::endl;
+ out << Qt::endl << "Input" << Qt::endl;
+ for (auto &deviceInfo : audioInputDevices)
+ printAudioDeviceInfo(out, deviceInfo);
+ out << Qt::endl << "Output" << Qt::endl;
+ for (auto &deviceInfo : audioOutputDevices)
+ printAudioDeviceInfo(out, deviceInfo);
+
+ out << Qt::endl << "Video devices detected: " << Qt::endl;
+ for (auto &cameraDevice : videoInputDevices)
+ printVideoDeviceInfo(out, cameraDevice);
+}
diff --git a/tests/manual/gstreamer-custom-camera-rtp/CMakeLists.txt b/tests/manual/gstreamer-custom-camera-rtp/CMakeLists.txt
new file mode 100644
index 000000000..58608db5c
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera-rtp/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(gstreamer-custom-camera-rtp LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/gstreamer-custom-camera-rtp")
+
+find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets QGstreamerMediaPluginPrivate)
+
+qt_add_executable( gstreamer-custom-camera-rtp WIN32 MACOSX_BUNDLE
+ gstreamer-custom-camera-rtp.cpp
+ Info.plist.in
+)
+
+target_link_libraries( gstreamer-custom-camera-rtp PUBLIC
+ Qt::Widgets
+ Qt::Multimedia
+ Qt::MultimediaPrivate
+ Qt::MultimediaWidgets
+
+ Qt::QGstreamerMediaPluginPrivate
+)
+
+install(TARGETS gstreamer-custom-camera-rtp
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+set_target_properties( gstreamer-custom-camera-rtp PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+)
diff --git a/tests/manual/gstreamer-custom-camera-rtp/Info.plist.in b/tests/manual/gstreamer-custom-camera-rtp/Info.plist.in
new file mode 100644
index 000000000..46a9ecf2d
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera-rtp/Info.plist.in
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSCameraUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/manual/gstreamer-custom-camera-rtp/gstreamer-custom-camera-rtp.cpp b/tests/manual/gstreamer-custom-camera-rtp/gstreamer-custom-camera-rtp.cpp
new file mode 100644
index 000000000..b61df7ce9
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera-rtp/gstreamer-custom-camera-rtp.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtMultimedia/QAudioOutput>
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+#include <QtMultimediaWidgets/QtMultimediaWidgets>
+#include <QtWidgets/QApplication>
+#include <QtCore/QCommandLineParser>
+
+#include <QtQGstreamerMediaPlugin/private/qgst_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgstpipeline_p.h>
+
+using namespace std::chrono_literals;
+using namespace Qt::Literals;
+
+struct GStreamerRtpStreamSender
+{
+ GStreamerRtpStreamSender()
+ {
+ element = QGstElement::createFromPipelineDescription(
+ "videotestsrc ! jpegenc ! rtpjpegpay ! udpsink host=127.0.0.1 port=50004"_ba);
+
+ pipeline.add(element);
+ pipeline.setStateSync(GstState::GST_STATE_PLAYING);
+ pipeline.dumpGraph("sender");
+ }
+
+ ~GStreamerRtpStreamSender() { pipeline.setStateSync(GstState::GST_STATE_NULL); }
+
+ QGstPipeline pipeline = QGstPipeline::create("UdpSend");
+ QGstElement element;
+};
+
+int main(int argc, char **argv)
+{
+ qputenv("QT_MEDIA_BACKEND", "gstreamer");
+
+ gst_init(&argc, &argv);
+ GStreamerRtpStreamSender sender;
+
+ QApplication app(argc, argv);
+
+ QByteArray pipelineString =
+ R"(udpsrc port=50004 ! application/x-rtp,encoding=JPEG,payload=26 ! rtpjpegdepay ! jpegdec ! videoconvert)"_ba;
+ QVideoWidget wid;
+ wid.show();
+
+ QMediaCaptureSession session;
+ session.setVideoSink(wid.videoSink());
+
+ QCamera *cam = QGStreamerPlatformSpecificInterface::instance()->makeCustomGStreamerCamera(
+ pipelineString, &session);
+ session.setCamera(cam);
+ cam->start();
+
+ return QApplication::exec();
+}
diff --git a/tests/manual/gstreamer-custom-camera/CMakeLists.txt b/tests/manual/gstreamer-custom-camera/CMakeLists.txt
new file mode 100644
index 000000000..f161a0630
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(gstreamer-custom-camera-rtp LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/gstreamer-custom-camera")
+
+find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets)
+
+qt_add_executable( gstreamer-custom-camera WIN32 MACOSX_BUNDLE
+ gstreamer-custom-camera.cpp
+ Info.plist.in
+)
+
+target_link_libraries( gstreamer-custom-camera PUBLIC
+ Qt::Widgets
+ Qt::Multimedia
+ Qt::MultimediaPrivate
+ Qt::MultimediaWidgets
+)
+
+install(TARGETS gstreamer-custom-camera
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+set_target_properties( gstreamer-custom-camera PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+)
diff --git a/tests/manual/gstreamer-custom-camera/Info.plist.in b/tests/manual/gstreamer-custom-camera/Info.plist.in
new file mode 100644
index 000000000..46a9ecf2d
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera/Info.plist.in
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSCameraUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp b/tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp
new file mode 100644
index 000000000..dbd729d15
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtMultimedia/QAudioOutput>
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+#include <QtMultimediaWidgets/QtMultimediaWidgets>
+#include <QtWidgets/QApplication>
+#include <QtCore/QCommandLineParser>
+
+using namespace std::chrono_literals;
+using namespace Qt::Literals;
+
+int main(int argc, char **argv)
+{
+ qputenv("QT_MEDIA_BACKEND", "gstreamer");
+
+ QApplication app(argc, argv);
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("GStreamer Custom Camera");
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addPositionalArgument(
+ "pipeline", "Pipeline string, e.g. `videotestsrc pattern=smpte-rp-219 is-live=true`");
+
+ parser.process(app);
+
+ QByteArray pipelineString;
+
+ if (parser.positionalArguments().isEmpty()) {
+ // pipelineString = "videotestsrc pattern=smpte-rp-219 is-live=true";
+ pipelineString = "videotestsrc is-live=true ! gamma gamma=2.0";
+ } else {
+ pipelineString = parser.positionalArguments()[0].toLatin1();
+ }
+
+ QVideoWidget wid;
+
+ QMediaCaptureSession session;
+ session.setVideoSink(wid.videoSink());
+
+ QCamera *cam = QGStreamerPlatformSpecificInterface::instance()->makeCustomGStreamerCamera(
+ pipelineString, &session);
+ session.setCamera(cam);
+ cam->start();
+
+ wid.show();
+
+ return QApplication::exec();
+}
diff --git a/tests/manual/mediaformats/CMakeLists.txt b/tests/manual/mediaformats/CMakeLists.txt
new file mode 100644
index 000000000..ed58e628e
--- /dev/null
+++ b/tests/manual/mediaformats/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(devices LANGUAGES CXX)
+
+if(ANDROID OR IOS)
+ message(FATAL_ERROR "This is a commandline tool that is not supported on mobile platforms")
+endif()
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/mediaformats")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Multimedia)
+
+qt_add_executable(mediaformats
+ main.cpp
+)
+
+set_target_properties(mediaformats PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(mediaformats PUBLIC
+ Qt::Core
+ Qt::Multimedia
+)
+
+install(TARGETS mediaformats
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/mediaformats/main.cpp b/tests/manual/mediaformats/main.cpp
new file mode 100644
index 000000000..57d0ad831
--- /dev/null
+++ b/tests/manual/mediaformats/main.cpp
@@ -0,0 +1,87 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QMimeType>
+#include <QtCore/QTextStream>
+#include <QtMultimedia/QMediaFormat>
+
+#include <stdio.h>
+
+namespace {
+
+void printFileFormatEntry(QMediaFormat::FileFormat format, QTextStream &out)
+{
+ out << " " << QMediaFormat::fileFormatName(format) << " - "
+ << QMediaFormat::fileFormatDescription(format);
+
+ QMimeType mimeType = QMediaFormat(format).mimeType();
+ if (mimeType.isValid()) {
+ out << " (" << mimeType.name() << ")\n";
+ out << " " << mimeType.suffixes().join(", ") << "\n";
+ }
+}
+
+void printCodecEntry(QMediaFormat::AudioCodec codec, QTextStream &out)
+{
+ out << " " << QMediaFormat::audioCodecName(codec) << " - "
+ << QMediaFormat::audioCodecDescription(codec) << "\n";
+}
+
+void printCodecEntry(QMediaFormat::VideoCodec codec, QTextStream &out)
+{
+ out << " " << QMediaFormat::videoCodecName(codec) << " - "
+ << QMediaFormat::videoCodecDescription(codec) << "\n";
+}
+
+void printFileFormats(QTextStream &out)
+{
+ out << "Supported file formats for decoding: \n";
+ for (QMediaFormat::FileFormat format :
+ QMediaFormat().supportedFileFormats(QMediaFormat::Decode))
+ printFileFormatEntry(format, out);
+
+ out << "\nSupported file formats for encoding: \n";
+ for (QMediaFormat::FileFormat format :
+ QMediaFormat().supportedFileFormats(QMediaFormat::Encode))
+ printFileFormatEntry(format, out);
+}
+
+void printAudioCodecs(QTextStream &out)
+{
+ out << "Supported audio codecs for decoding: \n";
+ for (QMediaFormat::AudioCodec codec : QMediaFormat().supportedAudioCodecs(QMediaFormat::Decode))
+ printCodecEntry(codec, out);
+
+ out << "\nSupported audio codecs for encoding: \n";
+ for (QMediaFormat::AudioCodec codec : QMediaFormat().supportedAudioCodecs(QMediaFormat::Encode))
+ printCodecEntry(codec, out);
+}
+
+void printVideoCodecs(QTextStream &out)
+{
+ out << "Supported video codecs for decoding: \n";
+ for (QMediaFormat::VideoCodec codec : QMediaFormat().supportedVideoCodecs(QMediaFormat::Decode))
+ printCodecEntry(codec, out);
+
+ out << "\nSupported video codecs for encoding: \n";
+ for (QMediaFormat::VideoCodec codec : QMediaFormat().supportedVideoCodecs(QMediaFormat::Encode))
+ printCodecEntry(codec, out);
+}
+
+} // namespace
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv); // QtMultimedia needs an application singleton
+
+ QTextStream out(stdout);
+
+ printFileFormats(out);
+ out << "\n";
+ printAudioCodecs(out);
+ out << "\n";
+ printVideoCodecs(out);
+
+ return 0;
+}
diff --git a/tests/manual/minimal-player/CMakeLists.txt b/tests/manual/minimal-player/CMakeLists.txt
new file mode 100644
index 000000000..6a5f5dfb0
--- /dev/null
+++ b/tests/manual/minimal-player/CMakeLists.txt
@@ -0,0 +1,35 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(sidepanel LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/minimal-player")
+
+find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets)
+
+qt_add_executable( minimal-player WIN32 MACOSX_BUNDLE
+ minimal-player.cpp
+)
+
+target_link_libraries( minimal-player PUBLIC
+ Qt::Widgets
+ Qt::Multimedia
+ Qt::MultimediaWidgets
+)
+
+install(TARGETS minimal-player
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+set_target_properties( minimal-player PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+)
diff --git a/tests/manual/minimal-player/Info.plist.in b/tests/manual/minimal-player/Info.plist.in
new file mode 100644
index 000000000..46a9ecf2d
--- /dev/null
+++ b/tests/manual/minimal-player/Info.plist.in
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSCameraUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/manual/minimal-player/minimal-player.cpp b/tests/manual/minimal-player/minimal-player.cpp
new file mode 100644
index 000000000..17a11b050
--- /dev/null
+++ b/tests/manual/minimal-player/minimal-player.cpp
@@ -0,0 +1,94 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/QTimer>
+#include <QtCore/QCommandLineParser>
+#include <QtMultimedia/QAudioOutput>
+#include <QtMultimedia/QMediaPlayer>
+#include <QtMultimediaWidgets/QVideoWidget>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QWidget>
+
+using namespace std::chrono_literals;
+using namespace Qt::Literals;
+
+int mainToggleWidgets(QString filename)
+{
+ QMediaPlayer player;
+ QVideoWidget widget1;
+ QVideoWidget widget2;
+ QAudioOutput audioOutput;
+ player.setVideoOutput(&widget1);
+ player.setAudioOutput(&audioOutput);
+ player.setSource(filename);
+
+ QTimer toggleOutput;
+ bool toggled = {};
+
+ toggleOutput.callOnTimeout([&] {
+ toggled = !toggled;
+ if (toggled)
+ player.setVideoOutput(&widget2);
+ else
+ player.setVideoOutput(&widget1);
+ });
+
+ toggleOutput.setInterval(1s);
+ toggleOutput.start();
+
+ widget1.show();
+ widget2.show();
+ player.play();
+ return QApplication::exec();
+}
+
+int mainSimple(QString filename, bool loop)
+{
+ QMediaPlayer player;
+ QVideoWidget widget1;
+ QAudioOutput audioOutput;
+ player.setVideoOutput(&widget1);
+ player.setAudioOutput(&audioOutput);
+ player.setSource(filename);
+
+ widget1.show();
+
+ if (loop)
+ player.setLoops(QMediaPlayer::Infinite);
+
+ player.play();
+ return QApplication::exec();
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("Minimal Player");
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addPositionalArgument("media", "File to play");
+
+ QCommandLineOption toggleWidgetsOption{ "toggle-widgets", "Toggle between widgets." };
+ parser.addOption(toggleWidgetsOption);
+
+ QCommandLineOption loopOption{ "loop", "Loop." };
+ parser.addOption(loopOption);
+
+ parser.process(app);
+
+ if (parser.positionalArguments().isEmpty()) {
+ qInfo() << "Please specify a video source";
+ return 0;
+ }
+
+ QString filename = parser.positionalArguments()[0];
+
+ if (parser.isSet(toggleWidgetsOption))
+ return mainToggleWidgets(filename);
+
+ bool loop = parser.isSet(loopOption);
+
+ return mainSimple(filename, loop);
+}
diff --git a/tests/manual/qml-gstreamer-rtp/CMakeLists.txt b/tests/manual/qml-gstreamer-rtp/CMakeLists.txt
new file mode 100644
index 000000000..29ea2a46a
--- /dev/null
+++ b/tests/manual/qml-gstreamer-rtp/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(sidepanel LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/qml-gstreamer-rtp")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Multimedia Qml Quick)
+
+qt_add_executable( qml-gstreamer-rtp WIN32 MACOSX_BUNDLE
+ qml-gstreamer-rtp.cpp
+)
+
+qt_add_qml_module( qml-gstreamer-rtp
+ URI QmlMinimalplayer
+ NO_RESOURCE_TARGET_PATH
+ QML_FILES
+ "qml-gstreamer-rtp.qml"
+)
+
+target_link_libraries( qml-gstreamer-rtp PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+install(TARGETS qml-gstreamer-rtp
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+set_target_properties( qml-gstreamer-rtp PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+)
diff --git a/tests/manual/qml-gstreamer-rtp/Info.plist.in b/tests/manual/qml-gstreamer-rtp/Info.plist.in
new file mode 100644
index 000000000..46a9ecf2d
--- /dev/null
+++ b/tests/manual/qml-gstreamer-rtp/Info.plist.in
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSCameraUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.cpp b/tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.cpp
new file mode 100644
index 000000000..44e8f1659
--- /dev/null
+++ b/tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QGuiApplication>
+#include <QProcess>
+#include <QQmlApplicationEngine>
+#include <QtEnvironmentVariables>
+
+int main(int argc, char *argv[])
+{
+ qputenv("QT_MEDIA_BACKEND", "gstreamer");
+
+ QProcess process;
+ process.startCommand(
+ "gst-launch-1.0 videotestsrc ! x264enc ! udpsink host=127.0.0.1 port=50004");
+
+ auto scopeGuard = qScopeGuard([&] {
+ process.terminate();
+ process.waitForFinished();
+ });
+
+ QGuiApplication app(argc, argv);
+ QQmlApplicationEngine engine;
+
+ process.waitForStarted();
+
+ engine.load(QUrl("qrc:/qml-gstreamer-rtp.qml"));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+
+ return app.exec();
+}
diff --git a/tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.qml b/tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.qml
new file mode 100644
index 000000000..73ec976fb
--- /dev/null
+++ b/tests/manual/qml-gstreamer-rtp/qml-gstreamer-rtp.qml
@@ -0,0 +1,29 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+import QtQuick
+import QtQuick.Controls
+import QtMultimedia
+
+ApplicationWindow {
+ id: window
+ width: 800
+ height: 600
+ visible: true
+ title: qsTr("GStreamer RTP receiver")
+
+ MediaPlayer {
+ id: player
+ videoOutput: output
+
+ source: "udp://127.0.0.1:50004"
+ }
+
+ Component.onCompleted: {
+ player.play()
+ }
+
+ VideoOutput {
+ id: output
+ anchors.fill: parent
+ }
+}
diff --git a/tests/manual/qml-minimal-camera/CMakeLists.txt b/tests/manual/qml-minimal-camera/CMakeLists.txt
new file mode 100644
index 000000000..fcd4676b3
--- /dev/null
+++ b/tests/manual/qml-minimal-camera/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(sidepanel LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/qml-minimal-camera")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Multimedia Qml Quick)
+
+qt_add_executable( qml-minimal-camera WIN32 MACOSX_BUNDLE
+ qml-minimal-camera.cpp
+)
+
+qt_add_qml_module( qml-minimal-camera
+ URI QmlMinimalCamera
+ NO_RESOURCE_TARGET_PATH
+ QML_FILES
+ "qml-minimal-camera.qml"
+)
+
+target_link_libraries( qml-minimal-camera PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+install(TARGETS qml-minimal-camera
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+set_target_properties( qml-minimal-camera PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+)
diff --git a/tests/manual/qml-minimal-camera/Info.plist.in b/tests/manual/qml-minimal-camera/Info.plist.in
new file mode 100644
index 000000000..46a9ecf2d
--- /dev/null
+++ b/tests/manual/qml-minimal-camera/Info.plist.in
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSCameraUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/manual/qml-minimal-camera/qml-minimal-camera.cpp b/tests/manual/qml-minimal-camera/qml-minimal-camera.cpp
new file mode 100644
index 000000000..c61b92992
--- /dev/null
+++ b/tests/manual/qml-minimal-camera/qml-minimal-camera.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl("qrc:/qml-minimal-camera.qml"));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+
+ return app.exec();
+}
diff --git a/tests/manual/qml-minimal-camera/qml-minimal-camera.qml b/tests/manual/qml-minimal-camera/qml-minimal-camera.qml
new file mode 100644
index 000000000..3965c663e
--- /dev/null
+++ b/tests/manual/qml-minimal-camera/qml-minimal-camera.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+import QtMultimedia
+
+ApplicationWindow {
+ id: window
+ width: 800
+ height: 600
+ visible: true
+ title: qsTr("QmlMinimalCamera")
+
+ MediaDevices {
+ id: mediaDevices
+ }
+
+ CaptureSession {
+ id: captureSession
+ videoOutput: output
+ camera: Camera {
+ id: camera
+ cameraDevice: mediaDevices.defaultVideoInput
+ }
+
+ Component.onCompleted: camera.start()
+ }
+
+ VideoOutput {
+ id: output
+ visible: true
+ }
+}
diff --git a/tests/manual/qml-minimal-player/CMakeLists.txt b/tests/manual/qml-minimal-player/CMakeLists.txt
new file mode 100644
index 000000000..be8f61861
--- /dev/null
+++ b/tests/manual/qml-minimal-player/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(sidepanel LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/qml-minimal-player")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Multimedia Qml Quick)
+
+qt_add_executable( qml-minimal-player WIN32 MACOSX_BUNDLE
+ qml-minimal-player.cpp
+)
+
+qt_add_qml_module( qml-minimal-player
+ URI QmlMinimalplayer
+ NO_RESOURCE_TARGET_PATH
+ QML_FILES
+ "qml-minimal-player.qml"
+)
+
+target_link_libraries( qml-minimal-player PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+install(TARGETS qml-minimal-player
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+set_target_properties( qml-minimal-player PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+)
diff --git a/tests/manual/qml-minimal-player/Info.plist.in b/tests/manual/qml-minimal-player/Info.plist.in
new file mode 100644
index 000000000..46a9ecf2d
--- /dev/null
+++ b/tests/manual/qml-minimal-player/Info.plist.in
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSCameraUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/manual/qml-minimal-player/qml-minimal-player.cpp b/tests/manual/qml-minimal-player/qml-minimal-player.cpp
new file mode 100644
index 000000000..f7714f016
--- /dev/null
+++ b/tests/manual/qml-minimal-player/qml-minimal-player.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl("qrc:/qml-minimal-player.qml"));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+
+ return app.exec();
+}
diff --git a/tests/manual/qml-minimal-player/qml-minimal-player.qml b/tests/manual/qml-minimal-player/qml-minimal-player.qml
new file mode 100644
index 000000000..4767d7e7a
--- /dev/null
+++ b/tests/manual/qml-minimal-player/qml-minimal-player.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+import QtQuick
+import QtQuick.Controls
+import QtMultimedia
+
+ApplicationWindow {
+ id: window
+ width: 800
+ height: 600
+ visible: true
+ title: qsTr("QmlMinimalPlayer")
+
+ MediaPlayer {
+ id: player
+ audioOutput: AudioOutput {
+ onMutedChanged: {
+ console.log("muted", player.audioOutput.muted)
+ }
+ }
+ videoOutput: output
+
+ onMediaStatusChanged: {
+ console.log("status", player.mediaStatus);
+
+ if (player.mediaStatus === MediaPlayer.LoadedMedia)
+ player.play()
+ }
+ }
+
+ Component.onCompleted: {
+ if (Qt.application.arguments.length > 1)
+ player.setSource(Qt.application.arguments[1])
+ else
+ console.log("Please specify a video source")
+ }
+
+ VideoOutput {
+ id: output
+ visible: true
+ }
+}
diff --git a/tests/manual/wasm/CMakeLists.txt b/tests/manual/wasm/CMakeLists.txt
new file mode 100644
index 000000000..1d3c623c4
--- /dev/null
+++ b/tests/manual/wasm/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(QT_FEATURE_widgets)
+ add_subdirectory(camera)
+endif()
diff --git a/tests/manual/wasm/camera/CMakeLists.txt b/tests/manual/wasm/camera/CMakeLists.txt
new file mode 100644
index 000000000..f63c60bbf
--- /dev/null
+++ b/tests/manual/wasm/camera/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Generated from camera-test.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(camera-test VERSION 1.0 LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+set(CMAKE_BUILD_TYPE Release)
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}")
+
+find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core)
+find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Multimedia MultimediaWidgets)
+find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS Widgets)
+
+qt_add_executable(camera-test WIN32 MACOSX_BUNDLE
+ main.cpp
+ mainwindow.cpp mainwindow.h mainwindow.ui
+)
+target_link_libraries(camera-test PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Multimedia
+ Qt::MultimediaWidgets
+ Qt::CorePrivate
+ Qt::Widgets
+)
+
+set(CMAKE_BUILD_TYPE Debug)
+# uncomment to enable asyncify
+# target_link_options(wasm-camera PUBLIC -sASYNCIFY -Os)
+
+install(TARGETS camera-test
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/wasm/camera/camera-test.pro b/tests/manual/wasm/camera/camera-test.pro
new file mode 100644
index 000000000..f13ba3596
--- /dev/null
+++ b/tests/manual/wasm/camera/camera-test.pro
@@ -0,0 +1,69 @@
+QT += core gui multimedia multimediawidgets
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++17 debug
+
+# uncomment this to use asyncify
+#wasm: QMAKE_LFLAGS += -s ASYNCIFY -Os
+
+# You can make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
+
+macos {
+ PRODUCT_NAME = $$TARGET
+ macx-xcode: PRODUCT_NAME = $${LITERAL_DOLLAR}{PRODUCT_NAME}
+ INFOPLIST = \
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" \
+ "<plist version=\"1.0\">" \
+ "<dict>" \
+ " <key>CFBundleIconFile</key>" \
+ " <string></string>" \
+ " <key>CFBundlePackageType</key>" \
+ " <string>APPL</string>" \
+ " <key>CFBundleGetInfoString</key>" \
+ " <string>Created by Qt/QMake</string>" \
+ " <key>CFBundleSignature</key>" \
+ " <string>????</string>" \
+ " <key>CFBundleExecutable</key>" \
+ " <string>$$TARGET</string>" \
+ " <key>CFBundleIdentifier</key>" \
+ " <string>com.digia.$${LITERAL_DOLLAR}{PRODUCT_NAME:rfc1034identifier}</string>" \
+ " <key>CFBundleDisplayName</key>" \
+ " <string>$$PRODUCT_NAME</string>" \
+ " <key>CFBundleName</key>" \
+ " <string>$$PRODUCT_NAME</string>" \
+ " <key>CFBundleShortVersionString</key>" \
+ " <string>1.0</string>" \
+ " <key>CFBundleVersion</key>" \
+ " <string>1.0</string>" \
+ " <key>NSPrincipalClass</key>" \
+ " <string>NSApplication</string>" \
+ " <key>NSCameraUsageDescription</key>" \
+ " <string>Qt Multimedia Example</string>" \
+ " <key>NSMicrophoneUsageDescription</key>" \
+ " <string>Qt Multimedia Example</string>" \
+ " <key>NOTE</key>" \
+ " <string>This file was generated by Qt/QMake.</string>" \
+ "</dict>" \
+ "</plist>"
+ write_file($$OUT_PWD/Info.plist, INFOPLIST)|error()
+ QMAKE_INFO_PLIST = $$OUT_PWD/Info.plist
+}
diff --git a/tests/manual/wasm/camera/main.cpp b/tests/manual/wasm/camera/main.cpp
new file mode 100644
index 000000000..8370ffb87
--- /dev/null
+++ b/tests/manual/wasm/camera/main.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mainwindow.h"
+
+#include <QApplication>
+#include <QLoggingCategory>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ QLoggingCategory::setFilterRules("*.debug=false\n"
+ "qt.multimedia.wasm.*=true");
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/tests/manual/wasm/camera/mainwindow.cpp b/tests/manual/wasm/camera/mainwindow.cpp
new file mode 100644
index 000000000..78c6a7584
--- /dev/null
+++ b/tests/manual/wasm/camera/mainwindow.cpp
@@ -0,0 +1,261 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include <QAudioInput>
+#include <QCamera>
+#include <QCameraDevice>
+#include <QGraphicsScene>
+#include <QGraphicsVideoItem>
+#include <QImageCapture>
+#include <QMediaCaptureSession>
+#include <QMediaDevices>
+#include <QMediaFormat>
+#include <QApplication>
+#include <QTimer>
+#include <QVideoWidget>
+#include <QLabel>
+#include <QFileDialog>
+#include <QScreen>
+#include <QMediaPlayer>
+
+#if QT_CONFIG(permissions)
+ #include <QPermission>
+#endif
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent),
+ ui(new Ui::MainWindow),
+ m_recorder(nullptr)
+{
+ ui->setupUi(this);
+ init();
+}
+
+MainWindow::~MainWindow()
+{
+ if (m_recorder)
+ delete m_recorder;
+ delete ui;
+}
+
+void MainWindow::init()
+{
+#if QT_CONFIG(permissions)
+ // camera
+ QCameraPermission cameraPermission;
+ switch (qApp->checkPermission(cameraPermission)) {
+ case Qt::PermissionStatus::Undetermined:
+ qApp->requestPermission(cameraPermission, this, &MainWindow::init);
+ return;
+ case Qt::PermissionStatus::Denied:
+ qWarning("Camera permission is not granted!");
+ return;
+ case Qt::PermissionStatus::Granted:
+ break;
+ }
+ // microphone
+ QMicrophonePermission microphonePermission;
+ switch (qApp->checkPermission(microphonePermission)) {
+ case Qt::PermissionStatus::Undetermined:
+ qApp->requestPermission(microphonePermission, this, &MainWindow::init);
+ return;
+ case Qt::PermissionStatus::Denied:
+ qWarning("Microphone permission is not granted!");
+ return;
+ case Qt::PermissionStatus::Granted:
+ break;
+ }
+#endif
+ m_captureSession = new QMediaCaptureSession(this);
+
+ m_mediaDevices = new QMediaDevices(this);
+ // wait until devices list is ready
+ connect(m_mediaDevices, &QMediaDevices::videoInputsChanged,
+ [this]() { doCamera(); });
+}
+
+void MainWindow::doCamera()
+{
+ m_audioInput.reset(new QAudioInput);
+ m_captureSession->setAudioInput(m_audioInput.get());
+ const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
+
+ ui->camerasComboBox->clear();
+ ui->camerasComboBox->setPlaceholderText("select camera");
+
+ for (const QCameraDevice &cameraDevice : cameras) {
+ if (ui->camerasComboBox->findText(cameraDevice.description()) == -1)
+ ui->camerasComboBox->addItem(cameraDevice.description(), cameraDevice.id());
+ }
+
+ if (cameras.count() == 0) {
+ qWarning() << "No camera found";
+ } else {
+
+ QGraphicsVideoItem *videoItem = new QGraphicsVideoItem();
+ QGraphicsScene *scene = new QGraphicsScene(this);
+ m_captureSession->setVideoOutput(videoItem); // sets videoSink
+
+ ui->graphicsView->setScene(scene);
+ ui->graphicsView->scene()->addItem(videoItem);
+ ui->graphicsView->show();
+ }
+}
+
+void MainWindow::on_startButton_clicked()
+{
+ m_camera.data()->start();
+}
+
+void MainWindow::on_stopButton_clicked()
+{
+ m_camera.data()->stop();
+}
+
+void MainWindow::on_captureButton_clicked()
+{
+ connect(m_camera.data(), &QCamera::errorOccurred,
+ [](QCamera::Error error, const QString &errorString) {
+ qWarning() << "Error occurred" << error << errorString;
+ });
+
+ QImageCapture *m_imageCapture = new QImageCapture(this);
+ connect(m_imageCapture, &QImageCapture::readyForCaptureChanged, [] (bool ready) {
+
+ qWarning() << "MainWindow::readyForCaptureChanged" << ready;
+ });
+
+ connect(m_imageCapture,
+ &QImageCapture::imageCaptured,
+ [] (int id, const QImage &preview) {
+ qWarning() << "MainWindow::imageCaptured" << id << preview;
+
+ });
+
+ connect(m_imageCapture, &QImageCapture::imageSaved,
+ [this] (int id, const QString &fileName) {
+ Q_UNUSED(id)
+ QFileInfo fi(fileName);
+ if (!fi.exists()) {
+ qWarning() << fileName << "Does not exist";
+ } else {
+ QDialog *dlg = new QDialog(this);
+ dlg->setWindowTitle(fi.fileName());
+ QHBoxLayout *l = new QHBoxLayout(dlg);
+ QLabel *label = new QLabel(this);
+ l->addWidget(label);
+ label->setPixmap(QPixmap(fileName));
+ dlg->show();
+ }
+
+ });
+ connect(m_imageCapture,
+ &QImageCapture::errorOccurred, []
+ (int id, QImageCapture::Error error, const QString &errorString) {
+ qWarning() << "MainWindow::errorOccurred" << id << error << errorString;
+ });
+
+ m_captureSession->setImageCapture(m_imageCapture);
+
+ // take photo
+ if (m_imageCapture->isReadyForCapture())
+ m_imageCapture->captureToFile(QStringLiteral("/home/web_user/image.png"));
+}
+
+void MainWindow::on_openButton_clicked()
+{
+ // open
+ QFileDialog *dialog = new QFileDialog(this);
+ dialog->setNameFilter(tr("All Files (*.*)"));
+ connect(dialog, &QFileDialog::fileSelected,
+ [this](const QString &file) {
+ qWarning() << "open this file" << file;
+ showFile(file);
+ });
+
+ dialog->show();
+}
+
+void MainWindow::on_camerasComboBox_textActivated(const QString &arg1)
+{
+ const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
+ for (const QCameraDevice &cameraDevice :cameras) {
+ if (arg1 == cameraDevice.description()) {
+ m_camera.reset(new QCamera(cameraDevice));
+ connect(m_captureSession, &QMediaCaptureSession::cameraChanged,
+ [this]() {
+ enableButtons(true);
+ });
+ m_captureSession->setCamera(m_camera.data());
+ break;
+ }
+ }
+}
+
+void MainWindow::on_recordButton_clicked()
+{
+ if (!isRecording) {
+ if (m_recorder)
+ delete m_recorder;
+ m_recorder = new QMediaRecorder();
+ connect(m_recorder, &QMediaRecorder::durationChanged,
+ [](qint64 duration) {
+ qWarning() << "MainWindow::durationChanged"
+ << duration;
+ });
+ m_captureSession->setRecorder(m_recorder);
+
+ m_recorder->setQuality(QMediaRecorder::HighQuality);
+ m_recorder->setOutputLocation(QUrl::fromLocalFile("test.mp4"));
+ m_recorder->record();
+ isRecording = true;
+ ui->recordButton->setText(QStringLiteral("Stop"));
+ } else {
+ m_recorder->stop();
+ isRecording = false;
+ m_recorder->deleteLater();
+ ui->recordButton->setText(QStringLiteral("Record"));
+ }
+}
+
+void MainWindow::enableButtons(bool ok)
+{
+ ui->captureButton->setEnabled(ok);
+ ui->startButton->setEnabled(ok);
+ ui->stopButton->setEnabled(ok);
+ ui->openButton->setEnabled(ok);
+ ui->recordButton->setEnabled(ok);
+}
+
+void MainWindow::showFile(const QString &fileName)
+{
+
+ const QSize screenGeometry = screen()->availableSize();
+ QFileInfo fi(fileName);
+ QDialog *dlg = new QDialog(this);
+ dlg->setWindowTitle(fi.fileName());
+ QHBoxLayout *layout = new QHBoxLayout(dlg);
+ QMediaPlayer *player = new QMediaPlayer(dlg);
+ connect(player, &QMediaPlayer::errorOccurred, [=] (QMediaPlayer::Error error, const QString &errorString) {
+ qWarning() << "MediaPlayer erro!:" << error << errorString;
+ });
+
+ QGraphicsVideoItem *m_videoItem = new QGraphicsVideoItem();
+ QSizeF dialogSize(screenGeometry.width() / 2, screenGeometry.height() / 2);
+ m_videoItem->setSize(dialogSize);
+ player->setVideoOutput(m_videoItem);
+ dlg->setGeometry(20, 20, dialogSize.width() + 40, dialogSize.height() + 40);
+
+ QGraphicsScene *scene = new QGraphicsScene(dlg);
+ QGraphicsView *graphicsView = new QGraphicsView(scene);
+ scene->addItem(m_videoItem);
+ layout->addWidget(graphicsView);
+
+ player->setSource(QUrl(fileName));
+
+ dlg->show();
+ player->play();
+}
diff --git a/tests/manual/wasm/camera/mainwindow.h b/tests/manual/wasm/camera/mainwindow.h
new file mode 100644
index 000000000..854c00935
--- /dev/null
+++ b/tests/manual/wasm/camera/mainwindow.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QImageCapture>
+#include <QMediaCaptureSession>
+#include <QGraphicsVideoItem>
+#include <QCamera>
+#include <QMediaDevices>
+#include <QMediaRecorder>
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+
+class QMediaCaptureSession;
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+ void init();
+
+private slots:
+ void doCamera();
+ void on_startButton_clicked();
+ void on_stopButton_clicked();
+ void on_captureButton_clicked();
+ void on_openButton_clicked();
+ void on_recordButton_clicked();
+ void on_camerasComboBox_textActivated(const QString &arg1);
+
+private:
+ Ui::MainWindow *ui;
+
+ void enableButtons(bool ok);
+ void showFile(const QString &filename);
+
+ QScopedPointer<QCamera> m_camera;
+ QMediaCaptureSession *m_captureSession;
+ QScopedPointer<QAudioInput> m_audioInput;
+ QMediaDevices *m_mediaDevices;
+ QMediaRecorder *m_recorder;
+ bool isRecording = false;
+};
+
+QT_END_NAMESPACE
+#endif // MAINWINDOW_H
diff --git a/tests/manual/wasm/camera/mainwindow.ui b/tests/manual/wasm/camera/mainwindow.ui
new file mode 100644
index 000000000..b5de38348
--- /dev/null
+++ b/tests/manual/wasm/camera/mainwindow.ui
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QComboBox" name="camerasComboBox">
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ <item>
+ <property name="text">
+ <string/>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QGraphicsView" name="graphicsView"/>
+ </item>
+ <item row="2" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="startButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>start camera</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="stopButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>stop camera</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QPushButton" name="captureButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>capture photo</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="recordButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>record</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="openButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>open</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>24</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/systemtests/audio_playback/sys_audio.qtt b/tests/systemtests/audio_playback/sys_audio.qtt
deleted file mode 100644
index 64629e8fc..000000000
--- a/tests/systemtests/audio_playback/sys_audio.qtt
+++ /dev/null
@@ -1,374 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
-
-testcase = {
-
-/* Notes
-Ensure various mp3, wav, ogg, oga, spx and flac audio files available for playback
-Ensure a valid m3u file referring to locations where indicated media is available on the device
-Ensure the device can ping destinations on the network (if applicable)
-Have an audio stream url available (e.g. http://202.6.74.107:8060/triplej.mp3 for example)
-Ensure access to Internet available to device either via 3G and WiFi
-*/
- initTestCase: function()
- {
- },
-
- play_an_audio_file_data: {
- mp3:[".mp3", "filename", "mpeg audio layer 3"],
- wav:[".wav", "filename", "waveform audio"],
- ogg:[".ogg", "filename", "container format"],
- vorbis:[".oga", "filename", "audio compression format"],
- speex:[".spx", "filename", "speech audio format"],
- flac:[".flac", "filename", "audio file format"]
- },
-
- play_an_audio_file: function(extension, filename, format)
- {
- // Test meta data
- testTitle = "Multimedia - Play Audio File";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify that various Audio files can be played.";
- testPreconditions = "Audio files in " + extension + " format are available on device. Launch the native Music player to populate the playlist before opening BGMPTest.";
- testGroups = "BAT, 5.0";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Verify that the playlist has populated the application | |
- | Select the desired "+filename+extension+" and press play | Verify that the " + format + " file is audible on device |
-
- "));
- },
-
- basic_player_controls_for_audio_data: {
- mp3:[".mp3", "filename", "mpeg audio layer 3"],
- wav:[".wav", "filename", "waveform audio"],
- ogg:[".ogg", "filename", "container format"],
- vorbis:[".oga", "filename", "audio compression format"],
- speex:[".spx", "filename", "speech audio format"],
- flac:[".flac", "filename", "audio file format"]
- },
-
- basic_player_controls_for_audio: function(extension, filename, format)
- {
- // Test meta data
- testTitle = "Multimedia - Audio Player Controls";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify basic API for controlling audio playback ";
- testPreconditions = "a test "+extension+" file is available on device";
- testGroups = "BAT, 5.0";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select the desired "+filename+extension+" in playlist and press [Play] | Verify that file plays properly from the start |
- | | Verify that the correct track details are displayed in the playlist |
- | Select [Pause] | Verify that file has paused |
- | Select [Play] | Verify that file continues to play properly from where previously paused. |
- | | Verify that the progress bar tracks the progression of the file playback |
- | Select [Next] control | Verify that next file in playlist is playing from start |
- | | Verify that the correct playlist title is highlighted and that the details are correct to reflect the selected audio track |
- | Select [Stop] control | Verify that file has stopped playing |
- | Select [Play] | Verify that file continues to play from start of file. |
- | With file playing, verify that UI volume control slider can change volume up and down | |
- | Select volume at 50% (or thereabout) | |
- | Select [Mute] | Verify that sound is muted while file is playing |
- | | Verify that [Mute] control is displaying the Muted icon |
- | Select [Mute] control again | Verify that sound has reverted back to level selected prior to muting |
- "));
- },
-
- hardware_volume_controls_for_audio_data: {
- mp3:[".mp3", "filename", "mpeg audio layer 3"],
- wav:[".wav", "filename", "waveform audio"],
- ogg:[".ogg", "filename", "container format"],
- vorbis:[".oga", "filename", "audio compression format"],
- speex:[".spx", "filename", "speech audio format"],
- flac:[".flac", "filename", "audio file format"]
- },
-
- hardware_volume_controls_for_audio: function(extension, filename, format)
- {
- // Test meta data
- testTitle = "Multimedia - Audio Player Controls";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify hardware volume control of audio playback ";
- testPreconditions = "a test "+extension+" file is available on device";
- testGroups = "BAT, 5.0";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select the desired "+filename+extension+" in playlist and press [Play] | Verify that file plays properly from the start |
- | Press the hardware volume keys to increase the volume to the maximum | Verify that the device now plays at maximum volume |
- | Using hardware volume keys, select volume at about 50% | Verify that the device is now playing at about 50% volume |
- | Using hardware keys, take volume down to 0% | Verify that sound is muted while file is playing |
- | Using hardware keys, increase volume | Verify that sound is once again playing from device |
- "));
- },
-
-
- basic_playlist_controls_for_audio_data: {
- mp3:[".mp3", "filename", "mpeg audio layer 3"],
- wav:[".wav", "filename", "waveform audio"],
- ogg:[".ogg", "filename", "container format"],
- vorbis:[".oga", "filename", "audio compression format"],
- speex:[".spx", "filename", "speech audio format"],
- flac:[".flac", "filename", "audio file format"]
- },
-
- basic_playlist_controls_for_audio: function(extension, filename, format)
- {
- // Test meta data
- testTitle = "Multimedia - Audio Player Controls";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify basic API for controlling playlist playback ";
- testPreconditions = "a test "+extension+" file is available on device";
- testGroups = "BAT, 5.0";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select 'Sequential' as the Play Mode | |
- | Select the desired "+filename+extension+" in playlist and press [Play] | Verify that file plays properly from the start |
- | | Verify that the correct track details are displayed in the playlist |
- | Select [Next] | Verify that the next file in the playlist is highlighted |
- | | Verify that the correct audio file is being played from the beginning of the track |
- | | Verify that there are no audible artifacts or undue lag during this change of track |
- | After some time (10-20 sec), select [Prev] icon | Verify that the previous file in the playlist is being played from start |
- | Let file play till end | Verify player continues playing the next file in the playlist window |
- | After some arbitrary time, Select [Stop] | |
- | Select [Next File] control | Verify that next file in playlist is highlighted |
- | | Verify that file is not automatically playing |
- | Select [Prev] control | Verify that previous file in playlist is highlighted |
- | Select file in playlist | Verify that file plays in player. |
- | Select number of files greater than can be displayed without scrolling in to playlist | Verify that list can be scrolled through |
- | Navigate to the last file in the playlist and select [Next] | Verify that no other track is played |
- | Select 'Loop' as the Play Mode | |
- | Select [Next] | Verify that the next song played is the first song in the playlist |
- | While first song is playing select [Prev] | Verify that the last song in the playlist is now playing |
- | Select [current Loop] from Play Mode | Verify that the same song now plays in a loop |
- | | Verify that selecting [Prev] or [Next] has no effect on the tune played |
- | Select [Current Only] in the Play Mode | Verify that only the selected song plays and stops at the end |
- | Select [Shuffle] | Verify that the playlist is now shuffled in a random fashion |
- | Select [Shuffle] again | Verify that the playlist is again shuffled in a random fashion |
- | Select [Reset] | Verify that the playlist is now back to its original order |
- "));
-
- },
-
- seek_controls_for_audio_data: {
- mp3:[".mp3", "filename", "mpeg audio layer 3"],
- wav:[".wav", "filename", "waveform audio"],
- ogg:[".ogg", "filename", "container format"],
- virbis:[".oga", "filename", "audio compression format"],
- speex:[".spx", "filename", "speech audio format"],
- flac:[".flac", "filename", "audio file format"]
- },
-
- seek_controls_for_audio: function(extension, filename, format)
- {
- // Test meta data
- testTitle = "Multimedia - Audio Seek Controls";
- testBinary = "AudioPlayer";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify FastForward and Rewind functionality of the API";
- testPreconditions = "a test "+extension+" file is available on device";
- testGroups = "BAT, 5.0";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select [Play] to play the file | |
- | Click on the [Move Forward] control | Verify that file playback has moved forward 5 seconds |
- | Select [Pause] | Verify that the file has paused the playback |
- | Click on the [Move Forward] control | Verify that the file has moved 5 seconds forward, but is still paused |
- | Select [Play] | Verify that file is now playing from new position |
- | Click on the [Move Backwards] control | Verify that file playback has moved back 5 seconds |
- | Select [Pause] | Verify that the file has paused the playback |
- | Click on the [Move Backwards] control | Verify that the file has moved 5 seconds backwards, but is still paused |
- | Select [Play] | Verify that file is now playing from new position |
- "));
- },
-
-
-
- basic_controls_for_streamed_audio_content: function()
- {
-
-//*Note* For this test you need a playlist of streaming media urls. Suggest: http://202.6.74.107:8060/triplej.mp3 ; http://www.abc.net.au/streaming/triplej.asx ; rtsp://media1.abc.net.au/broadcast/triplej.rm ; mms://media3.abc.net.au/triplej ; depending on your platform and backend support.
-
- // Test meta data
- testTitle = "Multimedia - Content Streaming";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify playback of streaming audio media";
- testPreconditions = "";
- testGroups = "BAT, 5.0";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | In player application, Select or Tap [Open] | |
- | In [Open File] navigate and highlight test (streaming) playlist file | |
- | Select or Tap on selected file to return to player UI | Verify selected file has populated playlist |
- | Highlight file in playlist by selecting or clicking it | |
- | Select [Play] | Verify that stream is playing on device |
- | Select [Pause] | Verify that stream is paused on device |
- | | Verify that the [Pause] button has changed to a [Play] button |
- | Select [Play] again | Verify that stream is playing on device |
- | Select [Stop] | |
- | Open local mp3 file in to play list and select it to play | Verify that the mp3 plays while the stream name is still present in the playlist |
- | Re-select the stream in the playlist | Verify that the stream starts playing again |
- | Select [Next File] | Verify that the player started playing the next file in the playlist |
- | Select [Previous File] | Verify that the original stream is playing again |
- | During stream playback, have headphones connected to device | Verify that the sound is now playing through the headphones |
- | Invoke a system notification on the device (such as an incoming SMS) | Verify that the device correctly transmits the audible system notification through the devices speakers and then returns to playing the stream through the headphones |
- "));
- },
-
-
- play_sound_effects: function()
- {
-
- // Test meta data
- testTitle = "Multimedia - SoundEffects Playback";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify playback of sound effects.";
- testPreconditions = "";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | Verify app launches normally |
- | play soundeffect | Verify that a sound effect is audible |
- | Close application | Verify that the application closes without issues |
- "));
- },
-
- change_volume_of_sound_effects: function()
- {
-
- // Test meta data
- testTitle = "Multimedia - SoundEffects Playback";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Change volume of sound effects.";
- testPreconditions = "";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | Verify app launches normally |
- | Set volume of device to maximum | Verify that sound effect now plays at maximum volume |
- | Set volume of device to about 50% volume | Verify that the sound effect now plays at half volume |
- | Set volume of device to minimum | Verify that there is now no audio from device when sound effect is played |
- | Close application | Verify that the application closes without issues |
- "));
- },
-
-
- play_sound_effects_over_compressed_audio: function()
- {
-
- // Test meta data
- testTitle = "Multimedia - SoundEffects Playback";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimedia/examples/player";
- testGoal = "Verify playback of sound effects over audio track.";
- testPreconditions = "player application to provide background playback";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch player, start playback of playlist | Audio should be heard from the device |
- | Swipe to background player | Audio should still be heard from player |
- | Launch " + testBinary + " | Verify app launches normally |
- | Touch red rectangle | Verify that a sound effect is audible together with the background track |
- | Touch blue rectangle | Verify that a sound effect is audible together with the background track |
- | Touch green rectangle | Verify that a sound effect is audible together with the background track |
- | Touch yellow rectangle | Verify that a sound effect is audible together with the background track |
- | Touch a combination of rectangles in quick succession | Verify that sound effects trigger on each touch and that the background track can still be heard |
- | Close application | Verify that the application closes without issues |
- | | Verify that player is still playing audio tracks |
- "));
- }
-}
diff --git a/tests/systemtests/audio_recording/sys_audio_recording.qtt b/tests/systemtests/audio_recording/sys_audio_recording.qtt
deleted file mode 100644
index 504e0c994..000000000
--- a/tests/systemtests/audio_recording/sys_audio_recording.qtt
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
-
-testcase = {
-
- initTestCase: function()
- {
- },
-
-
- record_an_audio_file: function(extension, filename, format)
- {
- // Test meta data
- testTitle = "Multimedia - Record Audio File";
- testBinary = "player";
- testSource = "$QTDIR/qtmultimediia/examples/audiorecorder";
- testGoal = "Verify that various Audio files can be recorded.";
- testPreconditions = "";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select Default for Input Device, Audio Codec, File Container and Sample rate | |
- | Select Constant Quality for Encoding mode | |
- | Select output file and hit Record | Verify that Audio Level is responding to audio input |
- | Navigate to created audio file and play | Verify that audio is of intended quality |
- | Close application | Verify application closes cleanly |
-
- "));
- }
-}
diff --git a/tests/systemtests/radio/sys_radio.qtt b/tests/systemtests/radio/sys_radio.qtt
deleted file mode 100644
index 81e911c2d..000000000
--- a/tests/systemtests/radio/sys_radio.qtt
+++ /dev/null
@@ -1,286 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
-
-testcase = {
-
-/* Notes
-Ensure radio reception is available in testing area
-Most tier 1 platforms require a radio module
-A device specific headset is required to be connected to device for radio testing
-*/
-
- initTestCase: function()
- {
- },
-
- play_a_radio_transmission: function()
- {
- // Test meta data
- testTitle = "Multimedia - Play Radio Transmission";
- testBinary = "radio";
- testSource ="qt5/qtmultimedia/examples/radio"
- testGoal = "Verify that radio stations can be played.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Device must have a suppported radio module.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | | If not first time running application on image, verify that you are presented with a list of previously scanned radio stations |
- | Select a radio station from the list | Verify that the station is properly selected |
- | Select the power icon next to the station name | Verify that audio from the radio station is now heard through the headphones |
- | Deselect the power icon next to the station name | Verify that audio from the radio station is no longer heard through the headphones |
- | Exit the radio application | Verify that the radio application closes cleanly |
- "));
- },
-
- change_a_radio_station: function()
- {
- // Test meta data
- testTitle = "Multimedia - Radio: Change radio station";
- testBinary = "radio";
- testSource ="qt5/qtmultimedia/examples/radio"
- testGoal = "Verify that radio station can be changed from station playlist.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select a radio station from the list | Verify that the station is heard through the headphones |
- | If in the visualization view, select the down icon to return to the station selection view | Verify that you are presented with the list of stations |
- | Select a different station | Verify that you are now listening to a different radio station |
- | Deselect the power icon next to the station name | Verify that audio from the radio station is no longer heard through the headphones |
- | Exit the radio application | Verify that the radio application closes cleanly |
- "));
- },
-
- manually_tune_radio_station: function()
- {
- // Test meta data
- testTitle = "Multimedia - Manually tune radio station";
- testBinary = "radio";
- testSource ="qt5/qtmultimedia/examples/radio"
- testGoal = "Verify that user can manually change radio station.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select a radio station from the list | Verify that the station is heard through the headphones |
- | Select the up icon to be presented to the visualization view | |
- | Select the Plus icon on the menu bar | Verify that you are presented with the frequency dial |
- | Note the current selected frequency | |
- | Select the dot indicator on the frequency dial, and move finger to right | Verify that the frequency on the indicator is now rising and that the audio has gone off the previous station |
- | Keep moving selector until a radio station is heard | Verify that the frequency of the selected station is higher than the originally selected station |
- | | Verify that the station is playing properly |
- | Select to save the selected radio station frequency | Verify that the station is saved in the radio station playlist |
- | Exit the radio application | Verify that the radio application closes cleanly |
- "));
- },
-
- scan_up_and_down: function()
- {
- // Test meta data
- testTitle = "Multimedia - Scan up and down the frequency";
- testBinary = "radio";
- testSource ="qt5/qtmultimedia/examples/radio"
- testGoal = "Verify that radio can scan up and down the FM frequency.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select a radio station from the list | Verify that the station is heard through the headphones |
- | Select the up icon to be presented to the visualization view | |
- | Select the Plus icon on the menu bar | Verify that you are presented with the frequency dial |
- | Note the current selected frequency | |
- | Select the Scan Up Frequency control | Verify that application has located a new station and that the frequency displayed is of the new station |
- | | Verify that the station is playing properly |
- | Select to save the selected radio station frequency | Verify that the station is saved in the radio station playlist |
- | Select the Scan Down Frequency control | Verify that application has located the original station and that the frequency displayed is of the original station |
- | | Verify that the station is playing properly |
- | Select to save the selected radio station frequency | Verify that the station is saved in the radio station playlist |
- | Exit the radio application | Verify that the radio application closes cleanly |
- "));
- },
-
- scan_for_multiple_radio_stations: function()
- {
- // Test meta data
- testTitle = "Multimedia - Radio: Scan for multiple radio station";
- testBinary = "radio";
- testSource ="qt5/qtmultimedia/examples/radio"
- testGoal = "Verify that radio can scan for multiple stations at once.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | On the menu, select Find new station | In the Radio Dialog Scanning view, observe the number of stations found |
- | Exit the radio application | Verify that the radio application closes cleanly |
- "));
- },
-
- save_radio_station_list: function()
- {
- // Test meta data
- testTitle = "Multimedia - Radio: Save station playlist";
- testBinary = "radio";
- testSource ="qt5/qtmultimedia/examples/radio"
- testGoal = "Verify that radio can save station playlist.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select to scan for multiple stations | Verify that multiple stations have been found |
- | Select to save station playlist | |
- | Close application | Verify that the application closes |
- | Reopen " + testBinary + " | Verify that the app launches normally |
- | Go to station playlist | Verify that the stations from the previous search are listed |
- | Select various stations from playlist | Verify that radio station play properly |
- | Close application | Verify that radio application closes properly |
- "));
- },
-
-
- radio_interrupted_by_system_notification: function()
- {
- // Test meta data
- testTitle = "Multimedia - Radio interrupted by System Notification";
- testBinary = "radio";
- testSource ="$QTDIR/qtmultimediakit/examples/Radio"
- testGoal = "Verify that radio can recover audio playback from various system notifications.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Locate a strong radio station signal by scanning up/down | |
- | While on a strong and audible radio signal, evoke a system notification on device (eg: alarm notification) | Verify that the radio has muted, and after the system notification has been delivered, the radio reverts to outputting the audio signal back through the headphones |
- | While on a strong and audible radio signal, call the device | Verify that the radio has been muted, and stays muted during the duration of the call, and resumes once the call has ended |
- | Close application | Verify that radio application closes properly |
- "));
- },
-
- radio_volume_control: function()
- {
- // Test meta data
- testTitle = "Multimedia - Radio Volume Control";
- testBinary = "radio";
- testGoal = "Verify that the radio volume can be controlled via volume controls.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Locate a strong radio station signal by scanning up or down the frequency | |
- | While on a strong and audible radio signal, move volume slider to the right | Verify that the audio volume of the radio station is amplified |
- | Move volume slider to the left | Verify that the audio volume is lowered |
- | Move the volume slider all the way to the left | Verify that the sound is now completely muted |
- | Return the volume to a value above 50% and click the Mute/unmute command | Verify that the audio changes from being muted to unmuted and back |
- "));
- },
-
- display_radio_metadata: function()
- {
- // Test meta data
- testTitle = "Multimedia - Display Radio Meta data";
- testBinary = "radio";
- testGoal = "Verify that the radio API can display properly formatted meta data.";
- testPreconditions = "1. Radio reception should be available in the test area.<br>2. Wired headphones act as an antenna to the device and must be connected.";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Locate a strong radio station signal by scanning up or down the frequency | Verify that the Frequency field is populated with the correct frequency for the given radio station |
- | | Verify that the Volume field is displaying the proper volume % |
- | Click on the Mute/Unmute command | Verify that Muted field changes from 'false' to 'true' and back |
- | | If applicable, confirm that the Station Name field is properly displayed |
- | | If applicable, confirm that the Station Id field is properly displayed |
- | | If applicable, confirm that the Program Type field is properly displayed |
- | | If applicable, confirm that the Radio Text field is properly displayed |
- "));
- },
-}
diff --git a/tests/systemtests/still_camera/sys_camera.qtt b/tests/systemtests/still_camera/sys_camera.qtt
deleted file mode 100644
index e2d885f44..000000000
--- a/tests/systemtests/still_camera/sys_camera.qtt
+++ /dev/null
@@ -1,162 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
-
-testcase = {
-
-/* Notes
-*/
- initTestCase: function()
- {
- },
-
- take_a_photo: function()
- {
- // Test meta data
- testTitle = "Multimedia - Still Camera";
- testBinary = "camera";
- testSource = "qt5/qtmultimedia/examples/camera"
- testGoal = "Verify that a photo can be taken with the camera.";
- testPreconditions = "None";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testTitle + " | App launches normally |
- | If device has lens cover, make sure it is open | |
- | Select Image tab to put camera in still mode | Verify the intended scene is reproduced in the preview pane/viewfinder |
- | Select Capture Photo | Verify that image is shown on screen for preview |
- | | Verify that a new file is in the Images folder and accessible with the image viewer |
- | Select given image | Verify that it is a true representation of the intended screen |
- | | Verify the image has no unintended artifacts and noise and is properly formatted |
- "));
- },
-
- change_camera_settings: function()
- {
- // Test meta data
- testTitle = "Multimedia - Still Camera, Change Settings";
- testBinary = "camera";
- testSource = "qt5/qtmultimedia/examples/camera"
- testGoal = "Verify that the camera can change its Still Camera settings successfully.";
- testPreconditions = None";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | If device has lens cover, make sure it is open | |
- | Select the primary camera device from Menu/Devices | Verify the viewfinder is displaying the scene from the main camera device |
- | Select Capture Photo | Verify that a photo was taken and that a preview image is shown on screen |
- | Select the secondary camera device from Menu/Devices | Verify the viewfinder is displaying the scene from the secondary camera device |
- | Select Capture Photo | Verify that a photo was taken from the secondary camera device and that a preview image is shown on screen |
- | Change Exposure Compensation on the slider in the main UI | Verify that the change in value affects the picture quality in expected fashion |
- | Select Settings/File/Settings | Verify that you have an option to change Image Resolution, Image Format and Quality |
- | Change Image Resolution to another supported resolution | Verify that you can take stills with various resolutions |
- | Select Flash always on from the settings menu | Verify that when photo is taken, the flash is always triggered |
- | Select No Flash on from the menu | Verify that despite the lack of natural light, the flash will not trigger when taking photos |
- | Change Image Format to another supported format | Verify that you can take stills with various Image Formats |
- | Select Settings/Device/Secondary Device | Verify that you can see the view from the Front Facing Camera on the viewfinder |
- | | Verify that you can take still images from the Front Facing Camera |
- | Select Settings/File/Exit | Verify that the application has now closed |
-
- "));
- },
-
- take_a_video: function()
- {
- // Test meta data
- testTitle = "Multimedia - Video Camera, Take Video";
- testBinary = "camera";
- testSource = "qt5/qtmultimedia/examples/camera"
- testGoal = "Verify that the camera can capture and save an audio/video file.";
- testPreconditions = "None";
- testGroups = "BAT, 1.2";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select Video icon to put camera in video mode | Verify the intended scene is reproduced in the preview/viewfinder |
- | Select Record Video | Verify that video is shown on screen for preview |
- | Select Stop | Verify that the recording has now stopped |
- | | Verify that the video file is available in the camera preview pane |
- | Select given video | Verify that it is a true representation of the intended screen |
- | | Verify the image has no unintended artifacts and noise and is properly formatted |
- "));
- },
-
- change_video_settings: function()
- {
- // Test meta data
- testApplication = "Multimedia - Video Camera, Change Video Settings";
- testBinary = "camera";
- testSource = "qt5/qtmultimedia/examples/camera"
- testGoal = "Verify that the camera can change its Video settings successfully.";
- testPreconditions = "None";
- testGroups = "BAT";
-
- // Test steps
- prompt(twiki("---+++ " + testTitle + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | If device has lens cover, make sure it is open | |
- | Select Video tab to put camera in video mode | Verify the intended scene is reproduced in the preview/viewfinder |
- | In the Menu Bar, select Settings/Devices | Verify that you can select Primary and Secondary Camera on Device |
- | Select Secondary Camera | Verify that devise is now showing video stream from Front Facing camera |
- | Select Settings/File/Settings | Verify that you now have the option to select Audio Codecs, Resolution Sample Rate, Framerate, Quality, Video Codecs and Container Format |
- | Change Audio Codecs to another supported Codecs | Verify that camera can record |
- | Change Resolution to another supported Resolution | Verify that camera can record |
- | Change Sample Rate to another supported Sample Rate | Verify that camera can record |
- | Change Framerate to another supported Framerate | Verify that camera can record |
- | Change Quality | Verify that camera can record |
- | Change Video Codecs to another supported Video Codecs | Verify that camera can record |
- | Change Container Format | Verify that camera can record |
- | Change Quality | Verify that camera can record |
- "));
- },
-}
diff --git a/tests/systemtests/video_playback/sys_video.qtt b/tests/systemtests/video_playback/sys_video.qtt
deleted file mode 100644
index 0cf375937..000000000
--- a/tests/systemtests/video_playback/sys_video.qtt
+++ /dev/null
@@ -1,180 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
-
-testcase = {
-
-/* Notes
-Ensure 2 test .mp4 files are available on device
-Ensure the device can ping destinations on the network (if applicable)
-Have a video stream url available (e.g. http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4)
-Ensure access to Internet available to device
-Ensure an active SIM card is available on the device. As some video streaming tests are carrier specific, it is recommended in Australia to have access to Testra, Optus and Vodafone SIM's.
-*/
- initTestCase: function()
- {
- },
-
- play_a_video_file_data: {
- mp4:[".mp4", "filename", "mpeg video layer 4"]
- },
-
- play_a_video_file: function(extension, filename, format)
- {
- // Test meta data
- testApplication = "Multimedia - Play Video File";
- testBinary = "player";
- testGoal = "Verify that local, networked and carrier streamed video files can be played. ";
- testPreconditions = "1. A test "+extension+" file is available on device.<br>2. Internet access is enabled on the device.<br>3. Operator SIM cards are available to the device";
- testGroups = "BAT";
-
- // Test steps
- prompt(twiki("---+++ " + testApplication + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select [Open] | |
- | In [Open File] select the "+filename+extension+" file to return to player UI | |
- | Select [Play] to play the file | Verify selected file has populated playlist |
- | Highlight file in playlist by clicking on it | |
- | Select [Play] | Verify that .MP4 file is playing on device |
- "));
- },
-
- basic_controls_for_video_data: {
- mp4:[".mp4", "filename", "mpeg video layer 4"]
- },
-
- basic_controls_for_video: function(extension, filename, format)
- {
- // Test meta data
- testApplication = "Multimedia - Video Controls";
- testBinary = "player";
- testGoal = "Verify the API for basic video playback functionality";
- testPreconditions = "a test "+extension+" file is available on device.";
- testGroups = "BAT";
-
- // Test steps
- prompt(twiki("---+++ " + testApplication + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | Select [Open] | |
- | In [Open File] select the "+filename+extension+" file to return to player UI | |
- | Select [Play] to play the file | |
- | Select [Pause] | Verify that file has paused |
- | | Verify that the [Pause] icon has changed to a [Play] icon |
- | Select [Play] | Verify that the [Play] icon has changed to a [Pause] icon |
- | | Verify that file continues to play from where previously paused. |
- | Select [Next File] | Verify that next file in playlist is playing from start |
- | After some time (10-20 sec) Select [Beginning of File] control | Verify that current file is being played from start |
- | Let arbitrary time pass, then Select [Beginning of File] control twice in quick succession.| Verify that previous file in playlist is playing from start |
- | Select [Stop] | Verify that file has stopped playing |
- | Select [Play] | Verify that file continues to play from start of file. |
- | Let file play till end | Verify player stops at end of file. |
- | Start playing file. | |
- | After arbitrary time, Select [Stop] | |
- | Select [Next File] | Verify that next file in playlist is highlighted |
- | | Verify that file is not automatically playing |
- | Select [Beginning of File] | Verify that previous file in playlist is highlighted |
- | Select file in playlist | Verify that file plays in player. |
- | Select number of files greater than can be displayed without scrolling in to playlist | Verify that list can be scrolled through |
- | With file playing, verify that hardware keys can change volume up and down | |
- | With file playing, verify that UI volume control slider can change volume up and down | |
- | Select volume at 50% (or thereabout) | |
- | Select [Mute] control | Verify that sound is muted while file is playing |
- | | Verify that [Mute] control is displaying the Muted icon |
- | Select [Mute] control again | Verify that sound has reverted back to level selected prior to muting |
- | Drag positional slider to right, then release | Verify that player continues to play file at later part of file |
- | Drag positional slider to left, then release | Verify that player continues to play file at earlier part of file |
- | Start playing file | |
- | Select [FullScreen] control | Verify that video is now playing in Fullscreen mode |
- | When at end of current file | Verify that next file in playlist is being played |
- | When at last file in playlist and at end of file | Verify that fullscreen mode is exited and user returned to player interface and that [FullScreen] is no longer selected. |
- "));
- },
-
- seek_controls_for_video: function()
- {
- // Test meta data
- testApplication = "Multimedia - Video Seek";
- testBinary = "player";
- testGoal = "Verify the API for Fast Forward/Rewind functionality.";
- testPreconditions = "Video files are available for testing on the device.";
- testGroups = "BAT";
-
- // Test steps
- prompt(twiki("---+++ " + testApplication + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | While playing a video file, Select or Tap on Forward control | Verify that playback has moved five seconds forward |
- | Select or Tap Back control | Verify that playback has moved 5 seconds back |
- "));
- },
-
- basic_controls_for_streamed_content: function()
- {
-
-//*Note* For this test you need a playlist of streaming media urls. Suggest: http://202.6.74.107:8060/triplej.mp3 ; http://www.abc.net.au/streaming/triplej.asx ; rtsp://media1.abc.net.au/broadcast/triplej.rm ; mms://media3.abc.net.au/triplej ; depending on your platform and backend support. A stream that I have found that works is: http://chaos.troll.no/~tavestbo/webkit/mediaelement/transformers640.ogg
-
- // Test meta data
- testApplication = "Multimedia - Content Streaming";
- testBinary = "Video player";
- testGoal = "Verify various forms of video streaming.";
- testPreconditions = "For now you need to eddit the .qml file and hardcode the following URI: http://chaos.troll.no/~tavestbo/webkit/mediaelement/transformers640.ogg";
- testGroups = "BAT";
-
- // Test steps
- prompt(twiki("---+++ " + testApplication + "<br><br>
- *Goal:* " + testGoal + "<br>
- *Pre-Requisites:* " + testPreconditions + "<br>
- *Tested Binary:* " + testBinary + "<br>
-
- | *Step* | *Verification* |
- | Launch " + testBinary + " | App launches normally |
- | In Video player application, Select or Tap Play | Verify that the video stream plays in the application |
- | Select [Pause] | Verify that stream is paused on device |
- | | Verify that the [Pause] button has changed to a [Play] button |
- | Select [Play] again | Verify that stream is playing on device |
- | Select [Stop] | |
- | During stream playback, have headphones connected to device | Verify that the sound is now playing through the headphones |
- | Invoke a system notification on the device (such as an incoming SMS) | Verify that the device correctly transmits the audible system notification through the devices speakers and then returns to playing the stream through the headphones |
- "));
- },
-}