summaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto')
-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
627 files changed, 14585 insertions, 3847 deletions
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();