summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/FindFFmpeg.cmake67
-rw-r--r--cmake/FindVAAPI.cmake34
-rw-r--r--dependencies.yaml8
-rw-r--r--examples/multimedia/audiodevices/audiodevices.cpp7
-rw-r--r--examples/multimedia/camera/android/AndroidManifest.xml32
-rw-r--r--examples/multimedia/camera/camera.cpp19
-rw-r--r--examples/multimedia/camera/metadatadialog.cpp2
-rw-r--r--examples/multimedia/player/player.cpp14
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/multimedia/QtAudioDeviceManager.java79
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/multimedia/QtVideoDeviceManager.java18
-rw-r--r--src/multimedia/CMakeLists.txt19
-rw-r--r--src/multimedia/alsa/qalsaaudiodevice.cpp52
-rw-r--r--src/multimedia/alsa/qalsaaudiodevice_p.h6
-rw-r--r--src/multimedia/android/qandroidmediadevices.cpp8
-rw-r--r--src/multimedia/audio/qaudiobufferinput.cpp157
-rw-r--r--src/multimedia/audio/qaudiobufferinput.h44
-rw-r--r--src/multimedia/camera/qcamera.cpp23
-rw-r--r--src/multimedia/camera/qcamera.h1
-rw-r--r--src/multimedia/camera/qcamera_p.h6
-rw-r--r--src/multimedia/camera/qcameradevice.cpp10
-rw-r--r--src/multimedia/doc/src/qtmultimedia-index.qdoc24
-rw-r--r--src/multimedia/platform/qgstreamer_platformspecificinterface.cpp27
-rw-r--r--src/multimedia/platform/qgstreamer_platformspecificinterface_p.h42
-rw-r--r--src/multimedia/platform/qplatformaudiobufferinput.cpp10
-rw-r--r--src/multimedia/platform/qplatformaudiobufferinput_p.h56
-rw-r--r--src/multimedia/platform/qplatformcamera.cpp7
-rw-r--r--src/multimedia/platform/qplatformcamera_p.h10
-rw-r--r--src/multimedia/platform/qplatformmediacapture.cpp11
-rw-r--r--src/multimedia/platform/qplatformmediacapture_p.h13
-rw-r--r--src/multimedia/platform/qplatformmediaintegration_p.h8
-rw-r--r--src/multimedia/platform/qplatformmediaplayer.cpp16
-rw-r--r--src/multimedia/platform/qplatformmediaplayer_p.h27
-rw-r--r--src/multimedia/platform/qplatformsurfacecapture_p.h3
-rw-r--r--src/multimedia/platform/qplatformvideoframeinput.cpp10
-rw-r--r--src/multimedia/platform/qplatformvideoframeinput_p.h55
-rw-r--r--src/multimedia/platform/qplatformvideosource_p.h5
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp6
-rw-r--r--src/multimedia/playback/qmediaplayer_p.h5
-rw-r--r--src/multimedia/qmediaframeinput.cpp43
-rw-r--r--src/multimedia/qmediaframeinput_p.h74
-rw-r--r--src/multimedia/qmediainputencoderinterface_p.h31
-rw-r--r--src/multimedia/qmediametadata.cpp26
-rw-r--r--src/multimedia/qmediametadata.h6
-rw-r--r--src/multimedia/qsymbolsresolveutils.cpp79
-rw-r--r--src/multimedia/qsymbolsresolveutils_p.h178
-rw-r--r--src/multimedia/recording/qmediacapturesession.cpp249
-rw-r--r--src/multimedia/recording/qmediacapturesession.h18
-rw-r--r--src/multimedia/recording/qmediacapturesession_p.h15
-rw-r--r--src/multimedia/recording/qscreencapture-limitations.qdocinc15
-rw-r--r--src/multimedia/recording/qvideoframeinput.cpp151
-rw-r--r--src/multimedia/recording/qvideoframeinput.h44
-rw-r--r--src/multimedia/video/qabstractvideobuffer_p.h2
-rw-r--r--src/multimedia/video/qimagevideobuffer.cpp5
-rw-r--r--src/multimedia/video/qimagevideobuffer_p.h2
-rw-r--r--src/multimedia/video/qmemoryvideobuffer.cpp16
-rw-r--r--src/multimedia/video/qmemoryvideobuffer_p.h3
-rw-r--r--src/multimedia/video/qvideoframe.cpp31
-rw-r--r--src/multimedia/video/qvideoframe.h3
-rw-r--r--src/multimedia/video/qvideoframe_p.h1
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper.cpp70
-rw-r--r--src/multimedia/video/qvideoframeconverter.cpp6
-rw-r--r--src/multimedia/video/qvideoframeconverter_p.h4
-rw-r--r--src/plugins/multimedia/android/common/qandroidvideooutput.cpp4
-rw-r--r--src/plugins/multimedia/darwin/avfvideobuffer_p.h1
-rw-r--r--src/plugins/multimedia/darwin/mediaplayer/avfmediaplayer.mm40
-rw-r--r--src/plugins/multimedia/ffmpeg/CMakeLists.txt98
-rw-r--r--src/plugins/multimedia/ffmpeg/cmake/QtAddFFmpegStubs.cmake199
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp25
-rw-r--r--src/plugins/multimedia/ffmpeg/qandroidcamera.cpp26
-rw-r--r--src/plugins/multimedia/ffmpeg/qandroidcameraframe.cpp34
-rw-r--r--src/plugins/multimedia/ffmpeg/qavfsamplebufferdelegate.mm2
-rw-r--r--src/plugins/multimedia/ffmpeg/qcgwindowcapture.mm2
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpeg.cpp49
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpeg_p.h31
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegaudioinput_p.h7
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpeghwaccel.cpp13
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpeghwaccel_vaapi.cpp2
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession.cpp36
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession_p.h18
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegmediaintegration.cpp3
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegmediarecorder.cpp23
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegopensslsymbols.cpp185
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp5
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolve_p.h37
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils.cpp103
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils_p.h142
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegvideobuffer.cpp33
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegvideobuffer_p.h1
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegwindowcapture_uwp.cpp2
-rw-r--r--src/plugins/multimedia/ffmpeg/qopenglvideobuffer.cpp5
-rw-r--r--src/plugins/multimedia/ffmpeg/qopenglvideobuffer_p.h1
-rw-r--r--src/plugins/multimedia/ffmpeg/qv4l2camera.cpp6
-rw-r--r--src/plugins/multimedia/ffmpeg/qwindowscamera.cpp2
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder.cpp76
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder_p.h17
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread.cpp8
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread_p.h37
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer.cpp165
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer_p.h77
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegmuxer.cpp1
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp159
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h45
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils.cpp63
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils_p.h70
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp93
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h23
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoderutils.cpp5
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder.cpp50
-rw-r--r--src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder_p.h4
-rw-r--r--src/plugins/multimedia/ffmpeg/symbolstubs/openssl3.ver7
-rw-r--r--src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-crypto.cpp6
-rw-r--r--src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-ssl.cpp300
-rw-r--r--src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-drm.cpp14
-rw-r--r--src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-x11.cpp14
-rw-r--r--src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va.cpp (renamed from src/plugins/multimedia/ffmpeg/qffmpegvaapisymbols.cpp)129
-rw-r--r--src/plugins/multimedia/ffmpeg/symbolstubs/va.ver7
-rw-r--r--src/plugins/multimedia/gstreamer/CMakeLists.txt2
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp93
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h11
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp25
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h18
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp376
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h124
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp366
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h120
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgst.cpp193
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgst_debug.cpp67
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgst_debug_p.h6
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgst_handle_types_p.h5
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgst_p.h66
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstappsource.cpp2
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstpipeline.cpp130
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstpipeline_p.h17
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreameraudioinput.cpp103
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreameraudioinput_p.h4
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput.cpp123
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput_p.h5
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer.cpp284
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer_p.h30
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamermessage_p.h2
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamervideooutput.cpp33
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamervideooutput_p.h3
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamervideosink.cpp45
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamervideosink_p.h18
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstutils.cpp2
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstvideobuffer.cpp6
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstvideobuffer_p.h2
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp314
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstvideorenderersink_p.h75
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera.cpp104
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera_p.h33
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture.cpp307
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture_p.h15
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture.cpp122
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture_p.h10
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder.cpp30
-rw-r--r--src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder_p.h2
-rw-r--r--src/plugins/multimedia/gstreamer/qgstreamerformatinfo.cpp16
-rw-r--r--src/plugins/multimedia/gstreamer/qgstreamerformatinfo_p.h8
-rw-r--r--src/plugins/multimedia/gstreamer/qgstreamerintegration.cpp141
-rw-r--r--src/plugins/multimedia/gstreamer/qgstreamerintegration_p.h22
-rw-r--r--src/plugins/multimedia/gstreamer/qgstreamervideodevices.cpp10
-rw-r--r--src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer.cpp5
-rw-r--r--src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer_p.h1
-rw-r--r--src/plugins/multimedia/qnx/mediaplayer/qqnxmediaplayer.cpp13
-rw-r--r--src/plugins/multimedia/wasm/mediacapture/qwasmcamera.cpp4
-rw-r--r--src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp2
-rw-r--r--tests/auto/integration/CMakeLists.txt1
-rw-r--r--tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp66
-rw-r--r--tests/auto/integration/qmediaplayerbackend/testdata/h264_avc1_yuv420p10le_tv_bt2020.movbin0 -> 20164 bytes
-rw-r--r--tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp118
-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/shared/mediabackendutils.h6
-rw-r--r--tests/auto/shared/qscopedenvironmentvariable.h29
-rw-r--r--tests/auto/unit/mockbackend/qmockcamera.cpp6
-rw-r--r--tests/auto/unit/mockbackend/qmockcamera.h3
-rw-r--r--tests/auto/unit/mockbackend/qmockvideobuffer.h2
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp21
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h2
-rw-r--r--tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp9
-rw-r--r--tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp24
-rw-r--r--tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp57
-rw-r--r--tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt4
-rw-r--r--tests/auto/unit/multimedia/qmediacapture_gstreamer/tst_qmediacapture_gstreamer.cpp117
-rw-r--r--tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp4
-rw-r--r--tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp64
-rw-r--r--tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp133
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT709_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_AdobeRgb_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_AdobeRgb_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT2020_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT2020_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT601_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT601_Video.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT709_Full.png)bin41243 -> 41243 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video_cpu.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT709_Video.png)bin41243 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_AdobeRgb_Full.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_AdobeRgb_Video.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT2020_Full.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT2020_Video.png)bin40978 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT601_Full.png)bin40854 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT601_Video.png)bin40904 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT709_Full.png)bin40945 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT709_Video.png)bin40959 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_AdobeRgb_Full.png)bin40934 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_AdobeRgb_Video.png)bin40934 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_BT2020_Full.png)bin40912 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_BT2020_Video.png)bin41004 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_BT601_Full.png)bin40870 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_BT601_Video.png)bin40924 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_BT709_Full.png)bin40966 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc2_BT709_Video.png)bin40975 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_AdobeRgb_Full.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_AdobeRgb_Video.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT2020_Full.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT2020_Video.png)bin40978 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT601_Full.png)bin40854 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT601_Video.png)bin40904 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT709_Full.png)bin40945 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT709_Video.png)bin40959 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_AdobeRgb_Full.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_AdobeRgb_Video.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_BT2020_Full.png)bin40912 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_BT2020_Video.png)bin40987 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_BT601_Full.png)bin40877 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_BT601_Video.png)bin40918 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_BT709_Full.png)bin40967 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc4_BT709_Video.png)bin40961 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_AdobeRgb_Full.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_AdobeRgb_Video.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT2020_Full.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT2020_Video.png)bin40978 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT601_Full.png)bin40854 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT601_Video.png)bin40904 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT709_Full.png)bin40945 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT709_Video.png)bin40959 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_AdobeRgb_Full.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_AdobeRgb_Video.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT2020_Full.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT2020_Video.png)bin40978 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT601_Full.png)bin40854 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT601_Video.png)bin40904 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT709_Full.png)bin40945 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT709_Video.png)bin40959 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_AdobeRgb_Full.png)bin40927 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_AdobeRgb_Video.png)bin40927 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_BT2020_Full.png)bin40923 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_BT2020_Video.png)bin40964 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_BT601_Full.png)bin40897 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_BT601_Video.png)bin40914 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_BT709_Full.png)bin40936 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p010_BT709_Video.png)bin40991 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_AdobeRgb_Full.png)bin40913 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_AdobeRgb_Video.png)bin40913 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_BT2020_Full.png)bin40969 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_BT2020_Video.png)bin40951 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_BT601_Full.png)bin40860 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_BT601_Video.png)bin40946 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_BT709_Full.png)bin40942 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_p016_BT709_Video.png)bin40966 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_AdobeRgb_Full.png)bin39859 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_AdobeRgb_Video.png)bin39859 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_BT2020_Full.png)bin39864 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_BT2020_Video.png)bin39919 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_BT601_Full.png)bin39789 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_BT601_Video.png)bin39890 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_BT709_Full.png)bin39879 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_uyvy_BT709_Video.png)bin39951 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_AdobeRgb_Full.png)bin25240 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_AdobeRgb_Video.png)bin25240 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_BT2020_Full.png)bin25544 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_BT2020_Video.png)bin24030 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_BT601_Full.png)bin25557 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_BT601_Video.png)bin23884 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_BT709_Full.png)bin25557 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y16_BT709_Video.png)bin24021 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_AdobeRgb_Full.png)bin25364 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_AdobeRgb_Video.png)bin25364 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_BT2020_Full.png)bin25430 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_BT2020_Video.png)bin23981 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_BT601_Full.png)bin25497 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_BT601_Video.png)bin23904 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_BT709_Full.png)bin25497 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_y8_BT709_Video.png)bin23979 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_AdobeRgb_Full.png)bin40919 -> 40919 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_adobergb_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_AdobeRgb_Video.png)bin40919 -> 40919 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_BT2020_Full.png)bin40952 -> 40952 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt2020_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_BT2020_Video.png)bin40967 -> 40967 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_BT601_Full.png)bin40881 -> 40881 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt601_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_BT601_Video.png)bin40962 -> 40962 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_BT709_Full.png)bin40954 -> 40954 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_bt709_video.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p10_BT709_Video.png)bin40987 -> 40987 bytes
-rw-r--r--tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_full.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_AdobeRgb_Full.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_AdobeRgb_Video.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT2020_Full.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT2020_Video.png)bin40978 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT601_Full.png)bin40854 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT601_Video.png)bin40904 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT709_Full.png)bin40945 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT709_Video.png)bin40959 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_AdobeRgb_Full.png)bin41163 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_AdobeRgb_Video.png)bin41163 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT2020_Full.png)bin41160 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT2020_Video.png)bin41199 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT601_Full.png)bin41000 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT601_Video.png)bin41177 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT709_Full.png)bin41183 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT709_Video.png)bin41209 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_AdobeRgb_Full.png)bin39859 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_AdobeRgb_Video.png)bin39859 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_BT2020_Full.png)bin39864 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_BT2020_Video.png)bin39919 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_BT601_Full.png)bin39789 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_BT601_Video.png)bin39890 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_BT709_Full.png)bin39879 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuyv_BT709_Video.png)bin39951 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_AdobeRgb_Full.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_AdobeRgb_Video.png)bin40898 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_BT2020_Full.png)bin40908 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_BT2020_Video.png)bin40978 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_BT601_Full.png)bin40854 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_BT601_Video.png)bin40904 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_BT709_Full.png)bin40945 -> 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.png (renamed from tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yv12_BT709_Video.png)bin40959 -> 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.cpp131
-rw-r--r--tests/manual/CMakeLists.txt4
-rw-r--r--tests/manual/gstreamer-custom-camera/CMakeLists.txt36
-rw-r--r--tests/manual/gstreamer-custom-camera/Info.plist.in46
-rw-r--r--tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp50
628 files changed, 5679 insertions, 3476 deletions
diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake
index 86be24dd7..ecf9b07cb 100644
--- a/cmake/FindFFmpeg.cmake
+++ b/cmake/FindFFmpeg.cmake
@@ -201,6 +201,7 @@ endmacro()
# Clear the previously cached variables, because they are recomputed every time
# the Find script is included.
unset(FFMPEG_SHARED_LIBRARIES CACHE)
+unset(FFMPEG_STUBS CACHE)
# Check for components.
foreach (_component ${FFmpeg_FIND_COMPONENTS})
@@ -225,33 +226,34 @@ foreach (_component ${FFmpeg_FIND_COMPONENTS})
endif()
endforeach()
-if (NOT FFMPEG_SHARED_COMPONENTS AND (ANDROID OR LINUX))
- set(ENABLE_DYNAMIC_RESOLVE_OPENSSL_SYMBOLS TRUE CACHE INTERNAL "")
-endif()
-set(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS ${LINUX} CACHE INTERNAL "")
+function(qt_internal_multimedia_try_add_dynamic_resolve_dependency _component dep)
+ set(dynamic_resolve_added FALSE PARENT_SCOPE)
-function(__try_add_dynamic_resolve_dependency dep added)
- set(added TRUE PARENT_SCOPE)
+ if (NOT ANDROID AND NOT LINUX)
+ return()
+ endif()
- if(ENABLE_DYNAMIC_RESOLVE_OPENSSL_SYMBOLS AND
- (${dep} STREQUAL "ssl" OR ${dep} STREQUAL "crypto"))
- set(DYNAMIC_RESOLVE_OPENSSL_SYMBOLS TRUE CACHE INTERNAL "")
- elseif(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS AND ${dep} STREQUAL "va")
- set(DYNAMIC_RESOLVE_VAAPI_SYMBOLS TRUE CACHE INTERNAL "")
- elseif(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS AND ${dep} STREQUAL "va-drm")
- set(DYNAMIC_RESOLVE_VA_DRM_SYMBOLS TRUE CACHE INTERNAL "")
- elseif(ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS AND ${dep} STREQUAL "va-x11")
- set(DYNAMIC_RESOLVE_VA_X11_SYMBOLS TRUE CACHE INTERNAL "")
- else()
- set(added FALSE PARENT_SCOPE)
+ set(supported_stubs "ssl|crypto|va|va-drm|va-x11")
+ if(${_component}_SHARED_LIBRARIES)
+ set(stub_prefix "Qt${PROJECT_VERSION_MAJOR}FFmpegStub-")
+ if (${dep} MATCHES "^${stub_prefix}(${supported_stubs})$")
+ string(REPLACE "${stub_prefix}" "" dep "${dep}")
+ set(FFMPEG_STUBS ${FFMPEG_STUBS} ${dep} CACHE INTERNAL "")
+
+ set(dynamic_resolve_added TRUE PARENT_SCOPE)
+ endif()
+ elseif (${dep} MATCHES "^(${supported_stubs})$")
+ set(FFMPEG_STUBS ${FFMPEG_STUBS} ${dep} CACHE INTERNAL "")
+ set(dynamic_resolve_added TRUE PARENT_SCOPE)
endif()
endfunction()
# Function parses package config file to find the static library dependencies
# and adds them to the target library.
-function(__ffmpeg_internal_set_dependencies lib)
- set(PC_FILE ${FFMPEG_DIR}/lib/pkgconfig/lib${lib}.pc)
+function(__ffmpeg_internal_set_dependencies _component)
+ string(TOLOWER ${_component} lib)
+ set(PC_FILE ${${_component}_LIBRARY_DIR}/pkgconfig/lib${lib}.pc)
if(EXISTS ${PC_FILE})
file(READ ${PC_FILE} pcfile)
@@ -270,18 +272,22 @@ function(__ffmpeg_internal_set_dependencies lib)
foreach(dependency ${deps_no_suffix})
string(REGEX REPLACE ${prefix_l} "" dependency ${dependency})
if(NOT ${lib} STREQUAL ${dependency})
- __try_add_dynamic_resolve_dependency(${dependency} added)
- if(NOT added)
+ qt_internal_multimedia_try_add_dynamic_resolve_dependency(${_component} ${dependency})
+ if(NOT dynamic_resolve_added AND NOT ${_component}_SHARED_LIBRARIES)
target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency})
endif()
endif()
endforeach()
- list(APPEND deps_lib_suffix ${libs_dependency_lib} ${libs_private_dependency_lib})
- foreach(dependency ${deps_lib_suffix})
- string(REGEX REPLACE ${suffix_lib} "" dependency ${dependency})
- target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency})
- endforeach()
+ if(NOT ${_component}_SHARED_LIBRARIES)
+ list(APPEND deps_lib_suffix ${libs_dependency_lib} ${libs_private_dependency_lib})
+ foreach(dependency ${deps_lib_suffix})
+ string(REGEX REPLACE ${suffix_lib} "" dependency ${dependency})
+ target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency})
+ endforeach()
+ endif()
+ else()
+ message(WARNING "FFmpeg pc file ${PC_FILE} is not found")
endif()
endfunction()
@@ -302,9 +308,8 @@ endfunction()
INTERFACE_LINK_LIBRARIES "${${_component}_LIBRARY_NAME}"
INTERFACE_LINK_DIRECTORIES "${${_component}_LIBRARY_DIR}"
)
- if(NOT ${_component}_SHARED_LIBRARIES)
- __ffmpeg_internal_set_dependencies(${_lowerComponent})
- endif()
+
+ __ffmpeg_internal_set_dependencies(${_component})
target_link_libraries(FFmpeg::${_lowerComponent} INTERFACE "${${_component}_LIBRARY_NAME}")
if (UNIX AND NOT APPLE)
target_link_options(FFmpeg::${_lowerComponent} INTERFACE "-Wl,--exclude-libs=lib${_lowerComponent}")
@@ -317,13 +322,17 @@ endfunction()
list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES FFMPEG_LIBRARY_DIRS)
list(REMOVE_DUPLICATES FFMPEG_SHARED_LIBRARIES)
+ list(REMOVE_DUPLICATES FFMPEG_STUBS)
message(STATUS "FFmpeg shared libs: ${FFMPEG_SHARED_LIBRARIES}")
+ message(STATUS "FFmpeg stubs: ${FFMPEG_STUBS}")
# cache the vars.
set(FFMPEG_SHARED_LIBRARIES ${FFMPEG_SHARED_LIBRARIES} CACHE STRING "The FFmpeg dynamic libraries." FORCE)
+ set(FFMPEG_STUBS ${FFMPEG_STUBS} CACHE STRING "The FFmpeg stubs." FORCE)
mark_as_advanced(FFMPEG_SHARED_LIBRARIES)
+ mark_as_advanced(FFMPEG_STUBS)
# endif ()
list(LENGTH FFMPEG_LIBRARY_DIRS DIRS_COUNT)
diff --git a/cmake/FindVAAPI.cmake b/cmake/FindVAAPI.cmake
index a3ea6cd58..b1170dc8e 100644
--- a/cmake/FindVAAPI.cmake
+++ b/cmake/FindVAAPI.cmake
@@ -4,13 +4,40 @@
find_package(PkgConfig QUIET)
+function(qt_internal_multimedia_set_va_outputs component include_dir lib_path)
+ if ("${component}" STREQUAL "VA")
+ set(VAAPI_INCLUDE_DIR "${include_dir}" CACHE INTERNAL "")
+ get_filename_component(lib_realpath "${lib_path}" REALPATH)
+
+ string(REGEX MATCH "[0-9]+(\\.[0-9]+)*$" VAAPI_SUFFIX "${lib_realpath}")
+ set(VAAPI_SUFFIX "${VAAPI_SUFFIX}" CACHE INTERNAL "")
+
+ mark_as_advanced(VAAPI_SUFFIX VAAPI_INCLUDE_DIR)
+ endif()
+endfunction()
+
function(find_component component prefix header library)
if(NOT TARGET VAAPI::${component})
string(TOUPPER ${component} upper)
- pkg_check_modules(PC_VAAPI_${upper} ${prefix} IMPORTED_TARGET)
+ pkg_search_module(PC_VAAPI_${upper} ${prefix} IMPORTED_TARGET)
if(TARGET PkgConfig::PC_VAAPI_${upper})
add_library(VAAPI::${component} INTERFACE IMPORTED)
target_link_libraries(VAAPI::${component} INTERFACE PkgConfig::PC_VAAPI_${upper})
+
+ if (NOT PC_VAAPI_${upper}_LINK_LIBRARIES)
+ get_target_property(PC_VAAPI_${upper}_LINK_LIBRARIES PkgConfig::PC_VAAPI_${upper} INTERFACE_LINK_LIBRARIES)
+ message(STATUS "PC_VAAPI_${upper}_LINK_LIBRARIES is not defined by PkgConfig; "
+ "Get the value from target properties: ${PC_VAAPI_${upper}_LINK_LIBRARIES}")
+ endif()
+
+ foreach (lib_path ${PC_VAAPI_${upper}_LINK_LIBRARIES})
+ get_filename_component(lib_name "${lib_path}" NAME_WLE)
+ if (${lib_name} STREQUAL ${prefix})
+ qt_internal_multimedia_set_va_outputs(${component}
+ "${PC_VAAPI_${upper}_INCLUDEDIR}" "${lib_path}")
+ break()
+ endif()
+ endforeach()
else()
find_path(VAAPI_${component}_INCLUDE_DIR
NAMES ${header}
@@ -25,6 +52,9 @@ function(find_component component prefix header library)
target_link_libraries(VAAPI::${component} INTERFACE ${VAAPI_${component}_LIBRARY})
endif()
mark_as_advanced(VAAPI_${component}_INCLUDE_DIR VAAPI_${component}_LIBRARY)
+
+ qt_internal_multimedia_set_va_outputs(${component}
+ "${VAAPI_${component}_INCLUDE_DIR}" "${VAAPI_${component}_LIBRARY}")
endif()
endif()
@@ -48,6 +78,8 @@ find_package_handle_standard_args(VAAPI
REQUIRED_VARS
VAAPI_VA_FOUND
VAAPI_DRM_FOUND
+ VAAPI_INCLUDE_DIR
+ VAAPI_SUFFIX
HANDLE_COMPONENTS
)
diff --git a/dependencies.yaml b/dependencies.yaml
index bc05ecd3e..cd640a712 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,13 +1,13 @@
dependencies:
../qtbase:
- ref: 4641945e45206508b44678011bb83da7722bad62
+ ref: f1c6c66985d1ceda16b0f74e91f36b0df44daf58
required: true
../qtdeclarative:
- ref: 828b823938395d4d43f9b7a1b7f53f10a4a6b99b
+ ref: 6083d39de9c003ffbb4b32fd8d5c9941479f3ad0
required: false
../qtquick3d:
- ref: 7a03b8412f81b3f152d12e71d107ed7c5288f880
+ ref: f7258496bf2cf25ef511d70ab41384ee3d6152c3
required: false
../qtshadertools:
- ref: 2eced24fc6550f2845f5d6de33100e7c27207008
+ ref: 776398835c8f366a3366c1a64456e3b1480d3d13
required: true
diff --git a/examples/multimedia/audiodevices/audiodevices.cpp b/examples/multimedia/audiodevices/audiodevices.cpp
index 30f52e0c9..d211189fd 100644
--- a/examples/multimedia/audiodevices/audiodevices.cpp
+++ b/examples/multimedia/audiodevices/audiodevices.cpp
@@ -70,7 +70,6 @@ void AudioTest::init()
}
#endif
m_devices->videoInputs();
- qDebug() << "<<<<<<<<<<<<<<<<<<";
QMediaFormat().supportedFileFormats(QMediaFormat::Encode);
connect(testButton, &QPushButton::clicked, this, &AudioTest::test);
connect(modeBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::modeChanged);
@@ -172,19 +171,19 @@ void AudioTest::populateTable()
allFormatsTable->setRowCount(row + 1);
QTableWidgetItem *sampleTypeItem = new QTableWidgetItem(toString(sampleFormat));
- allFormatsTable->setItem(row, 2, sampleTypeItem);
+ allFormatsTable->setItem(row, 0, sampleTypeItem);
QTableWidgetItem *sampleRateItem =
new QTableWidgetItem(QStringLiteral("%1 - %2")
.arg(m_deviceInfo.minimumSampleRate())
.arg(m_deviceInfo.maximumSampleRate()));
- allFormatsTable->setItem(row, 0, sampleRateItem);
+ allFormatsTable->setItem(row, 1, sampleRateItem);
QTableWidgetItem *channelsItem =
new QTableWidgetItem(QStringLiteral("%1 - %2")
.arg(m_deviceInfo.minimumChannelCount())
.arg(m_deviceInfo.maximumChannelCount()));
- allFormatsTable->setItem(row, 1, channelsItem);
+ allFormatsTable->setItem(row, 2, channelsItem);
++row;
}
diff --git a/examples/multimedia/camera/android/AndroidManifest.xml b/examples/multimedia/camera/android/AndroidManifest.xml
index 4af2fe92f..9f77579b4 100644
--- a/examples/multimedia/camera/android/AndroidManifest.xml
+++ b/examples/multimedia/camera/android/AndroidManifest.xml
@@ -4,12 +4,7 @@
android:installLocation="auto"
android:versionCode="-- %%INSERT_VERSION_CODE%% --"
android:versionName="-- %%INSERT_VERSION_NAME%% --">
- <!-- The comment below will be replaced with dependencies permissions upon deployment.
- Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
-
- <!-- The comment below will be replaced with dependencies permissions upon deployment.
- Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->
<supports-screens
@@ -28,7 +23,6 @@
<activity
android:name="org.qtproject.qt.android.bindings.QtActivity"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
- android:label="-- %%INSERT_APP_NAME%% --"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:exported="true">
@@ -36,36 +30,10 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
- <!-- Application arguments -->
-
- <meta-data
- android:name="android.app.arguments"
- android:value="-- %%INSERT_APP_ARGUMENTS%% --" />
- <!-- Application arguments -->
<meta-data
android:name="android.app.lib_name"
android:value="-- %%INSERT_APP_LIB_NAME%% --" />
- <!-- Background running -->
- <!-- Warning: changing this value to true may cause unexpected crashes if the
- application still try to draw after
- "applicationStateChanged(Qt::ApplicationSuspended)" signal is sent! -->
- <meta-data
- android:name="android.app.background_running"
- android:value="false" />
- <!-- Background running -->
-
- <!-- extract android style -->
- <!-- available android:values :
- * default - In most cases this will be the same as "full", but it can also be
- * something else if needed, e.g., for compatibility reasons
- * full - useful QWidget & Quick Controls 1 apps
- * minimal - useful for Quick Controls 2 apps, it is much faster than "full"
- * none - useful for apps that don't use any of the above Qt modules -->
- <meta-data
- android:name="android.app.extract_android_style"
- android:value="minimal" />
- <!-- extract android style -->
</activity>
</application>
</manifest>
diff --git a/examples/multimedia/camera/camera.cpp b/examples/multimedia/camera/camera.cpp
index bc24b1b89..c5aa19e2d 100644
--- a/examples/multimedia/camera/camera.cpp
+++ b/examples/multimedia/camera/camera.cpp
@@ -391,17 +391,26 @@ void Camera::saveMetaData()
for (int i = 0; i < QMediaMetaData::NumMetaData; i++) {
QString val = m_metaDataDialog->m_metaDataFields[i]->text();
if (!val.isEmpty()) {
- auto key = static_cast<QMediaMetaData::Key>(i);
- if (i == QMediaMetaData::CoverArtImage) {
+ const auto key = static_cast<QMediaMetaData::Key>(i);
+ switch (key) {
+ case QMediaMetaData::CoverArtImage: {
QImage coverArt(val);
data.insert(key, coverArt);
- } else if (i == QMediaMetaData::ThumbnailImage) {
+ break;
+ }
+ case QMediaMetaData::ThumbnailImage: {
QImage thumbnail(val);
data.insert(key, thumbnail);
- } else if (i == QMediaMetaData::Date) {
+ break;
+ }
+ case QMediaMetaData::Date: {
QDateTime date = QDateTime::fromString(val);
data.insert(key, date);
- } else {
+ break;
+ }
+ case QMediaMetaData::HasHdrContent:
+ break;
+ default:
data.insert(key, val);
}
}
diff --git a/examples/multimedia/camera/metadatadialog.cpp b/examples/multimedia/camera/metadatadialog.cpp
index b2147d868..8213baa6f 100644
--- a/examples/multimedia/camera/metadatadialog.cpp
+++ b/examples/multimedia/camera/metadatadialog.cpp
@@ -65,6 +65,8 @@ MetaDataDialog::MetaDataDialog(QWidget *parent) : QDialog(parent)
metaDataLayout->addRow(label, layout);
}
break;
+ case QMediaMetaData::HasHdrContent:
+ break; // Read-only
default:
metaDataLayout->addRow(label, lineEdit);
break;
diff --git a/examples/multimedia/player/player.cpp b/examples/multimedia/player/player.cpp
index c674554e8..f5590b0e6 100644
--- a/examples/multimedia/player/player.cpp
+++ b/examples/multimedia/player/player.cpp
@@ -301,6 +301,20 @@ void Player::metaDataChanged()
m_metaDataFields[i]->setDisabled(false);
m_metaDataLabels[i]->setDisabled(false);
}
+
+ const QList<QMediaMetaData> tracks = m_player->videoTracks();
+ const int currentVideoTrack = m_player->activeVideoTrack();
+ if (currentVideoTrack >= 0 && currentVideoTrack < tracks.size()) {
+ const QMediaMetaData track = tracks.value(currentVideoTrack);
+ for (const QMediaMetaData::Key &key : track.keys()) {
+ if (QLineEdit *field = qobject_cast<QLineEdit *>(m_metaDataFields[key])) {
+ QString stringValue = track.stringValue(key);
+ field->setText(stringValue);
+ }
+ m_metaDataFields[key]->setDisabled(true);
+ m_metaDataLabels[key]->setDisabled(true);
+ }
+ }
#endif
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAudioDeviceManager.java b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAudioDeviceManager.java
index 3bc589de6..2b6fcc2dc 100644
--- a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAudioDeviceManager.java
+++ b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtAudioDeviceManager.java
@@ -4,20 +4,16 @@
package org.qtproject.qt.android.multimedia;
import java.util.ArrayList;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
+import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
public class QtAudioDeviceManager
@@ -25,10 +21,12 @@ public class QtAudioDeviceManager
private static final String TAG = "QtAudioDeviceManager";
static private AudioManager m_audioManager = null;
static private final AudioDevicesReceiver m_audioDevicesReceiver = new AudioDevicesReceiver();
+ static private Handler handler = new Handler(Looper.getMainLooper());
static private AudioRecord m_recorder = null;
static private AudioTrack m_streamPlayer = null;
static private Thread m_streamingThread = null;
static private boolean m_isStreaming = false;
+ static private boolean m_useSpeaker = false;
static private final int m_sampleRate = 8000;
static private final int m_channels = AudioFormat.CHANNEL_CONFIGURATION_MONO;
static private final int m_audioFormat = AudioFormat.ENCODING_PCM_16BIT;
@@ -37,36 +35,37 @@ public class QtAudioDeviceManager
public static native void onAudioInputDevicesUpdated();
public static native void onAudioOutputDevicesUpdated();
- static private class AudioDevicesReceiver extends BroadcastReceiver
- {
+ static private void updateDeviceList() {
+ onAudioInputDevicesUpdated();
+ onAudioOutputDevicesUpdated();
+ if (m_useSpeaker) {
+ final AudioDeviceInfo[] audioDevices =
+ m_audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ setAudioOutput(getModeForSpeaker(audioDevices), false, true);
+ }
+ }
+
+ private static class AudioDevicesReceiver extends AudioDeviceCallback {
+ @Override
+ public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+ updateDeviceList();
+ }
+
@Override
- public void onReceive(Context context, Intent intent) {
- onAudioInputDevicesUpdated();
- onAudioOutputDevicesUpdated();
+ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+ updateDeviceList();
}
}
- public static void registerAudioHeadsetStateReceiver(Context context)
+
+ public static void registerAudioHeadsetStateReceiver()
{
- IntentFilter audioDevicesFilter = new IntentFilter();
- audioDevicesFilter.addAction(AudioManager.ACTION_HEADSET_PLUG);
- audioDevicesFilter.addAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
- audioDevicesFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
- audioDevicesFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
- audioDevicesFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
- audioDevicesFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- audioDevicesFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- audioDevicesFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- audioDevicesFilter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
- audioDevicesFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
- audioDevicesFilter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
-
- context.registerReceiver(m_audioDevicesReceiver, audioDevicesFilter);
+ m_audioManager.registerAudioDeviceCallback(m_audioDevicesReceiver, handler);
}
- public static void unregisterAudioHeadsetStateReceiver(Context context)
+ public static void unregisterAudioHeadsetStateReceiver()
{
- context.unregisterReceiver(m_audioDevicesReceiver);
+ m_audioManager.unregisterAudioDeviceCallback(m_audioDevicesReceiver);
}
static public void setContext(Context context)
@@ -226,8 +225,27 @@ public class QtAudioDeviceManager
return ret;
}
+ private static int getModeForSpeaker(AudioDeviceInfo[] audioDevices)
+ {
+ // If we want to force device to use speaker when Bluetooth or Wiread headset is connected,
+ // we need to use MODE_IN_COMMUNICATION. Otherwise the MODE_NORMAL can be used.
+ for (AudioDeviceInfo deviceInfo : audioDevices) {
+ switch (deviceInfo.getType()) {
+ case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
+ case AudioDeviceInfo.TYPE_BLUETOOTH_SCO:
+ case AudioDeviceInfo.TYPE_WIRED_HEADSET:
+ case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
+ return AudioManager.MODE_IN_COMMUNICATION;
+ default: break;
+ }
+ }
+ return AudioManager.MODE_NORMAL;
+ }
+
+
private static boolean setAudioOutput(int id)
{
+ m_useSpeaker = false;
final AudioDeviceInfo[] audioDevices =
m_audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
for (AudioDeviceInfo deviceInfo : audioDevices) {
@@ -239,7 +257,8 @@ public class QtAudioDeviceManager
setAudioOutput(AudioManager.MODE_IN_COMMUNICATION, true, false);
return true;
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
- setAudioOutput(AudioManager.MODE_IN_COMMUNICATION, false, true);
+ m_useSpeaker = true;
+ setAudioOutput(getModeForSpeaker(audioDevices), false, true);
return true;
case AudioDeviceInfo.TYPE_WIRED_HEADSET:
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
diff --git a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtVideoDeviceManager.java b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtVideoDeviceManager.java
index 3339bddc9..2e11e62a2 100644
--- a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtVideoDeviceManager.java
+++ b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtVideoDeviceManager.java
@@ -13,6 +13,7 @@ import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.MediaCodecList;
import android.media.MediaCodecInfo;
+import android.os.Build;
import android.util.Range;
import android.util.Size;
import android.util.Log;
@@ -219,6 +220,23 @@ public class QtVideoDeviceManager {
return supportedFlashModesList.toArray(ret);
}
+ static public boolean isEmulator()
+ {
+ return ((Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
+ || Build.FINGERPRINT.startsWith("generic")
+ || Build.FINGERPRINT.startsWith("unknown")
+ || Build.HARDWARE.contains("goldfish")
+ || Build.HARDWARE.contains("ranchu")
+ || Build.MODEL.contains("google_sdk")
+ || Build.MODEL.contains("Emulator")
+ || Build.MODEL.contains("Android SDK built for x86")
+ || Build.MANUFACTURER.contains("Genymotion")
+ || Build.PRODUCT.contains("sdk")
+ || Build.PRODUCT.contains("vbox86p")
+ || Build.PRODUCT.contains("emulator")
+ || Build.PRODUCT.contains("simulator"));
+ }
+
public boolean isTorchModeSupported(String cameraId) {
boolean ret = false;
final CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
diff --git a/src/multimedia/CMakeLists.txt b/src/multimedia/CMakeLists.txt
index 8c58545b5..7939ecef9 100644
--- a/src/multimedia/CMakeLists.txt
+++ b/src/multimedia/CMakeLists.txt
@@ -23,6 +23,7 @@ qt_internal_add_module(Multimedia
audio/qaudiodecoder.cpp audio/qaudiodecoder.h audio/qaudiodecoder_p.h
audio/qaudiodevice.cpp audio/qaudiodevice.h audio/qaudiodevice_p.h
audio/qaudioinput.cpp audio/qaudioinput.h
+ audio/qaudiobufferinput.cpp audio/qaudiobufferinput.h
audio/qaudiooutput.cpp audio/qaudiooutput.h
audio/qaudioformat.cpp audio/qaudioformat.h
audio/qaudiohelpers.cpp audio/qaudiohelpers_p.h
@@ -38,25 +39,28 @@ qt_internal_add_module(Multimedia
camera/qcameradevice.cpp camera/qcameradevice.h camera/qcameradevice_p.h
camera/qimagecapture.cpp camera/qimagecapture.h
compat/removed_api.cpp
+ platform/qgstreamer_platformspecificinterface.cpp platform/qgstreamer_platformspecificinterface_p.h
platform/qplatformaudiodecoder.cpp platform/qplatformaudiodecoder_p.h
platform/qplatformaudioinput_p.h
platform/qplatformaudiooutput_p.h
platform/qplatformaudioresampler_p.h
platform/qplatformcamera.cpp platform/qplatformcamera_p.h
- platform/qplatformvideosource.cpp platform/qplatformvideosource_p.h
- platform/qplatformsurfacecapture.cpp platform/qplatformsurfacecapture_p.h
+ platform/qplatformcapturablewindows_p.h
platform/qplatformimagecapture.cpp platform/qplatformimagecapture_p.h
platform/qplatformmediacapture.cpp platform/qplatformmediacapture_p.h
platform/qplatformmediadevices.cpp platform/qplatformmediadevices_p.h
- platform/qplatformmediarecorder.cpp platform/qplatformmediarecorder_p.h
platform/qplatformmediaformatinfo.cpp platform/qplatformmediaformatinfo_p.h
platform/qplatformmediaintegration.cpp platform/qplatformmediaintegration_p.h
platform/qplatformmediaplayer.cpp platform/qplatformmediaplayer_p.h
platform/qplatformmediaplugin.cpp platform/qplatformmediaplugin_p.h
+ platform/qplatformmediarecorder.cpp platform/qplatformmediarecorder_p.h
+ platform/qplatformsurfacecapture.cpp platform/qplatformsurfacecapture_p.h
platform/qplatformvideodevices.cpp platform/qplatformvideodevices_p.h
platform/qplatformvideosink.cpp platform/qplatformvideosink_p.h
+ platform/qplatformvideosource.cpp platform/qplatformvideosource_p.h
+ platform/qplatformvideoframeinput.cpp platform/qplatformvideoframeinput_p.h
+ platform/qplatformaudiobufferinput.cpp platform/qplatformaudiobufferinput_p.h
playback/qmediaplayer.cpp playback/qmediaplayer.h playback/qmediaplayer_p.h
- platform/qplatformcapturablewindows_p.h
qmediadevices.cpp qmediadevices.h
qmediaenumdebug.h
qmediaformat.cpp qmediaformat.h
@@ -64,14 +68,17 @@ qt_internal_add_module(Multimedia
qmediastoragelocation.cpp qmediastoragelocation_p.h
qmediatimerange.cpp qmediatimerange.h
qmultimediautils.cpp qmultimediautils_p.h
+ qmediaframeinput.cpp qmediaframeinput_p.h
qmaybe_p.h
qtmultimediaglobal.h qtmultimediaglobal_p.h
qerrorinfo_p.h
+ qmediainputencoderinterface_p.h
recording/qmediacapturesession.cpp recording/qmediacapturesession.h recording/qmediacapturesession_p.h
recording/qmediarecorder.cpp recording/qmediarecorder.h recording/qmediarecorder_p.h
recording/qscreencapture.cpp recording/qscreencapture.h
recording/qwindowcapture.cpp recording/qwindowcapture.h
recording/qcapturablewindow.cpp recording/qcapturablewindow.h recording/qcapturablewindow_p.h
+ recording/qvideoframeinput.cpp recording/qvideoframeinput.h
video/qabstractvideobuffer.cpp video/qabstractvideobuffer_p.h
video/qmemoryvideobuffer.cpp video/qmemoryvideobuffer_p.h
video/qimagevideobuffer.cpp video/qimagevideobuffer_p.h
@@ -107,6 +114,10 @@ qt_internal_add_module(Multimedia
GENERATE_CPP_EXPORTS
)
+qt_internal_extend_target(Multimedia
+ CONDITION LINUX OR ANDROID
+ SOURCES qsymbolsresolveutils.cpp qsymbolsresolveutils_p.h)
+
qt_internal_add_simd_part(Multimedia SIMD sse2
SOURCES
video/qvideoframeconversionhelper_sse2.cpp
diff --git a/src/multimedia/alsa/qalsaaudiodevice.cpp b/src/multimedia/alsa/qalsaaudiodevice.cpp
index f5d4a2209..893375270 100644
--- a/src/multimedia/alsa/qalsaaudiodevice.cpp
+++ b/src/multimedia/alsa/qalsaaudiodevice.cpp
@@ -37,55 +37,35 @@ QAlsaAudioDeviceInfo::QAlsaAudioDeviceInfo(const QByteArray &dev, const QString
minimumSampleRate = 8000;
maximumSampleRate = 48000;
- supportedSampleFormats << QAudioFormat::UInt8 << QAudioFormat::Int16 << QAudioFormat::Int32 << QAudioFormat::Float;
+ supportedSampleFormats = {
+ QAudioFormat::UInt8,
+ QAudioFormat::Int16,
+ QAudioFormat::Int32,
+ QAudioFormat::Float,
+ };
preferredFormat.setChannelCount(mode == QAudioDevice::Input ? 1 : 2);
preferredFormat.setSampleFormat(QAudioFormat::Float);
preferredFormat.setSampleRate(48000);
}
-QAlsaAudioDeviceInfo::~QAlsaAudioDeviceInfo()
-{
-}
+QAlsaAudioDeviceInfo::~QAlsaAudioDeviceInfo() = default;
void QAlsaAudioDeviceInfo::checkSurround()
{
+ if (mode != QAudioDevice::Output)
+ return;
+
surround40 = false;
surround51 = false;
surround71 = false;
- void **hints, **n;
- char *name, *descr, *io;
-
- if(snd_device_name_hint(-1, "pcm", &hints) < 0)
- return;
-
- n = hints;
-
- while (*n != NULL) {
- name = snd_device_name_get_hint(*n, "NAME");
- descr = snd_device_name_get_hint(*n, "DESC");
- io = snd_device_name_get_hint(*n, "IOID");
- if((name != NULL) && (descr != NULL)) {
- QString deviceName = QLatin1String(name);
- if (mode == QAudioDevice::Output) {
- if(deviceName.contains(QLatin1String("surround40")))
- surround40 = true;
- if(deviceName.contains(QLatin1String("surround51")))
- surround51 = true;
- if(deviceName.contains(QLatin1String("surround71")))
- surround71 = true;
- }
- }
- if(name != NULL)
- free(name);
- if(descr != NULL)
- free(descr);
- if(io != NULL)
- free(io);
- ++n;
- }
- snd_device_name_free_hint(hints);
+ if (id.startsWith(QLatin1String("surround40")))
+ surround40 = true;
+ if (id.startsWith(QLatin1String("surround51")))
+ surround51 = true;
+ if (id.startsWith(QLatin1String("surround71")))
+ surround71 = true;
}
QT_END_NAMESPACE
diff --git a/src/multimedia/alsa/qalsaaudiodevice_p.h b/src/multimedia/alsa/qalsaaudiodevice_p.h
index f82ea4f5a..dcbc9e692 100644
--- a/src/multimedia/alsa/qalsaaudiodevice_p.h
+++ b/src/multimedia/alsa/qalsaaudiodevice_p.h
@@ -38,9 +38,9 @@ public:
private:
void checkSurround();
- bool surround40;
- bool surround51;
- bool surround71;
+ bool surround40{};
+ bool surround51{};
+ bool surround71{};
};
QT_END_NAMESPACE
diff --git a/src/multimedia/android/qandroidmediadevices.cpp b/src/multimedia/android/qandroidmediadevices.cpp
index 55533621c..7688da079 100644
--- a/src/multimedia/android/qandroidmediadevices.cpp
+++ b/src/multimedia/android/qandroidmediadevices.cpp
@@ -23,9 +23,7 @@ Q_DECLARE_JNI_CLASS(QtAudioDeviceManager,
QAndroidMediaDevices::QAndroidMediaDevices() : QPlatformMediaDevices()
{
- QtJniTypes::QtAudioDeviceManager::callStaticMethod<void>(
- "registerAudioHeadsetStateReceiver",
- QNativeInterface::QAndroidApplication::context());
+ QtJniTypes::QtAudioDeviceManager::callStaticMethod<void>("registerAudioHeadsetStateReceiver");
}
QAndroidMediaDevices::~QAndroidMediaDevices()
@@ -33,9 +31,7 @@ QAndroidMediaDevices::~QAndroidMediaDevices()
// Object of QAndroidMediaDevices type is static. Unregistering will happend only when closing
// the application. In such case it is probably not needed, but let's leave it for
// compatibility with Android documentation
- QtJniTypes::QtAudioDeviceManager::callStaticMethod<void>(
- "unregisterAudioHeadsetStateReceiver",
- QNativeInterface::QAndroidApplication::context());
+ QtJniTypes::QtAudioDeviceManager::callStaticMethod<void>("unregisterAudioHeadsetStateReceiver");
}
QList<QAudioDevice> QAndroidMediaDevices::audioInputs() const
diff --git a/src/multimedia/audio/qaudiobufferinput.cpp b/src/multimedia/audio/qaudiobufferinput.cpp
new file mode 100644
index 000000000..ef4fdb0c3
--- /dev/null
+++ b/src/multimedia/audio/qaudiobufferinput.cpp
@@ -0,0 +1,157 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qaudiobufferinput.h"
+#include "qplatformaudiobufferinput_p.h"
+#include "qmediainputencoderinterface_p.h"
+#include "qmediaframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAudioBufferInputPrivate : public QMediaFrameInputPrivate
+{
+public:
+ QAudioBufferInputPrivate(QAudioBufferInput *q) : q(q) { }
+
+ bool sendAudioBuffer(const QAudioBuffer &audioBuffer)
+ {
+ return sendMediaFrame(
+ [&]() { emit m_platfromAudioBufferInput->newAudioBuffer(audioBuffer); });
+ }
+
+ void initialize()
+ {
+ m_platfromAudioBufferInput = std::make_unique<QPlatformAudioBufferInput>();
+ addUpdateSignal(m_platfromAudioBufferInput.get(),
+ &QPlatformAudioBufferInput::encoderUpdated);
+ }
+
+ void uninitialize()
+ {
+ m_platfromAudioBufferInput.reset();
+
+ if (captureSession())
+ captureSession()->setAudioBufferInput(nullptr);
+ }
+
+ QMediaCaptureSession *session() const { return m_captureSession; }
+
+ QPlatformAudioBufferInput *platfromAudioBufferInput() const
+ {
+ return m_platfromAudioBufferInput.get();
+ }
+
+private:
+ void updateCaptureSessionConnections(QMediaCaptureSession *prevSession,
+ QMediaCaptureSession *newSession) override
+ {
+ if (prevSession)
+ removeUpdateSignal(prevSession, &QMediaCaptureSession::audioOutputChanged);
+
+ if (newSession)
+ addUpdateSignal(newSession, &QMediaCaptureSession::audioOutputChanged);
+ }
+
+ bool checkIfCanSendMediaFrame() const override
+ {
+ if (auto encoderInterface = m_platfromAudioBufferInput->encoderInterface())
+ return encoderInterface->canPushFrame();
+
+ // Not implemented yet
+ // return captureSession()->audioOutput() != nullptr;
+ return false;
+ }
+
+ void emitReadyToSendMediaFrame() override { emit q->readyToSendAudioBuffer(); }
+
+private:
+ QAudioBufferInput *q = nullptr;
+ QMediaCaptureSession *m_captureSession = nullptr;
+ std::unique_ptr<QPlatformAudioBufferInput> m_platfromAudioBufferInput;
+};
+
+/*!
+ \class QAudioBufferInput
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
+ \since 6.8
+
+ \brief The QAudioBufferInput class is used for providing custom audio buffers
+ to \l QMediaRecorder through \l QMediaCaptureSession.
+
+ \sa QMediaRecorder, QMediaCaptureSession
+*/
+
+/*!
+ Constructs a new QAudioBufferInput object with \a parent.
+*/
+QAudioBufferInput::QAudioBufferInput(QObject *parent)
+ : QObject(*new QAudioBufferInputPrivate(this), parent)
+{
+ Q_D(QAudioBufferInput);
+ d->initialize();
+}
+
+/*!
+ Destroys the object.
+ */
+QAudioBufferInput::~QAudioBufferInput()
+{
+ Q_D(QAudioBufferInput);
+ d->uninitialize();
+}
+
+/*!
+ Sends \l QAudioBuffer to \l QMediaRecorder through \l QMediaCaptureSession.
+
+ Returns \c true if the specified \a audioBuffer has been sent successfully
+ to the destination. Returns \c false, if the buffer hasn't been sent,
+ which can happen if the instance is not assigned to
+ \l QMediaCaptureSession, the session doesn't have a media recorder,
+ the media recorder is not started or its queue is full.
+ The signal \l readyToSendAudiobuffer will be sent as soon as
+ the destination is able to handle a new audio buffer.
+*/
+bool QAudioBufferInput::sendAudioBuffer(const QAudioBuffer &audioBuffer)
+{
+ Q_D(QAudioBufferInput);
+ return d->sendAudioBuffer(audioBuffer);
+}
+
+/*!
+ Returns the capture session this audio buffer input is connected to, or
+ a \c nullptr if the audio buffer input is not connected to a capture session.
+
+ Use QMediaCaptureSession::setAudioBufferInput() to connect
+ the audio buffer input to a session.
+*/
+QMediaCaptureSession *QAudioBufferInput::captureSession() const
+{
+ Q_D(const QAudioBufferInput);
+ return d->captureSession();
+}
+
+void QAudioBufferInput::setCaptureSession(QMediaCaptureSession *captureSession)
+{
+ Q_D(QAudioBufferInput);
+ d->setCaptureSession(captureSession);
+}
+
+QPlatformAudioBufferInput *QAudioBufferInput::platformAudioBufferInput() const
+{
+ Q_D(const QAudioBufferInput);
+ return d->platfromAudioBufferInput();
+}
+
+/*!
+ \fn void QAudioBufferInput::readyToSendAudioBuffer()
+
+ Signals that a new audio buffer can be sent to the audio buffer input.
+ After receiving the signal, if you have audio date to be sent, invoke \l sendAudioBuffer
+ once or in a loop until it returns \c false.
+
+ \sa sendAudioBuffer()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiobufferinput.h b/src/multimedia/audio/qaudiobufferinput.h
new file mode 100644
index 000000000..92bb8b71a
--- /dev/null
+++ b/src/multimedia/audio/qaudiobufferinput.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QAUDIOBUFFERINPUT_H
+#define QAUDIOBUFFERINPUT_H
+
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtMultimedia/qaudiobuffer.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformAudioBufferInput;
+class QAudioBufferInputPrivate;
+class QMediaCaptureSession;
+
+class Q_MULTIMEDIA_EXPORT QAudioBufferInput : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QAudioBufferInput(QObject *parent = nullptr);
+
+ ~QAudioBufferInput() override;
+
+ bool sendAudioBuffer(const QAudioBuffer &audioBuffer);
+
+ QMediaCaptureSession *captureSession() const;
+
+Q_SIGNALS:
+ void readyToSendAudioBuffer();
+
+private:
+ void setCaptureSession(QMediaCaptureSession *captureSession);
+
+ QPlatformAudioBufferInput *platformAudioBufferInput() const;
+
+ friend class QMediaCaptureSession;
+ Q_DISABLE_COPY(QAudioBufferInput)
+ Q_DECLARE_PRIVATE(QAudioBufferInput)
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOBUFFERINPUT_H
diff --git a/src/multimedia/camera/qcamera.cpp b/src/multimedia/camera/qcamera.cpp
index a625fb96f..9cfbcc01d 100644
--- a/src/multimedia/camera/qcamera.cpp
+++ b/src/multimedia/camera/qcamera.cpp
@@ -152,14 +152,6 @@ QT_BEGIN_NAMESPACE
See the \l{Camera Overview}{camera overview} for more information.
*/
-
-void QCameraPrivate::_q_error(int error, const QString &errorString)
-{
- Q_Q(QCamera);
-
- this->error.setAndNotify(QCamera::Error(error), errorString, *q);
-}
-
void QCameraPrivate::init(const QCameraDevice &device)
{
Q_Q(QCamera);
@@ -167,16 +159,16 @@ void QCameraPrivate::init(const QCameraDevice &device)
auto maybeControl = QPlatformMediaIntegration::instance()->createCamera(q);
if (!maybeControl) {
qWarning() << "Failed to initialize QCamera" << maybeControl.error();
- error = { QCamera::CameraError, maybeControl.error() };
return;
}
control = maybeControl.value();
cameraDevice = !device.isNull() ? device : QMediaDevices::defaultVideoInput();
if (cameraDevice.isNull())
- _q_error(QCamera::CameraError, QStringLiteral("No camera detected"));
+ control->updateError(QCamera::CameraError, QStringLiteral("No camera detected"));
control->setCamera(cameraDevice);
q->connect(control, &QPlatformVideoSource::activeChanged, q, &QCamera::activeChanged);
- q->connect(control, SIGNAL(error(int, QString)), q, SLOT(_q_error(int, QString)));
+ q->connect(control, &QPlatformCamera::errorChanged, q, &QCamera::errorChanged);
+ q->connect(control, &QPlatformCamera::errorOccurred, q, &QCamera::errorOccurred);
}
/*!
@@ -296,7 +288,9 @@ void QCamera::setActive(bool active)
QCamera::Error QCamera::error() const
{
- return d_func()->error.code();
+ Q_D(const QCamera);
+
+ return d->control ? d->control->error() : QCamera::CameraError;
}
/*!
@@ -312,7 +306,10 @@ QCamera::Error QCamera::error() const
*/
QString QCamera::errorString() const
{
- return d_func()->error.description();
+ Q_D(const QCamera);
+
+ return d->control ? d->control->errorString()
+ : QStringLiteral("Camera is not supported on the platform");
}
/*! \enum QCamera::Feature
diff --git a/src/multimedia/camera/qcamera.h b/src/multimedia/camera/qcamera.h
index 09d9521ff..82d89f5a9 100644
--- a/src/multimedia/camera/qcamera.h
+++ b/src/multimedia/camera/qcamera.h
@@ -261,7 +261,6 @@ private:
friend class QMediaCaptureSession;
Q_DISABLE_COPY(QCamera)
Q_DECLARE_PRIVATE(QCamera)
- Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &))
friend class QCameraDevice;
};
diff --git a/src/multimedia/camera/qcamera_p.h b/src/multimedia/camera/qcamera_p.h
index c0477c242..ae1299435 100644
--- a/src/multimedia/camera/qcamera_p.h
+++ b/src/multimedia/camera/qcamera_p.h
@@ -16,7 +16,6 @@
//
#include "private/qobject_p.h"
-#include "private/qerrorinfo_p.h"
#include "qcamera.h"
#include "qcameradevice.h"
@@ -34,13 +33,8 @@ public:
QMediaCaptureSession *captureSession = nullptr;
QPlatformCamera *control = nullptr;
- QErrorInfo<QCamera::Error> error;
-
QCameraDevice cameraDevice;
QCameraFormat cameraFormat;
-
- void _q_error(int error, const QString &errorString);
- void unsetError() { error = {}; }
};
QT_END_NAMESPACE
diff --git a/src/multimedia/camera/qcameradevice.cpp b/src/multimedia/camera/qcameradevice.cpp
index 50727d49c..63e7fb4c0 100644
--- a/src/multimedia/camera/qcameradevice.cpp
+++ b/src/multimedia/camera/qcameradevice.cpp
@@ -455,10 +455,12 @@ QCameraDevice& QCameraDevice::operator=(const QCameraDevice& other) = default;
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QCameraDevice &camera)
{
- d.maybeSpace() << QStringLiteral("QCameraDevice(name=%1, position=%2, orientation=%3)")
- .arg(camera.description())
- .arg(QString::fromLatin1(QCamera::staticMetaObject.enumerator(QCamera::staticMetaObject.indexOfEnumerator("Position"))
- .valueToKey(camera.position())));
+ d.maybeSpace() << QStringLiteral("QCameraDevice(name=%1, id=%2, position=%3)")
+ .arg(camera.description())
+ .arg(QLatin1StringView(camera.id()))
+ .arg(QLatin1StringView(
+ QMetaEnum::fromType<QCameraDevice::Position>().valueToKey(
+ camera.position())));
return d.space();
}
#endif
diff --git a/src/multimedia/doc/src/qtmultimedia-index.qdoc b/src/multimedia/doc/src/qtmultimedia-index.qdoc
index 67b6688be..ad4c15e41 100644
--- a/src/multimedia/doc/src/qtmultimedia-index.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-index.qdoc
@@ -193,18 +193,18 @@
The version shipped with Qt binary packages is \b{FFmpeg 6.1.1} and is tested
by the maintainers.
- \note On the Windows platform, Qt's FFmpeg media backend uses
- dynamic linking to the FFmpeg libraries. Windows applications must
- therefore bundle FFmpeg binaries in their installer, and make them
- visible to the application according to Windows dll loading rules.
- We recommend to store the FFmpeg dlls in the same directory as the
- application's executable file, because this guarantees that the
- correct build of FFmpeg is being used if multiple versions are
- available on the system. All necessary FFmpeg dlls are shipped with
- the Qt Online Installer and are automatically deployed if the
- windeployqt tool is used to create the deployment. Applications can
- also deploy their own build of FFmpeg, as long as the FFmpeg major
- version matches the version used by Qt.
+ \note On the Windows and macOS platforms, Qt's FFmpeg media backend
+ uses dynamic linking to the FFmpeg libraries. Windows and macOS
+ applications must therefore bundle FFmpeg binaries in their
+ installer, and make them visible to the application at runtime. On
+ Windows, we recommend to store the FFmpeg dlls in the same directory
+ as the application's executable file, because this guarantees that
+ the correct build of FFmpeg is being used if multiple versions are
+ available on the system. All necessary FFmpeg libraries are shipped
+ with the Qt Online Installer and are automatically deployed if the
+ windeployqt or macdeployqt tools are used to create the deployment.
+ Applications can also deploy their own build of FFmpeg, as long as
+ the FFmpeg major version matches the version used by Qt.
\note See \l{Licenses and Attributions} regarding what components are removed
in the package shipped by Qt.
diff --git a/src/multimedia/platform/qgstreamer_platformspecificinterface.cpp b/src/multimedia/platform/qgstreamer_platformspecificinterface.cpp
new file mode 100644
index 000000000..06ce46e3c
--- /dev/null
+++ b/src/multimedia/platform/qgstreamer_platformspecificinterface.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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 <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QGStreamerPlatformSpecificInterface::~QGStreamerPlatformSpecificInterface() = default;
+
+QGStreamerPlatformSpecificInterface *QGStreamerPlatformSpecificInterface::instance()
+{
+ return dynamic_cast<QGStreamerPlatformSpecificInterface *>(
+ QPlatformMediaIntegration::instance()->platformSpecificInterface());
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qgstreamer_platformspecificinterface_p.h b/src/multimedia/platform/qgstreamer_platformspecificinterface_p.h
new file mode 100644
index 000000000..94183efc8
--- /dev/null
+++ b/src/multimedia/platform/qgstreamer_platformspecificinterface_p.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef GSTREAMER_PLATFORMSPECIFICINTERFACE_P_H
+#define GSTREAMER_PLATFORMSPECIFICINTERFACE_P_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 <QtMultimedia/private/qplatformmediaintegration_p.h>
+
+typedef struct _GstPipeline GstPipeline; // NOLINT (bugprone-reserved-identifier)
+
+QT_BEGIN_NAMESPACE
+
+class Q_MULTIMEDIA_EXPORT QGStreamerPlatformSpecificInterface
+ : public QAbstractPlatformSpecificInterface
+{
+public:
+ ~QGStreamerPlatformSpecificInterface() override;
+
+ static QGStreamerPlatformSpecificInterface *instance();
+
+ virtual QAudioDevice makeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline) = 0;
+ virtual QAudioDevice makeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline) = 0;
+ virtual QCamera *makeCustomGStreamerCamera(const QByteArray &gstreamerPipeline,
+ QObject *parent) = 0;
+
+ virtual GstPipeline *gstPipeline(QMediaPlayer *) = 0;
+ virtual GstPipeline *gstPipeline(QMediaCaptureSession *) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // GSTREAMER_PLATFORMSPECIFICINTERFACE_P_H
diff --git a/src/multimedia/platform/qplatformaudiobufferinput.cpp b/src/multimedia/platform/qplatformaudiobufferinput.cpp
new file mode 100644
index 000000000..883b11fc0
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudiobufferinput.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qplatformaudiobufferinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformaudiobufferinput_p.cpp"
diff --git a/src/multimedia/platform/qplatformaudiobufferinput_p.h b/src/multimedia/platform/qplatformaudiobufferinput_p.h
new file mode 100644
index 000000000..a05a98100
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudiobufferinput_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPLATFORMAUDIOBUFFERINPUT_P_H
+#define QPLATFORMAUDIOBUFFERINPUT_P_H
+
+#include "qaudioformat.h"
+#include "qaudiobuffer.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QMediaInputEncoderInterface;
+
+class Q_MULTIMEDIA_EXPORT QPlatformAudioBufferInputBase : public QObject
+{
+ Q_OBJECT
+Q_SIGNALS:
+ void newAudioBuffer(const QAudioBuffer &buffer);
+};
+
+class Q_MULTIMEDIA_EXPORT QPlatformAudioBufferInput : public QPlatformAudioBufferInputBase
+{
+ Q_OBJECT
+public:
+ QPlatformAudioBufferInput(QAudioFormat format = {}) : m_format(std::move(format)) { }
+
+ const QAudioFormat &audioFormat() const { return m_format; }
+
+ QMediaInputEncoderInterface *encoderInterface() const { return m_encoderInterface; }
+ void setEncoderInterface(QMediaInputEncoderInterface *interface)
+ {
+ m_encoderInterface = interface;
+ }
+
+Q_SIGNALS:
+ void encoderUpdated();
+
+private:
+ QMediaInputEncoderInterface *m_encoderInterface = nullptr;
+ QAudioFormat m_format;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMAUDIOBUFFERINPUT_P_H
diff --git a/src/multimedia/platform/qplatformcamera.cpp b/src/multimedia/platform/qplatformcamera.cpp
index 1d0e49cdd..d03c19d67 100644
--- a/src/multimedia/platform/qplatformcamera.cpp
+++ b/src/multimedia/platform/qplatformcamera.cpp
@@ -221,6 +221,13 @@ int QPlatformCamera::colorTemperatureForWhiteBalance(QCamera::WhiteBalanceMode m
return 0;
}
+void QPlatformCamera::updateError(QCamera::Error error, const QString &errorString)
+{
+ QMetaObject::invokeMethod(this, [this, error, errorString]() {
+ m_error.setAndNotify(error, errorString, *this);
+ });
+}
+
QT_END_NAMESPACE
#include "moc_qplatformcamera_p.cpp"
diff --git a/src/multimedia/platform/qplatformcamera_p.h b/src/multimedia/platform/qplatformcamera_p.h
index 85624c0ce..341bf9121 100644
--- a/src/multimedia/platform/qplatformcamera_p.h
+++ b/src/multimedia/platform/qplatformcamera_p.h
@@ -16,7 +16,7 @@
//
#include "qplatformvideosource_p.h"
-
+#include "private/qerrorinfo_p.h"
#include <QtMultimedia/qcamera.h>
QT_BEGIN_NAMESPACE
@@ -110,8 +110,13 @@ public:
static int colorTemperatureForWhiteBalance(QCamera::WhiteBalanceMode mode);
+ QCamera::Error error() const { return m_error.code(); }
+ QString errorString() const final { return m_error.description(); }
+
+ void updateError(QCamera::Error error, const QString &errorString);
+
Q_SIGNALS:
- void error(int error, const QString &errorString);
+ void errorOccurred(QCamera::Error error, const QString &errorString);
protected:
explicit QPlatformCamera(QCamera *parent);
@@ -150,6 +155,7 @@ private:
float m_maxExposureTime = -1.;
QCamera::WhiteBalanceMode m_whiteBalance = QCamera::WhiteBalanceAuto;
int m_colorTemperature = 0;
+ QErrorInfo<QCamera::Error> m_error;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediacapture.cpp b/src/multimedia/platform/qplatformmediacapture.cpp
index c8aded824..13bcbd63b 100644
--- a/src/multimedia/platform/qplatformmediacapture.cpp
+++ b/src/multimedia/platform/qplatformmediacapture.cpp
@@ -8,6 +8,7 @@
#include <QtMultimedia/private/qplatformmediacapture_p.h>
#include <QtMultimedia/private/qmediacapturesession_p.h>
#include <QtMultimedia/private/qplatformsurfacecapture_p.h>
+#include <QtMultimedia/private/qplatformvideoframeinput_p.h>
#include <QtMultimedia/private/qtmultimediaglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -23,6 +24,7 @@ std::vector<QPlatformVideoSource *> QPlatformMediaCaptureSession::activeVideoSou
result.push_back(source);
};
+ checkSource(videoFrameInput());
checkSource(camera());
checkSource(screenCapture());
checkSource(windowCapture());
@@ -30,15 +32,6 @@ std::vector<QPlatformVideoSource *> QPlatformMediaCaptureSession::activeVideoSou
return result;
}
-void *QPlatformMediaCaptureSession::nativePipeline(QMediaCaptureSession *session)
-{
- auto sessionPrivate = session->d_func();
- if (!sessionPrivate || !sessionPrivate->captureSession)
- return nullptr;
-
- return sessionPrivate->captureSession->nativePipeline();
-}
-
QT_END_NAMESPACE
#include "moc_qplatformmediacapture_p.cpp"
diff --git a/src/multimedia/platform/qplatformmediacapture_p.h b/src/multimedia/platform/qplatformmediacapture_p.h
index 981cf199b..8d6afc90e 100644
--- a/src/multimedia/platform/qplatformmediacapture_p.h
+++ b/src/multimedia/platform/qplatformmediacapture_p.h
@@ -29,6 +29,8 @@ class QPlatformAudioOutput;
class QMediaCaptureSession;
class QPlatformSurfaceCapture;
class QPlatformVideoSource;
+class QPlatformAudioBufferInput;
+class QPlatformVideoFrameInput;
class Q_MULTIMEDIA_EXPORT QPlatformMediaCaptureSession : public QObject
{
@@ -49,6 +51,9 @@ public:
virtual QPlatformSurfaceCapture *windowCapture() { return nullptr; }
virtual void setWindowCapture(QPlatformSurfaceCapture *) { }
+ virtual QPlatformVideoFrameInput *videoFrameInput() { return nullptr; }
+ virtual void setVideoFrameInput(QPlatformVideoFrameInput *) { }
+
virtual QPlatformImageCapture *imageCapture() = 0;
virtual void setImageCapture(QPlatformImageCapture *) {}
@@ -57,6 +62,8 @@ public:
virtual void setAudioInput(QPlatformAudioInput *input) = 0;
+ virtual void setAudioBufferInput(QPlatformAudioBufferInput *) { }
+
virtual void setVideoPreview(QVideoSink * /*sink*/) {}
virtual void setAudioOutput(QPlatformAudioOutput *) {}
@@ -64,15 +71,11 @@ public:
// TBD: implement ordering of the sources basing on the order of adding
std::vector<QPlatformVideoSource *> activeVideoSources();
- virtual void *nativePipeline() { return nullptr; }
-
- // private API, the purpose is getting GstPipeline
- static void *nativePipeline(QMediaCaptureSession *);
-
Q_SIGNALS:
void cameraChanged();
void screenCaptureChanged();
void windowCaptureChanged();
+ void videoFrameInputChanged();
void imageCaptureChanged();
void encoderChanged();
diff --git a/src/multimedia/platform/qplatformmediaintegration_p.h b/src/multimedia/platform/qplatformmediaintegration_p.h
index b949af02a..d03d0c794 100644
--- a/src/multimedia/platform/qplatformmediaintegration_p.h
+++ b/src/multimedia/platform/qplatformmediaintegration_p.h
@@ -55,6 +55,12 @@ class QCapturableWindow;
class QPlatformCapturableWindows;
class QVideoFrame;
+class Q_MULTIMEDIA_EXPORT QAbstractPlatformSpecificInterface
+{
+public:
+ virtual ~QAbstractPlatformSpecificInterface() = default;
+};
+
class Q_MULTIMEDIA_EXPORT QPlatformMediaIntegration : public QObject
{
Q_OBJECT
@@ -100,6 +106,8 @@ public:
// Convert a QVideoFrame to the destination format
virtual QVideoFrame convertVideoFrame(QVideoFrame &, const QVideoFrameFormat &);
+ virtual QAbstractPlatformSpecificInterface *platformSpecificInterface() { return nullptr; }
+
protected:
virtual QPlatformMediaFormatInfo *createFormatInfo();
diff --git a/src/multimedia/platform/qplatformmediaplayer.cpp b/src/multimedia/platform/qplatformmediaplayer.cpp
index ea22f94df..00840f074 100644
--- a/src/multimedia/platform/qplatformmediaplayer.cpp
+++ b/src/multimedia/platform/qplatformmediaplayer.cpp
@@ -14,9 +14,7 @@ QPlatformMediaPlayer::QPlatformMediaPlayer(QMediaPlayer *parent) : player(parent
QPlatformMediaIntegration::instance()->mediaDevices()->prepareAudio();
}
-QPlatformMediaPlayer::~QPlatformMediaPlayer()
-{
-}
+QPlatformMediaPlayer::~QPlatformMediaPlayer() = default;
void QPlatformMediaPlayer::stateChanged(QMediaPlayer::PlaybackState newState)
{
@@ -39,16 +37,4 @@ void QPlatformMediaPlayer::error(int error, const QString &errorString)
player->d_func()->setError(QMediaPlayer::Error(error), errorString);
}
-void *QPlatformMediaPlayer::nativePipeline(QMediaPlayer *player)
-{
- if (!player)
- return nullptr;
-
- auto playerPrivate = player->d_func();
- if (!playerPrivate || !playerPrivate->control)
- return nullptr;
-
- return playerPrivate->control->nativePipeline();
-}
-
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaplayer_p.h b/src/multimedia/platform/qplatformmediaplayer_p.h
index 6e3590763..3f9d57677 100644
--- a/src/multimedia/platform/qplatformmediaplayer_p.h
+++ b/src/multimedia/platform/qplatformmediaplayer_p.h
@@ -22,6 +22,7 @@
#include <QtCore/qpair.h>
#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
@@ -76,7 +77,9 @@ public:
virtual int activeTrack(TrackType) { return -1; }
virtual void setActiveTrack(TrackType, int /*streamNumber*/) {}
+ void durationChanged(std::chrono::milliseconds ms) { durationChanged(ms.count()); }
void durationChanged(qint64 duration) { emit player->durationChanged(duration); }
+ void positionChanged(std::chrono::milliseconds ms) { positionChanged(ms.count()); }
void positionChanged(qint64 position) {
if (m_position == position)
return;
@@ -124,11 +127,6 @@ public:
Q_EMIT player->loopsChanged();
}
- virtual void *nativePipeline() { return nullptr; }
-
- // private API, the purpose is getting GstPipeline
- static void *nativePipeline(QMediaPlayer *player);
-
protected:
explicit QPlatformMediaPlayer(QMediaPlayer *parent = nullptr);
@@ -144,6 +142,25 @@ private:
qint64 m_position = 0;
};
+#ifndef QT_NO_DEBUG_STREAM
+inline QDebug operator<<(QDebug dbg, QPlatformMediaPlayer::TrackType type)
+{
+ QDebugStateSaver save(dbg);
+ dbg.nospace();
+
+ switch (type) {
+ case QPlatformMediaPlayer::TrackType::AudioStream:
+ return dbg << "AudioStream";
+ case QPlatformMediaPlayer::TrackType::VideoStream:
+ return dbg << "VideoStream";
+ case QPlatformMediaPlayer::TrackType::SubtitleStream:
+ return dbg << "SubtitleStream";
+ default:
+ Q_UNREACHABLE_RETURN(dbg);
+ }
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformsurfacecapture_p.h b/src/multimedia/platform/qplatformsurfacecapture_p.h
index 42fbda474..e4c59c6f4 100644
--- a/src/multimedia/platform/qplatformsurfacecapture_p.h
+++ b/src/multimedia/platform/qplatformsurfacecapture_p.h
@@ -61,7 +61,7 @@ public:
Source source() const { return m_source; }
Error error() const;
- QString errorString() const;
+ QString errorString() const final;
protected:
virtual bool setActiveInternal(bool) = 0;
@@ -74,7 +74,6 @@ public Q_SLOTS:
Q_SIGNALS:
void sourceChanged(WindowSource);
void sourceChanged(ScreenSource);
- void errorChanged();
void errorOccurred(Error error, QString errorString);
private:
diff --git a/src/multimedia/platform/qplatformvideoframeinput.cpp b/src/multimedia/platform/qplatformvideoframeinput.cpp
new file mode 100644
index 000000000..d90306345
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideoframeinput.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qplatformvideoframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformvideoframeinput_p.cpp"
diff --git a/src/multimedia/platform/qplatformvideoframeinput_p.h b/src/multimedia/platform/qplatformvideoframeinput_p.h
new file mode 100644
index 000000000..45714492c
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideoframeinput_p.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPLATFORMVIDEOFRAMEINPUT_P_H
+#define QPLATFORMVIDEOFRAMEINPUT_P_H
+
+#include "qplatformvideosource_p.h"
+#include "qmetaobject.h"
+#include "qpointer.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QMediaInputEncoderInterface;
+
+class Q_MULTIMEDIA_EXPORT QPlatformVideoFrameInput : public QPlatformVideoSource
+{
+ Q_OBJECT
+public:
+ QPlatformVideoFrameInput(QVideoFrameFormat format = {}) : m_format(std::move(format)) { }
+
+ void setActive(bool) final { }
+ bool isActive() const final { return true; }
+
+ QVideoFrameFormat frameFormat() const final { return m_format; }
+
+ QString errorString() const final { return {}; }
+
+ QMediaInputEncoderInterface *encoderInterface() const { return m_encoderInterface; }
+ void setEncoderInterface(QMediaInputEncoderInterface *interface)
+ {
+ m_encoderInterface = interface;
+ }
+
+Q_SIGNALS:
+ void encoderUpdated();
+
+private:
+ QMediaInputEncoderInterface *m_encoderInterface = nullptr;
+ QVideoFrameFormat m_format;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMVIDEOFRAMEINPUT_P_H
diff --git a/src/multimedia/platform/qplatformvideosource_p.h b/src/multimedia/platform/qplatformvideosource_p.h
index 3ed76d3e2..b11524226 100644
--- a/src/multimedia/platform/qplatformvideosource_p.h
+++ b/src/multimedia/platform/qplatformvideosource_p.h
@@ -43,9 +43,14 @@ public:
virtual void setCaptureSession(QPlatformMediaCaptureSession *) { }
+ virtual QString errorString() const = 0;
+
+ bool hasError() const { return !errorString().isEmpty(); }
+
Q_SIGNALS:
void newVideoFrame(const QVideoFrame &);
void activeChanged(bool);
+ void errorChanged();
};
QT_END_NAMESPACE
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index dc8e3dab8..2336cf12e 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -596,6 +596,12 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
It does not wait for the media to finish loading and does not check for errors. Listen for
the mediaStatusChanged() and error() signals to be notified when the media is loaded and
when an error occurs during loading.
+
+ \note FFmpeg, used by the FFmpeg media backend, restricts use of nested protocols for
+ security reasons. In controlled environments where all inputs are trusted, the list of
+ approved protocols can be overridden using the QT_FFMPEG_PROTOCOL_WHITELIST environment
+ variable. This environment variable is Qt's private API and can change between patch
+ releases without notice.
*/
void QMediaPlayer::setSource(const QUrl &source)
diff --git a/src/multimedia/playback/qmediaplayer_p.h b/src/multimedia/playback/qmediaplayer_p.h
index ece086d06..a8a4653e3 100644
--- a/src/multimedia/playback/qmediaplayer_p.h
+++ b/src/multimedia/playback/qmediaplayer_p.h
@@ -40,6 +40,11 @@ class QMediaPlayerPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QMediaPlayer)
public:
+ static QMediaPlayerPrivate *get(QMediaPlayer *session)
+ {
+ return reinterpret_cast<QMediaPlayerPrivate *>(QObjectPrivate::get(session));
+ }
+
QMediaPlayerPrivate() = default;
QPlatformMediaPlayer *control = nullptr;
diff --git a/src/multimedia/qmediaframeinput.cpp b/src/multimedia/qmediaframeinput.cpp
new file mode 100644
index 000000000..4bb90d3ee
--- /dev/null
+++ b/src/multimedia/qmediaframeinput.cpp
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qmediaframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QMediaFrameInputPrivate::setCaptureSession(QMediaCaptureSession *session)
+{
+ if (session == m_captureSession)
+ return;
+
+ auto prevSession = std::exchange(m_captureSession, session);
+ updateCaptureSessionConnections(prevSession, session);
+ updateCanSendMediaFrame();
+}
+
+void QMediaFrameInputPrivate::updateCanSendMediaFrame()
+{
+ const bool canSendMediaFrame = m_captureSession && checkIfCanSendMediaFrame();
+ if (m_canSendMediaFrame != canSendMediaFrame) {
+ m_canSendMediaFrame = canSendMediaFrame;
+ if (m_canSendMediaFrame)
+ emitReadyToSendMediaFrame();
+ }
+}
+
+void QMediaFrameInputPrivate::postponeCheckReadyToSend()
+{
+ if (m_canSendMediaFrame && !m_postponeReadyToSendCheckRun) {
+ m_postponeReadyToSendCheckRun = true;
+ QMetaObject::invokeMethod(
+ q_ptr,
+ [this]() {
+ m_postponeReadyToSendCheckRun = false;
+ if (m_canSendMediaFrame)
+ emitReadyToSendMediaFrame();
+ },
+ Qt::QueuedConnection);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qmediaframeinput_p.h b/src/multimedia/qmediaframeinput_p.h
new file mode 100644
index 000000000..22277865d
--- /dev/null
+++ b/src/multimedia/qmediaframeinput_p.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QMEDIAFRAMEINPUT_P_H
+#define QMEDIAFRAMEINPUT_P_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 "qmediacapturesession.h"
+#include <QtCore/private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaFrameInputPrivate : public QObjectPrivate
+{
+public:
+ void setCaptureSession(QMediaCaptureSession *session);
+
+ QMediaCaptureSession *captureSession() const { return m_captureSession; }
+
+protected:
+ template <typename Sender>
+ bool sendMediaFrame(Sender &&sender)
+ {
+ if (!m_canSendMediaFrame)
+ return false;
+
+ sender();
+ postponeCheckReadyToSend();
+ return true;
+ }
+
+ template <typename Sender, typename Signal>
+ void addUpdateSignal(Sender sender, Signal signal)
+ {
+ connect(sender, signal, this, &QMediaFrameInputPrivate::updateCanSendMediaFrame);
+ }
+
+ template <typename Sender, typename Signal>
+ void removeUpdateSignal(Sender sender, Signal signal)
+ {
+ disconnect(sender, signal, this, &QMediaFrameInputPrivate::updateCanSendMediaFrame);
+ }
+
+ void updateCanSendMediaFrame();
+
+private:
+ void postponeCheckReadyToSend();
+
+ virtual bool checkIfCanSendMediaFrame() const = 0;
+
+ virtual void emitReadyToSendMediaFrame() = 0;
+
+ virtual void updateCaptureSessionConnections(QMediaCaptureSession *prevSession,
+ QMediaCaptureSession *currentSession) = 0;
+
+private:
+ QMediaCaptureSession *m_captureSession = nullptr;
+ bool m_canSendMediaFrame = false;
+ bool m_postponeReadyToSendCheckRun = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMEDIAFRAMEINPUT_P_H
diff --git a/src/multimedia/qmediainputencoderinterface_p.h b/src/multimedia/qmediainputencoderinterface_p.h
new file mode 100644
index 000000000..c199e59b4
--- /dev/null
+++ b/src/multimedia/qmediainputencoderinterface_p.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QMEDIAINPUTENCODERINTERFACE_P_H
+#define QMEDIAINPUTENCODERINTERFACE_P_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 <QtMultimedia/qtmultimediaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaInputEncoderInterface
+{
+public:
+ virtual ~QMediaInputEncoderInterface() = default;
+ virtual bool canPushFrame() const = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMEDIAINPUTENCODERINTERFACE_P_H
diff --git a/src/multimedia/qmediametadata.cpp b/src/multimedia/qmediametadata.cpp
index dc238721f..afbaea5b7 100644
--- a/src/multimedia/qmediametadata.cpp
+++ b/src/multimedia/qmediametadata.cpp
@@ -2,14 +2,15 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmediametadata.h"
+
#include <QtCore/qcoreapplication.h>
-#include <qvariant.h>
-#include <qobject.h>
-#include <qdatetime.h>
-#include <qmediaformat.h>
-#include <qsize.h>
-#include <qurl.h>
-#include <qimage.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qimage.h>
+#include <QtMultimedia/qmediaformat.h>
QT_BEGIN_NAMESPACE
@@ -41,7 +42,7 @@ QT_BEGIN_NAMESPACE
Media attributes
\row \li MediaType \li The type of the media (audio, video, etc). \li QString
\row \li FileFormat \li The file format of the media. \li QMediaFormat::FileFormat
- \row \li Duration \li The duration in millseconds of the media. \li qint64
+ \row \li Duration \li The duration in milliseconds of the media. \li qint64
\header \li {3,1}
Audio attributes
@@ -53,6 +54,7 @@ QT_BEGIN_NAMESPACE
\row \li VideoFrameRate \li The frame rate of the media's video stream. \li qreal
\row \li VideoBitRate \li The bit rate of the media's video stream in bits per second. \li int
\row \li VideoCodec \li The codec of the media's video stream. \li QMediaFormat::VideoCodec
+ \row \li HasHdrContent \li True if video is intended for HDR display (FFmpeg media backend only). \li bool
\header \li {3,1}
Music attributes
@@ -129,6 +131,10 @@ QMetaType QMediaMetaData::keyType(Key key)
case Resolution:
return QMetaType::fromType<QSize>();
+
+ case HasHdrContent:
+ return QMetaType::fromType<bool>();
+
default:
return QMetaType::fromType<void>();
}
@@ -276,6 +282,7 @@ QMetaType QMediaMetaData::keyType(Key key)
\value CoverArtImage Media cover art
\value Orientation
\value Resolution
+ \value [since 6.8] HasHdrContent Video may have HDR content (read only, FFmpeg media backend only)
*/
/*!
@@ -385,6 +392,7 @@ QString QMediaMetaData::stringValue(QMediaMetaData::Key key) const
case Composer:
case Orientation:
case LeadPerformer:
+ case HasHdrContent:
return value.toString();
case Language: {
auto l = value.value<QLocale::Language>();
@@ -479,6 +487,8 @@ QString QMediaMetaData::metaDataKeyToString(QMediaMetaData::Key key)
return (QCoreApplication::translate("QMediaMetaData", "Resolution"));
case QMediaMetaData::LeadPerformer:
return (QCoreApplication::translate("QMediaMetaData", "Lead performer"));
+ case QMediaMetaData::HasHdrContent:
+ return (QCoreApplication::translate("QMediaMetaData", "Has HDR content"));
}
return QString();
}
diff --git a/src/multimedia/qmediametadata.h b/src/multimedia/qmediametadata.h
index d6f4477d3..0ff03dda2 100644
--- a/src/multimedia/qmediametadata.h
+++ b/src/multimedia/qmediametadata.h
@@ -57,11 +57,13 @@ public:
CoverArtImage,
Orientation,
- Resolution
+ Resolution,
+
+ HasHdrContent
};
Q_ENUM(Key)
- static constexpr int NumMetaData = Resolution + 1;
+ static constexpr int NumMetaData = HasHdrContent + 1;
// QMetaType typeForKey(Key k);
Q_INVOKABLE QVariant value(Key k) const { return data.value(k); }
diff --git a/src/multimedia/qsymbolsresolveutils.cpp b/src/multimedia/qsymbolsresolveutils.cpp
new file mode 100644
index 000000000..8441ac243
--- /dev/null
+++ b/src/multimedia/qsymbolsresolveutils.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsymbolsresolveutils_p.h"
+
+#include <qdebug.h>
+#include <algorithm>
+#include <qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+static Q_LOGGING_CATEGORY(qLcSymbolsResolver, "qt.multimedia.symbolsresolver");
+
+bool SymbolsResolver::isLazyLoadEnabled()
+{
+ static const bool lazyLoad =
+ !static_cast<bool>(qEnvironmentVariableIntValue("QT_INSTANT_LOAD_FFMPEG_STUBS"));
+ return lazyLoad;
+}
+
+SymbolsResolver::SymbolsResolver(const char *libLoggingName, LibraryLoader loader)
+ : m_libLoggingName(libLoggingName)
+{
+ Q_ASSERT(libLoggingName);
+ Q_ASSERT(loader);
+
+ auto library = loader();
+ if (library && library->isLoaded())
+ m_library = std::move(library);
+ else
+ qCWarning(qLcSymbolsResolver) << "Couldn't load" << m_libLoggingName << "library";
+}
+
+SymbolsResolver::SymbolsResolver(const char *libName, const char *version,
+ const char *libLoggingName)
+ : m_libLoggingName(libLoggingName ? libLoggingName : libName)
+{
+ Q_ASSERT(libName);
+ Q_ASSERT(version);
+
+ auto library = std::make_unique<QLibrary>(QString::fromLocal8Bit(libName),
+ QString::fromLocal8Bit(version));
+ if (library->load())
+ m_library = std::move(library);
+ else
+ qCWarning(qLcSymbolsResolver) << "Couldn't load" << m_libLoggingName << "library";
+}
+
+SymbolsResolver::~SymbolsResolver()
+{
+ if (m_library)
+ m_library->unload();
+}
+
+QFunctionPointer SymbolsResolver::initFunction(const char *funcName)
+{
+ if (!m_library)
+ return nullptr;
+ if (auto func = m_library->resolve(funcName))
+ return func;
+
+ qCWarning(qLcSymbolsResolver) << "Couldn't resolve" << m_libLoggingName << "symbol" << funcName;
+ m_library->unload();
+ m_library.reset();
+ return nullptr;
+}
+
+void SymbolsResolver::checkLibrariesLoaded(SymbolsMarker *begin, SymbolsMarker *end)
+{
+ if (m_library) {
+ qCDebug(qLcSymbolsResolver) << m_libLoggingName << "symbols resolved";
+ } else {
+ const auto size = reinterpret_cast<char *>(end) - reinterpret_cast<char *>(begin);
+ memset(begin, 0, size);
+ qCWarning(qLcSymbolsResolver) << "Couldn't resolve" << m_libLoggingName << "symbols";
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qsymbolsresolveutils_p.h b/src/multimedia/qsymbolsresolveutils_p.h
new file mode 100644
index 000000000..98a552170
--- /dev/null
+++ b/src/multimedia/qsymbolsresolveutils_p.h
@@ -0,0 +1,178 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q_SYMBOLSRESOLVEUTILS
+#define Q_SYMBOLSRESOLVEUTILS
+
+#include <QtCore/qlibrary.h>
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <tuple>
+#include <memory>
+
+//
+// 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.
+//
+
+QT_BEGIN_NAMESPACE
+
+constexpr bool areVersionsEqual(const char lhs[], const char rhs[])
+{
+ int i = 0;
+ for (; lhs[i] && rhs[i]; ++i)
+ if (lhs[i] != rhs[i])
+ return false;
+ return lhs[i] == rhs[i];
+}
+
+constexpr bool areVersionsEqual(const char lhs[], int rhsInt)
+{
+ int lhsInt = 0;
+ for (int i = 0; lhs[i]; ++i) {
+ if (lhs[i] < '0' || lhs[i] > '9')
+ return false;
+
+ lhsInt *= 10;
+ lhsInt += lhs[i] - '0';
+ }
+
+ return lhsInt == rhsInt;
+}
+
+
+template <typename T>
+struct DefaultReturn
+{
+ template <typename... Arg>
+ T operator()(Arg &&...) { return val; }
+ T val;
+};
+
+template <>
+struct DefaultReturn<void>
+{
+ template <typename... Arg>
+ void operator()(Arg &&...) { }
+};
+
+template <typename...>
+struct FuncInfo;
+
+template <typename R, typename... A>
+struct FuncInfo<R(A...)>
+{
+ using Return = R;
+ using Args = std::tuple<A...>;
+};
+
+class Q_MULTIMEDIA_EXPORT SymbolsResolver
+{
+public:
+ using LibraryLoader = std::unique_ptr<QLibrary> (*)();
+ static bool isLazyLoadEnabled();
+
+ ~SymbolsResolver();
+protected:
+ SymbolsResolver(const char *libLoggingName, LibraryLoader loader);
+
+ SymbolsResolver(const char *libName, const char *version = "",
+ const char *libLoggingName = nullptr);
+
+ QFunctionPointer initFunction(const char *name);
+
+ struct SymbolsMarker {};
+ void checkLibrariesLoaded(SymbolsMarker *begin, SymbolsMarker *end);
+
+private:
+ const char *m_libLoggingName;
+ std::unique_ptr<QLibrary> m_library;
+};
+
+
+QT_END_NAMESPACE
+
+// clang-format off
+
+#define CHECK_VERSIONS(Name, NeededSoversion, DetectedVersion) \
+ static_assert(areVersionsEqual(NeededSoversion, DetectedVersion), \
+ "Configuartion error: misleading " Name " versions!")
+
+#define BEGIN_INIT_FUNCS(...) \
+ QT_USE_NAMESPACE \
+ namespace { \
+ class SymbolsResolverImpl : SymbolsResolver { \
+ public: \
+ SymbolsResolverImpl() : SymbolsResolver(__VA_ARGS__) \
+ { checkLibrariesLoaded(&symbolsBegin, &symbolsEnd); } \
+ static const SymbolsResolverImpl& instance() \
+ { static const SymbolsResolverImpl instance; return instance; } \
+ SymbolsMarker symbolsBegin;
+
+#define INIT_FUNC(F) QFunctionPointer F = initFunction(#F);
+
+#define END_INIT_FUNCS() \
+ SymbolsMarker symbolsEnd; \
+ }; \
+ [[maybe_unused]] static const auto *instantResolver = \
+ SymbolsResolver::isLazyLoadEnabled() ? &SymbolsResolverImpl::instance() : nullptr; \
+ }
+
+
+#ifdef Q_EXPORT_STUB_SYMBOLS
+#define EXPORT_FUNC Q_MULTIMEDIA_EXPORT
+#else
+#define EXPORT_FUNC
+#endif
+
+#define DEFINE_FUNC_IMPL(F, Vars, TypesWithVars, ReturnFunc) \
+ using F##_ReturnType = FuncInfo<decltype(F)>::Return; \
+ extern "C" EXPORT_FUNC [[maybe_unused]] F##_ReturnType F(TypesWithVars(F)) { \
+ using F##_Type = F##_ReturnType (*)(TypesWithVars(F)); \
+ const auto f = SymbolsResolverImpl::instance().F; \
+ return f ? (reinterpret_cast<F##_Type>(f))(Vars()) : ReturnFunc(); \
+ }
+
+
+#define VAR(I) a##I
+#define VARS0()
+#define VARS1() VAR(0)
+#define VARS2() VARS1(), VAR(1)
+#define VARS3() VARS2(), VAR(2)
+#define VARS4() VARS3(), VAR(3)
+#define VARS5() VARS4(), VAR(4)
+#define VARS6() VARS5(), VAR(5)
+#define VARS7() VARS6(), VAR(6)
+#define VARS8() VARS7(), VAR(7)
+#define VARS9() VARS8(), VAR(8)
+#define VARS10() VARS9(), VAR(9)
+#define VARS11() VARS10(), VAR(10)
+
+#define TYPE_WITH_VAR(F, I) std::tuple_element_t<I, FuncInfo<decltype(F)>::Args> VAR(I)
+#define TYPES_WITH_VARS0(F)
+#define TYPES_WITH_VARS1(F) TYPE_WITH_VAR(F, 0)
+#define TYPES_WITH_VARS2(F) TYPES_WITH_VARS1(F), TYPE_WITH_VAR(F, 1)
+#define TYPES_WITH_VARS3(F) TYPES_WITH_VARS2(F), TYPE_WITH_VAR(F, 2)
+#define TYPES_WITH_VARS4(F) TYPES_WITH_VARS3(F), TYPE_WITH_VAR(F, 3)
+#define TYPES_WITH_VARS5(F) TYPES_WITH_VARS4(F), TYPE_WITH_VAR(F, 4)
+#define TYPES_WITH_VARS6(F) TYPES_WITH_VARS5(F), TYPE_WITH_VAR(F, 5)
+#define TYPES_WITH_VARS7(F) TYPES_WITH_VARS6(F), TYPE_WITH_VAR(F, 6)
+#define TYPES_WITH_VARS8(F) TYPES_WITH_VARS7(F), TYPE_WITH_VAR(F, 7)
+#define TYPES_WITH_VARS9(F) TYPES_WITH_VARS8(F), TYPE_WITH_VAR(F, 8)
+#define TYPES_WITH_VARS10(F) TYPES_WITH_VARS9(F), TYPE_WITH_VAR(F, 9)
+#define TYPES_WITH_VARS11(F) TYPES_WITH_VARS10(F), TYPE_WITH_VAR(F, 10)
+
+
+#define RET(F, ...) DefaultReturn<FuncInfo<decltype(F)>::Return>{__VA_ARGS__}
+
+#define DEFINE_FUNC(F, ArgsCount, /*Return value*/...) \
+ DEFINE_FUNC_IMPL(F, VARS##ArgsCount, TYPES_WITH_VARS##ArgsCount, RET(F, __VA_ARGS__));
+
+// clang-format on
+
+#endif // Q_SYMBOLSRESOLVEUTILS
diff --git a/src/multimedia/recording/qmediacapturesession.cpp b/src/multimedia/recording/qmediacapturesession.cpp
index f175cd98e..9df09acef 100644
--- a/src/multimedia/recording/qmediacapturesession.cpp
+++ b/src/multimedia/recording/qmediacapturesession.cpp
@@ -10,16 +10,20 @@
#include "qvideosink.h"
#include "qscreencapture.h"
#include "qwindowcapture.h"
+#include "qvideoframeinput.h"
#include "qplatformmediaintegration_p.h"
#include "qplatformmediacapture_p.h"
#include "qaudioinput.h"
+#include "qaudiobufferinput.h"
#include "qaudiooutput.h"
QT_BEGIN_NAMESPACE
void QMediaCaptureSessionPrivate::setVideoSink(QVideoSink *sink)
{
+ Q_Q(QMediaCaptureSession);
+
if (sink == videoSink)
return;
if (videoSink)
@@ -41,18 +45,23 @@ void QMediaCaptureSessionPrivate::setVideoSink(QVideoSink *sink)
\ingroup multimedia_video
\ingroup multimedia_audio
- The QMediaCaptureSession is the central class that manages capturing of media on the local device.
+ The QMediaCaptureSession is the central class that manages capturing of media on the local
+ device.
- You can connect a video input to QMediaCaptureSession using setCamera(), setScreenCapture() or setWindowCapture().
- A preview of the captured media can be seen by setting a QVideoWidget or QGraphicsVideoItem using setVideoOutput().
+ You can connect a video input to QMediaCaptureSession using setCamera(),
+ setScreenCapture(), setWindowCapture() or setVideoFrameInput().
+ A preview of the captured media can be seen by setting a QVideoWidget or QGraphicsVideoItem
+ using setVideoOutput().
- You can connect a microphone to QMediaCaptureSession using setAudioInput().
+ You can connect a microphone to QMediaCaptureSession using setAudioInput(), or set your
+ custom audio input using setAudioBufferInput().
The captured sound can be heard by routing the audio to an output device using setAudioOutput().
- You can capture still images from a camera by setting a QImageCapture object on the capture session,
- and record audio/video using a QMediaRecorder.
+ You can capture still images from a camera by setting a QImageCapture object on the capture
+ session, and record audio/video using a QMediaRecorder.
- \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QScreenCapture, QWindowCapture, QMediaRecorder, QGraphicsVideoItem
+ \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QScreenCapture, QWindowCapture,
+ QVideoFrameInput, QMediaRecorder, QGraphicsVideoItem
*/
/*!
@@ -112,14 +121,16 @@ void QMediaCaptureSessionPrivate::setVideoSink(QVideoSink *sink)
Creates a session for media capture from the \a parent object.
*/
QMediaCaptureSession::QMediaCaptureSession(QObject *parent)
- : QObject(parent),
- d_ptr(new QMediaCaptureSessionPrivate)
+ : QObject{ *new QMediaCaptureSessionPrivate, parent }
{
- d_ptr->q = this;
+ QT6_ONLY(Q_UNUSED(unused))
+
+ Q_D(QMediaCaptureSession);
+
auto maybeCaptureSession = QPlatformMediaIntegration::instance()->createCaptureSession();
if (maybeCaptureSession) {
- d_ptr->captureSession = maybeCaptureSession.value();
- d_ptr->captureSession->setCaptureSession(this);
+ d->captureSession.reset(maybeCaptureSession.value());
+ d->captureSession->setCaptureSession(this);
} else {
qWarning() << "Failed to initialize QMediaCaptureSession" << maybeCaptureSession.error();
}
@@ -130,16 +141,19 @@ QMediaCaptureSession::QMediaCaptureSession(QObject *parent)
*/
QMediaCaptureSession::~QMediaCaptureSession()
{
+ Q_D(QMediaCaptureSession);
+
setCamera(nullptr);
setRecorder(nullptr);
setImageCapture(nullptr);
setScreenCapture(nullptr);
setWindowCapture(nullptr);
+ setVideoFrameInput(nullptr);
+ setAudioBufferInput(nullptr);
setAudioInput(nullptr);
setAudioOutput(nullptr);
- d_ptr->setVideoSink(nullptr);
- delete d_ptr->captureSession;
- delete d_ptr;
+ d->setVideoSink(nullptr);
+ d->captureSession.reset();
}
/*!
\qmlproperty AudioInput QtMultimedia::CaptureSession::audioInput
@@ -154,7 +168,8 @@ QMediaCaptureSession::~QMediaCaptureSession()
*/
QAudioInput *QMediaCaptureSession::audioInput() const
{
- return d_ptr->audioInput;
+ Q_D(const QMediaCaptureSession);
+ return d->audioInput;
}
/*!
@@ -164,28 +179,69 @@ QAudioInput *QMediaCaptureSession::audioInput() const
*/
void QMediaCaptureSession::setAudioInput(QAudioInput *input)
{
- QAudioInput *oldInput = d_ptr->audioInput;
+ Q_D(QMediaCaptureSession);
+
+ QAudioInput *oldInput = d->audioInput;
if (oldInput == input)
return;
// To avoid double emit of audioInputChanged
// from recursive setAudioInput(nullptr) call.
- d_ptr->audioInput = nullptr;
+ d->audioInput = nullptr;
- if (d_ptr->captureSession)
- d_ptr->captureSession->setAudioInput(nullptr);
+ if (d->captureSession)
+ d->captureSession->setAudioInput(nullptr);
if (oldInput)
oldInput->setDisconnectFunction({});
if (input) {
input->setDisconnectFunction([this](){ setAudioInput(nullptr); });
- if (d_ptr->captureSession)
- d_ptr->captureSession->setAudioInput(input->handle());
+ if (d->captureSession)
+ d->captureSession->setAudioInput(input->handle());
}
- d_ptr->audioInput = input;
+ d->audioInput = input;
emit audioInputChanged();
}
/*!
+ \property QMediaCaptureSession::audioBufferInput
+ \since 6.8
+
+ \brief The object used to send custom audio buffers to \l QMediaRecorder.
+*/
+QAudioBufferInput *QMediaCaptureSession::audioBufferInput() const
+{
+ Q_D(const QMediaCaptureSession);
+
+ return d->audioBufferInput;
+}
+
+void QMediaCaptureSession::setAudioBufferInput(QAudioBufferInput *input)
+{
+ Q_D(QMediaCaptureSession);
+
+ // TODO: come up with an unification of the captures setup
+ QAudioBufferInput *oldInput = d->audioBufferInput;
+ if (oldInput == input)
+ return;
+ d->audioBufferInput = input;
+ if (d->captureSession)
+ d->captureSession->setAudioBufferInput(nullptr);
+ if (oldInput) {
+ if (oldInput->captureSession() && oldInput->captureSession() != this)
+ oldInput->captureSession()->setAudioBufferInput(nullptr);
+ oldInput->setCaptureSession(nullptr);
+ }
+ if (input) {
+ if (input->captureSession())
+ input->captureSession()->setAudioBufferInput(nullptr);
+ if (d->captureSession)
+ d->captureSession->setAudioBufferInput(input->platformAudioBufferInput());
+ input->setCaptureSession(this);
+ }
+ emit audioBufferInputChanged();
+}
+
+/*!
\qmlproperty Camera QtMultimedia::CaptureSession::camera
\brief The camera used to capture video.
@@ -204,18 +260,22 @@ void QMediaCaptureSession::setAudioInput(QAudioInput *input)
*/
QCamera *QMediaCaptureSession::camera() const
{
- return d_ptr->camera;
+ Q_D(const QMediaCaptureSession);
+
+ return d->camera;
}
void QMediaCaptureSession::setCamera(QCamera *camera)
{
+ Q_D(QMediaCaptureSession);
+
// TODO: come up with an unification of the captures setup
- QCamera *oldCamera = d_ptr->camera;
+ QCamera *oldCamera = d->camera;
if (oldCamera == camera)
return;
- d_ptr->camera = camera;
- if (d_ptr->captureSession)
- d_ptr->captureSession->setCamera(nullptr);
+ d->camera = camera;
+ if (d->captureSession)
+ d->captureSession->setCamera(nullptr);
if (oldCamera) {
if (oldCamera->captureSession() && oldCamera->captureSession() != this)
oldCamera->captureSession()->setCamera(nullptr);
@@ -224,8 +284,8 @@ void QMediaCaptureSession::setCamera(QCamera *camera)
if (camera) {
if (camera->captureSession())
camera->captureSession()->setCamera(nullptr);
- if (d_ptr->captureSession)
- d_ptr->captureSession->setCamera(camera->platformCamera());
+ if (d->captureSession)
+ d->captureSession->setCamera(camera->platformCamera());
camera->setCaptureSession(this);
}
emit cameraChanged();
@@ -252,18 +312,22 @@ void QMediaCaptureSession::setCamera(QCamera *camera)
*/
QScreenCapture *QMediaCaptureSession::screenCapture()
{
- return d_ptr ? d_ptr->screenCapture : nullptr;
+ Q_D(QMediaCaptureSession);
+
+ return d->screenCapture;
}
void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture)
{
+ Q_D(QMediaCaptureSession);
+
// TODO: come up with an unification of the captures setup
- QScreenCapture *oldScreenCapture = d_ptr->screenCapture;
+ QScreenCapture *oldScreenCapture = d->screenCapture;
if (oldScreenCapture == screenCapture)
return;
- d_ptr->screenCapture = screenCapture;
- if (d_ptr->captureSession)
- d_ptr->captureSession->setScreenCapture(nullptr);
+ d->screenCapture = screenCapture;
+ if (d->captureSession)
+ d->captureSession->setScreenCapture(nullptr);
if (oldScreenCapture) {
if (oldScreenCapture->captureSession() && oldScreenCapture->captureSession() != this)
oldScreenCapture->captureSession()->setScreenCapture(nullptr);
@@ -272,8 +336,8 @@ void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture)
if (screenCapture) {
if (screenCapture->captureSession())
screenCapture->captureSession()->setScreenCapture(nullptr);
- if (d_ptr->captureSession)
- d_ptr->captureSession->setScreenCapture(screenCapture->platformScreenCapture());
+ if (d->captureSession)
+ d->captureSession->setScreenCapture(screenCapture->platformScreenCapture());
screenCapture->setCaptureSession(this);
}
emit screenCaptureChanged();
@@ -298,19 +362,23 @@ void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture)
Record a window by adding a window capture objet
to the capture session using this property.
*/
-QWindowCapture *QMediaCaptureSession::windowCapture() {
- return d_ptr ? d_ptr->windowCapture : nullptr;
+QWindowCapture *QMediaCaptureSession::windowCapture()
+{
+ Q_D(QMediaCaptureSession);
+ return d->windowCapture;
}
void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture)
{
+ Q_D(QMediaCaptureSession);
+
// TODO: come up with an unification of the captures setup
- QWindowCapture *oldCapture = d_ptr->windowCapture;
+ QWindowCapture *oldCapture = d->windowCapture;
if (oldCapture == windowCapture)
return;
- d_ptr->windowCapture = windowCapture;
- if (d_ptr->captureSession)
- d_ptr->captureSession->setWindowCapture(nullptr);
+ d->windowCapture = windowCapture;
+ if (d->captureSession)
+ d->captureSession->setWindowCapture(nullptr);
if (oldCapture) {
if (oldCapture->captureSession() && oldCapture->captureSession() != this)
oldCapture->captureSession()->setWindowCapture(nullptr);
@@ -319,14 +387,52 @@ void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture)
if (windowCapture) {
if (windowCapture->captureSession())
windowCapture->captureSession()->setWindowCapture(nullptr);
- if (d_ptr->captureSession)
- d_ptr->captureSession->setWindowCapture(windowCapture->platformWindowCapture());
+ if (d->captureSession)
+ d->captureSession->setWindowCapture(windowCapture->platformWindowCapture());
windowCapture->setCaptureSession(this);
}
emit windowCaptureChanged();
}
/*!
+ \property QMediaCaptureSession::videoFrameInput
+ \since 6.8
+
+ \brief The object used to send custom video frames to
+ \l QMediaRecorder or a video output.
+*/
+QVideoFrameInput *QMediaCaptureSession::videoFrameInput() const
+{
+ Q_D(const QMediaCaptureSession);
+ return d->videoFrameInput;
+}
+
+void QMediaCaptureSession::setVideoFrameInput(QVideoFrameInput *input)
+{
+ Q_D(QMediaCaptureSession);
+ // TODO: come up with an unification of the captures setup
+ QVideoFrameInput *oldInput = d->videoFrameInput;
+ if (oldInput == input)
+ return;
+ d->videoFrameInput = input;
+ if (d->captureSession)
+ d->captureSession->setVideoFrameInput(nullptr);
+ if (oldInput) {
+ if (oldInput->captureSession() && oldInput->captureSession() != this)
+ oldInput->captureSession()->setVideoFrameInput(nullptr);
+ oldInput->setCaptureSession(nullptr);
+ }
+ if (input) {
+ if (input->captureSession())
+ input->captureSession()->setVideoFrameInput(nullptr);
+ if (d->captureSession)
+ d->captureSession->setVideoFrameInput(input->platformVideoFrameInput());
+ input->setCaptureSession(this);
+ }
+ emit videoFrameInputChanged();
+}
+
+/*!
\qmlproperty ImageCapture QtMultimedia::CaptureSession::imageCapture
\brief The object used to capture still images.
@@ -344,18 +450,22 @@ void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture)
*/
QImageCapture *QMediaCaptureSession::imageCapture()
{
- return d_ptr->imageCapture;
+ Q_D(QMediaCaptureSession);
+
+ return d->imageCapture;
}
void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture)
{
+ Q_D(QMediaCaptureSession);
+
// TODO: come up with an unification of the captures setup
- QImageCapture *oldImageCapture = d_ptr->imageCapture;
+ QImageCapture *oldImageCapture = d->imageCapture;
if (oldImageCapture == imageCapture)
return;
- d_ptr->imageCapture = imageCapture;
- if (d_ptr->captureSession)
- d_ptr->captureSession->setImageCapture(nullptr);
+ d->imageCapture = imageCapture;
+ if (d->captureSession)
+ d->captureSession->setImageCapture(nullptr);
if (oldImageCapture) {
if (oldImageCapture->captureSession() && oldImageCapture->captureSession() != this)
oldImageCapture->captureSession()->setImageCapture(nullptr);
@@ -364,8 +474,8 @@ void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture)
if (imageCapture) {
if (imageCapture->captureSession())
imageCapture->captureSession()->setImageCapture(nullptr);
- if (d_ptr->captureSession)
- d_ptr->captureSession->setImageCapture(imageCapture->platformImageCapture());
+ if (d->captureSession)
+ d->captureSession->setImageCapture(imageCapture->platformImageCapture());
imageCapture->setCaptureSession(this);
}
emit imageCaptureChanged();
@@ -389,17 +499,19 @@ void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture)
QMediaRecorder *QMediaCaptureSession::recorder()
{
- return d_ptr->recorder;
+ Q_D(QMediaCaptureSession);
+ return d->recorder;
}
void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder)
{
- QMediaRecorder *oldRecorder = d_ptr->recorder;
+ Q_D(QMediaCaptureSession);
+ QMediaRecorder *oldRecorder = d->recorder;
if (oldRecorder == recorder)
return;
- d_ptr->recorder = recorder;
- if (d_ptr->captureSession)
- d_ptr->captureSession->setMediaRecorder(nullptr);
+ d->recorder = recorder;
+ if (d->captureSession)
+ d->captureSession->setMediaRecorder(nullptr);
if (oldRecorder) {
if (oldRecorder->captureSession() && oldRecorder->captureSession() != this)
oldRecorder->captureSession()->setRecorder(nullptr);
@@ -408,8 +520,8 @@ void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder)
if (recorder) {
if (recorder->captureSession())
recorder->captureSession()->setRecorder(nullptr);
- if (d_ptr->captureSession)
- d_ptr->captureSession->setMediaRecorder(recorder->platformRecoder());
+ if (d->captureSession)
+ d->captureSession->setMediaRecorder(recorder->platformRecoder());
recorder->setCaptureSession(this);
}
emit recorderChanged();
@@ -487,25 +599,27 @@ QVideoSink *QMediaCaptureSession::videoSink() const
*/
void QMediaCaptureSession::setAudioOutput(QAudioOutput *output)
{
- QAudioOutput *oldOutput = d_ptr->audioOutput;
+ Q_D(QMediaCaptureSession);
+
+ QAudioOutput *oldOutput = d->audioOutput;
if (oldOutput == output)
return;
// We don't want to end up with signal emitted
// twice (from recursive call setAudioInput(nullptr)
// from oldOutput->setDisconnectFunction():
- d_ptr->audioOutput = nullptr;
+ d->audioOutput = nullptr;
- if (d_ptr->captureSession)
- d_ptr->captureSession->setAudioOutput(nullptr);
+ if (d->captureSession)
+ d->captureSession->setAudioOutput(nullptr);
if (oldOutput)
oldOutput->setDisconnectFunction({});
if (output) {
output->setDisconnectFunction([this](){ setAudioOutput(nullptr); });
- if (d_ptr->captureSession)
- d_ptr->captureSession->setAudioOutput(output->handle());
+ if (d->captureSession)
+ d->captureSession->setAudioOutput(output->handle());
}
- d_ptr->audioOutput = output;
+ d->audioOutput = output;
emit audioOutputChanged();
}
/*!
@@ -531,7 +645,8 @@ QAudioOutput *QMediaCaptureSession::audioOutput() const
*/
QPlatformMediaCaptureSession *QMediaCaptureSession::platformSession() const
{
- return d_ptr->captureSession;
+ Q_D(const QMediaCaptureSession);
+ return d->captureSession.get();
}
/*!
\qmlsignal QtMultimedia::CaptureSession::audioInputChanged()
diff --git a/src/multimedia/recording/qmediacapturesession.h b/src/multimedia/recording/qmediacapturesession.h
index 1333af7eb..219c382d1 100644
--- a/src/multimedia/recording/qmediacapturesession.h
+++ b/src/multimedia/recording/qmediacapturesession.h
@@ -11,6 +11,7 @@ QT_BEGIN_NAMESPACE
class QCamera;
class QAudioInput;
+class QAudioBufferInput;
class QAudioOutput;
class QCameraDevice;
class QImageCapture;
@@ -19,18 +20,23 @@ class QPlatformMediaCaptureSession;
class QVideoSink;
class QScreenCapture;
class QWindowCapture;
+class QVideoFrameInput;
class QMediaCaptureSessionPrivate;
class Q_MULTIMEDIA_EXPORT QMediaCaptureSession : public QObject
{
Q_OBJECT
Q_PROPERTY(QAudioInput *audioInput READ audioInput WRITE setAudioInput NOTIFY audioInputChanged)
+ Q_PROPERTY(QAudioBufferInput *audioBufferInput READ audioBufferInput WRITE setAudioBufferInput
+ NOTIFY audioBufferInputChanged)
Q_PROPERTY(QAudioOutput *audioOutput READ audioOutput WRITE setAudioOutput NOTIFY audioOutputChanged)
Q_PROPERTY(QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged)
Q_PROPERTY(
QScreenCapture *screenCapture READ screenCapture WRITE setScreenCapture NOTIFY screenCaptureChanged)
Q_PROPERTY(
QWindowCapture *windowCapture READ windowCapture WRITE setWindowCapture NOTIFY windowCaptureChanged)
+ Q_PROPERTY(QVideoFrameInput *videoFrameInput READ videoFrameInput WRITE setVideoFrameInput
+ NOTIFY videoFrameInputChanged)
Q_PROPERTY(QImageCapture *imageCapture READ imageCapture WRITE setImageCapture NOTIFY imageCaptureChanged)
Q_PROPERTY(QMediaRecorder *recorder READ recorder WRITE setRecorder NOTIFY recorderChanged)
Q_PROPERTY(QObject *videoOutput READ videoOutput WRITE setVideoOutput NOTIFY videoOutputChanged)
@@ -41,6 +47,9 @@ public:
QAudioInput *audioInput() const;
void setAudioInput(QAudioInput *input);
+ QAudioBufferInput *audioBufferInput() const;
+ void setAudioBufferInput(QAudioBufferInput *input);
+
QCamera *camera() const;
void setCamera(QCamera *camera);
@@ -53,6 +62,9 @@ public:
QWindowCapture *windowCapture();
void setWindowCapture(QWindowCapture *windowCapture);
+ QVideoFrameInput *videoFrameInput() const;
+ void setVideoFrameInput(QVideoFrameInput *input);
+
QMediaRecorder *recorder();
void setRecorder(QMediaRecorder *recorder);
@@ -69,9 +81,11 @@ public:
Q_SIGNALS:
void audioInputChanged();
+ void audioBufferInputChanged();
void cameraChanged();
void screenCaptureChanged();
void windowCaptureChanged();
+ void videoFrameInputChanged();
void imageCaptureChanged();
void recorderChanged();
void videoOutputChanged();
@@ -80,7 +94,9 @@ Q_SIGNALS:
private:
friend class QPlatformMediaCaptureSession;
- QMediaCaptureSessionPrivate *d_ptr;
+ // ### Qt7: remove unused member
+ QT6_ONLY(void *unused = nullptr;) // for ABI compatibility
+
Q_DISABLE_COPY(QMediaCaptureSession)
Q_DECLARE_PRIVATE(QMediaCaptureSession)
};
diff --git a/src/multimedia/recording/qmediacapturesession_p.h b/src/multimedia/recording/qmediacapturesession_p.h
index 8702c8d2b..cba222993 100644
--- a/src/multimedia/recording/qmediacapturesession_p.h
+++ b/src/multimedia/recording/qmediacapturesession_p.h
@@ -18,19 +18,28 @@
#include <QtMultimedia/qmediacapturesession.h>
#include <QtCore/qpointer.h>
+#include <QtCore/private/qobject_p.h>
QT_BEGIN_NAMESPACE
-class QMediaCaptureSessionPrivate
+class QMediaCaptureSessionPrivate : public QObjectPrivate
{
public:
- QMediaCaptureSession *q = nullptr;
- QPlatformMediaCaptureSession *captureSession = nullptr;
+ static QMediaCaptureSessionPrivate *get(QMediaCaptureSession *session)
+ {
+ return reinterpret_cast<QMediaCaptureSessionPrivate *>(QObjectPrivate::get(session));
+ }
+
+ Q_DECLARE_PUBLIC(QMediaCaptureSession)
+
+ std::unique_ptr<QPlatformMediaCaptureSession> captureSession;
QAudioInput *audioInput = nullptr;
+ QPointer<QAudioBufferInput> audioBufferInput;
QAudioOutput *audioOutput = nullptr;
QPointer<QCamera> camera;
QPointer<QScreenCapture> screenCapture;
QPointer<QWindowCapture> windowCapture;
+ QPointer<QVideoFrameInput> videoFrameInput;
QPointer<QImageCapture> imageCapture;
QPointer<QMediaRecorder> recorder;
QPointer<QVideoSink> videoSink;
diff --git a/src/multimedia/recording/qscreencapture-limitations.qdocinc b/src/multimedia/recording/qscreencapture-limitations.qdocinc
index cac51df02..240a1a389 100644
--- a/src/multimedia/recording/qscreencapture-limitations.qdocinc
+++ b/src/multimedia/recording/qscreencapture-limitations.qdocinc
@@ -1,22 +1,25 @@
-// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
//! [content]
\section1 Screen Capture Limitations
- On Qt 6.5.2 and 6.5.3, the following limitations apply to using \1ScreenCapture:
+ On Qt 6.5.2 and above, the following limitations apply to using \1ScreenCapture:
\list
\li It is only supported with the FFmpeg backend.
- \li It is supported on all desktop platforms, except Linux with Wayland
- compositor, due to Wayland protocol restrictions and limitations.
+ \li It is unsupported on Linux with Wayland compositor, due to Wayland
+ protocol restrictions and limitations.
\li It is not supported on mobile operating systems, except on Android.
There, you might run into performance issues as the class is currently
implemented via QScreen::grabWindow, which is not optimal for the use case.
- \li On Linux, it works with X11, but it has not been tested on embedded.
+ \li On embedded with EGLFS, it has limited functionality. For Qt Quick
+ applications, the class is currently implemented via
+ QQuickWindow::grabWindow, which can cause performance issues.
\li In most cases, we set a screen capture frame rate that equals the screen
refresh rate, except on Windows, where the rate might be flexible.
Such a frame rate (75/120 FPS) might cause performance issues on weak
- CPUs if the captured screen is of 4K resolution.
+ CPUs if the captured screen is of 4K resolution. On EGLFS, the capture
+ frame rate is currently locked to 30 FPS.
\endlist
//! [content]
*/
diff --git a/src/multimedia/recording/qvideoframeinput.cpp b/src/multimedia/recording/qvideoframeinput.cpp
new file mode 100644
index 000000000..509ec9239
--- /dev/null
+++ b/src/multimedia/recording/qvideoframeinput.cpp
@@ -0,0 +1,151 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qvideoframeinput.h"
+#include "qmediaframeinput_p.h"
+#include "qmediainputencoderinterface_p.h"
+#include "qplatformvideoframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFrameInputPrivate : public QMediaFrameInputPrivate
+{
+public:
+ QVideoFrameInputPrivate(QVideoFrameInput *q) : q(q) { }
+
+ bool sendVideoFrame(const QVideoFrame &frame)
+ {
+ return sendMediaFrame([&]() { emit m_platfromVideoFrameInput->newVideoFrame(frame); });
+ }
+
+ void initialize()
+ {
+ m_platfromVideoFrameInput = std::make_unique<QPlatformVideoFrameInput>();
+ addUpdateSignal(m_platfromVideoFrameInput.get(), &QPlatformVideoFrameInput::encoderUpdated);
+ }
+
+ void uninitialize()
+ {
+ m_platfromVideoFrameInput.reset();
+
+ if (captureSession())
+ captureSession()->setVideoFrameInput(nullptr);
+ }
+
+ QPlatformVideoFrameInput *platfromVideoFrameInput() const
+ {
+ return m_platfromVideoFrameInput.get();
+ }
+
+protected:
+ void updateCaptureSessionConnections(QMediaCaptureSession *prevSession,
+ QMediaCaptureSession *newSession) override
+ {
+ if (prevSession)
+ removeUpdateSignal(prevSession, &QMediaCaptureSession::videoOutputChanged);
+
+ if (newSession)
+ addUpdateSignal(newSession, &QMediaCaptureSession::videoOutputChanged);
+ }
+
+ bool checkIfCanSendMediaFrame() const override
+ {
+ if (auto encoderInterface = m_platfromVideoFrameInput->encoderInterface())
+ return encoderInterface->canPushFrame();
+
+ return captureSession()->videoOutput() || captureSession()->videoSink();
+ }
+
+ void emitReadyToSendMediaFrame() override { emit q->readyToSendVideoFrame(); }
+
+private:
+ QVideoFrameInput *q = nullptr;
+ std::unique_ptr<QPlatformVideoFrameInput> m_platfromVideoFrameInput;
+};
+
+/*!
+ \class QVideoFrameInput
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_video
+ \since 6.8
+
+ \brief The QVideoFrameInput class is used for providing custom video frames
+ to \l QMediaRecorder or a video output through \l QMediaCaptureSession.
+
+ \sa QMediaRecorder, QMediaCaptureSession, QVideoSink, QVideoOutput
+*/
+
+/*!
+ Constructs a new QVideoFrameInput object with \a parent.
+*/
+QVideoFrameInput::QVideoFrameInput(QObject *parent)
+ : QObject(*new QVideoFrameInputPrivate(this), parent)
+{
+ Q_D(QVideoFrameInput);
+ d->initialize();
+}
+
+/*!
+ Destroys the object.
+ */
+QVideoFrameInput::~QVideoFrameInput()
+{
+ Q_D(QVideoFrameInput);
+ d->uninitialize();
+}
+
+/*!
+ Sends \l QVideoFrame to \l QMediaRecorder or a video output
+ through \l QMediaCaptureSession.
+
+ Returns \c true if the specified \a frame has been sent successfully
+ to the destination. Returns \c false, if the frame hasn't been sent,
+ which can happen if the instance is not assigned to
+ \l QMediaCaptureSession, the session doesn't have video outputs or
+ a media recorder, the media recorder is not started or its queue is full.
+ The signal \l readyToSendVideoFrame will be sent as soon as
+ the destination is able to handle a new frame.
+*/
+bool QVideoFrameInput::sendVideoFrame(const QVideoFrame &frame)
+{
+ Q_D(QVideoFrameInput);
+ return d->sendVideoFrame(frame);
+}
+
+/*!
+ Returns the capture session this video frame input is connected to, or
+ a \c nullptr if the video frame input is not connected to a capture session.
+
+ Use QMediaCaptureSession::setVideoFrameInput() to connect
+ the video frame input to a session.
+*/
+QMediaCaptureSession *QVideoFrameInput::captureSession() const
+{
+ Q_D(const QVideoFrameInput);
+ return d->captureSession();
+}
+
+void QVideoFrameInput::setCaptureSession(QMediaCaptureSession *captureSession)
+{
+ Q_D(QVideoFrameInput);
+ d->setCaptureSession(captureSession);
+}
+
+QPlatformVideoFrameInput *QVideoFrameInput::platformVideoFrameInput() const
+{
+ Q_D(const QVideoFrameInput);
+ return d->platfromVideoFrameInput();
+}
+
+/*!
+ \fn void QVideoFrameInput::readyToSendVideoFrame()
+
+ Signals that a new frame can be sent to the video frame input.
+ After receiving the signal, if you have frames to be sent, invoke \l sendVideoFrame
+ once or in a loop until it returns \c false.
+
+ \sa sendVideoFrame()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/recording/qvideoframeinput.h b/src/multimedia/recording/qvideoframeinput.h
new file mode 100644
index 000000000..6617b051f
--- /dev/null
+++ b/src/multimedia/recording/qvideoframeinput.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QVIDEOFRAMEINPUT_H
+#define QVIDEOFRAMEINPUT_H
+
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtMultimedia/qvideoframe.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformVideoFrameInput;
+class QVideoFrameInputPrivate;
+class QMediaCaptureSession;
+
+class Q_MULTIMEDIA_EXPORT QVideoFrameInput : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QVideoFrameInput(QObject *parent = nullptr);
+
+ ~QVideoFrameInput() override;
+
+ bool sendVideoFrame(const QVideoFrame &frame);
+
+ QMediaCaptureSession *captureSession() const;
+
+Q_SIGNALS:
+ void readyToSendVideoFrame();
+
+private:
+ void setCaptureSession(QMediaCaptureSession *captureSession);
+
+ QPlatformVideoFrameInput *platformVideoFrameInput() const;
+
+ friend class QMediaCaptureSession;
+ Q_DISABLE_COPY(QVideoFrameInput)
+ Q_DECLARE_PRIVATE(QVideoFrameInput)
+};
+
+QT_END_NAMESPACE
+
+#endif // QVIDEOFRAMEINPUT_H
diff --git a/src/multimedia/video/qabstractvideobuffer_p.h b/src/multimedia/video/qabstractvideobuffer_p.h
index 2004e25f7..2824ab7ac 100644
--- a/src/multimedia/video/qabstractvideobuffer_p.h
+++ b/src/multimedia/video/qabstractvideobuffer_p.h
@@ -55,7 +55,6 @@ public:
int size[4] = {};
};
- virtual QVideoFrame::MapMode mapMode() const = 0;
virtual MapData map(QVideoFrame::MapMode mode) = 0;
virtual void unmap() = 0;
@@ -64,7 +63,6 @@ public:
virtual QMatrix4x4 externalTextureMatrix() const { return {}; }
- virtual QByteArray underlyingByteArray(int /*plane*/) const { return {}; }
protected:
QVideoFrame::HandleType m_type;
QRhi *m_rhi = nullptr;
diff --git a/src/multimedia/video/qimagevideobuffer.cpp b/src/multimedia/video/qimagevideobuffer.cpp
index bc825004e..6142ec322 100644
--- a/src/multimedia/video/qimagevideobuffer.cpp
+++ b/src/multimedia/video/qimagevideobuffer.cpp
@@ -56,11 +56,6 @@ QImageVideoBuffer::QImageVideoBuffer(QImage image)
{
}
-QVideoFrame::MapMode QImageVideoBuffer::mapMode() const
-{
- return m_mapMode;
-}
-
QAbstractVideoBuffer::MapData QImageVideoBuffer::map(QVideoFrame::MapMode mode)
{
MapData mapData;
diff --git a/src/multimedia/video/qimagevideobuffer_p.h b/src/multimedia/video/qimagevideobuffer_p.h
index e5467563a..94841f87a 100644
--- a/src/multimedia/video/qimagevideobuffer_p.h
+++ b/src/multimedia/video/qimagevideobuffer_p.h
@@ -25,8 +25,6 @@ class Q_MULTIMEDIA_EXPORT QImageVideoBuffer : public QAbstractVideoBuffer
public:
QImageVideoBuffer(QImage image);
- QVideoFrame::MapMode mapMode() const override;
-
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override;
diff --git a/src/multimedia/video/qmemoryvideobuffer.cpp b/src/multimedia/video/qmemoryvideobuffer.cpp
index bcbbe7e59..bc7ec9a95 100644
--- a/src/multimedia/video/qmemoryvideobuffer.cpp
+++ b/src/multimedia/video/qmemoryvideobuffer.cpp
@@ -32,14 +32,6 @@ QMemoryVideoBuffer::~QMemoryVideoBuffer() = default;
/*!
\reimp
*/
-QVideoFrame::MapMode QMemoryVideoBuffer::mapMode() const
-{
- return m_mapMode;
-}
-
-/*!
- \reimp
-*/
QAbstractVideoBuffer::MapData QMemoryVideoBuffer::map(QVideoFrame::MapMode mode)
{
MapData mapData;
@@ -68,12 +60,4 @@ void QMemoryVideoBuffer::unmap()
m_mapMode = QVideoFrame::NotMapped;
}
-/*!
- \reimp
-*/
-QByteArray QMemoryVideoBuffer::underlyingByteArray(int plane) const
-{
- return plane == 0 ? m_data : QByteArray{};
-}
-
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qmemoryvideobuffer_p.h b/src/multimedia/video/qmemoryvideobuffer_p.h
index ec97abd4f..5ee5b075b 100644
--- a/src/multimedia/video/qmemoryvideobuffer_p.h
+++ b/src/multimedia/video/qmemoryvideobuffer_p.h
@@ -25,12 +25,9 @@ public:
QMemoryVideoBuffer(QByteArray data, int bytesPerLine);
~QMemoryVideoBuffer();
- QVideoFrame::MapMode mapMode() const override;
-
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override;
- QByteArray underlyingByteArray(int plane) const override;
private:
int m_bytesPerLine = 0;
QVideoFrame::MapMode m_mapMode = QVideoFrame::NotMapped;
diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp
index d30017dab..45b3ad85d 100644
--- a/src/multimedia/video/qvideoframe.cpp
+++ b/src/multimedia/video/qvideoframe.cpp
@@ -281,7 +281,7 @@ int QVideoFrame::height() const
bool QVideoFrame::isMapped() const
{
- return d && d->buffer && d->buffer->mapMode() != QVideoFrame::NotMapped;
+ return d && d->mapMode != QVideoFrame::NotMapped;
}
/*!
@@ -300,7 +300,7 @@ bool QVideoFrame::isMapped() const
*/
bool QVideoFrame::isWritable() const
{
- return d && d->buffer && (d->buffer->mapMode() & QVideoFrame::WriteOnly);
+ return d && (d->mapMode & QVideoFrame::WriteOnly);
}
/*!
@@ -316,7 +316,7 @@ bool QVideoFrame::isWritable() const
*/
bool QVideoFrame::isReadable() const
{
- return d && d->buffer && (d->buffer->mapMode() & QVideoFrame::ReadOnly);
+ return d && (d->mapMode & QVideoFrame::ReadOnly);
}
/*!
@@ -326,7 +326,7 @@ bool QVideoFrame::isReadable() const
*/
QVideoFrame::MapMode QVideoFrame::mapMode() const
{
- return (d && d->buffer) ? d->buffer->mapMode() : QVideoFrame::NotMapped;
+ return d ? d->mapMode : QVideoFrame::NotMapped;
}
/*!
@@ -371,8 +371,7 @@ bool QVideoFrame::map(QVideoFrame::MapMode mode)
if (d->mappedCount > 0) {
//it's allowed to map the video frame multiple times in read only mode
- if (d->buffer->mapMode() == QVideoFrame::ReadOnly
- && mode == QVideoFrame::ReadOnly) {
+ if (d->mapMode == QVideoFrame::ReadOnly && mode == QVideoFrame::ReadOnly) {
d->mappedCount++;
return true;
}
@@ -389,6 +388,8 @@ bool QVideoFrame::map(QVideoFrame::MapMode mode)
if (d->mapData.nPlanes == 0)
return false;
+ d->mapMode = mode;
+
if (d->mapData.nPlanes == 1) {
auto pixelFmt = d->format.pixelFormat();
// If the plane count is 1 derive the additional planes for planar formats.
@@ -509,6 +510,7 @@ void QVideoFrame::unmap()
if (d->mappedCount == 0) {
d->mapData = {};
+ d->mapMode = QVideoFrame::NotMapped;
d->buffer->unmap();
}
}
@@ -713,6 +715,23 @@ bool QVideoFrame::mirrored() const
}
/*!
+ Sets the frame \a rate of a video stream in frames per second.
+*/
+void QVideoFrame::setStreamFrameRate(qreal rate)
+{
+ if (d)
+ d->format.setStreamFrameRate(rate);
+}
+
+/*!
+ Returns the frame rate of a video stream in frames per second.
+*/
+qreal QVideoFrame::streamFrameRate() const
+{
+ return d ? d->format.streamFrameRate() : 0.;
+}
+
+/*!
Based on the pixel format converts current video frame to image.
\since 5.15
*/
diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h
index a306162e8..5a2cf177d 100644
--- a/src/multimedia/video/qvideoframe.h
+++ b/src/multimedia/video/qvideoframe.h
@@ -114,6 +114,9 @@ public:
void setMirrored(bool);
bool mirrored() const;
+ void setStreamFrameRate(qreal rate);
+ qreal streamFrameRate() const;
+
QImage toImage() const;
struct PaintOptions {
diff --git a/src/multimedia/video/qvideoframe_p.h b/src/multimedia/video/qvideoframe_p.h
index cb8b7b747..06793871a 100644
--- a/src/multimedia/video/qvideoframe_p.h
+++ b/src/multimedia/video/qvideoframe_p.h
@@ -44,6 +44,7 @@ public:
qint64 startTime = -1;
qint64 endTime = -1;
QAbstractVideoBuffer::MapData mapData;
+ QVideoFrame::MapMode mapMode = QVideoFrame::NotMapped;
QVideoFrameFormat format;
std::unique_ptr<QAbstractVideoBuffer> buffer;
int mappedCount = 0;
diff --git a/src/multimedia/video/qvideoframeconversionhelper.cpp b/src/multimedia/video/qvideoframeconversionhelper.cpp
index 1b570b74f..d3f2b0403 100644
--- a/src/multimedia/video/qvideoframeconversionhelper.cpp
+++ b/src/multimedia/video/qvideoframeconversionhelper.cpp
@@ -34,31 +34,30 @@ static inline void planarYUV420_to_ARGB32(const uchar *y, int yStride,
int width, int height)
{
height &= ~1;
- quint32 *rgb0 = rgb;
- quint32 *rgb1 = rgb + width;
- for (int j = 0; j < height; j += 2) {
+ for (int j = 0; j + 1 < height; j += 2) {
const uchar *lineY0 = y;
const uchar *lineY1 = y + yStride;
const uchar *lineU = u;
const uchar *lineV = v;
- for (int i = 0; i < width; i += 2) {
+ quint32 *rgb0 = rgb;
+ quint32 *rgb1 = rgb + width;
+ for (int i = 0; i + 1 < width; i += 2) {
EXPAND_UV(*lineU, *lineV);
lineU += uvPixelStride;
lineV += uvPixelStride;
- *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
- *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
- *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu);
- *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu);
+ rgb0[i] = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ rgb0[i + 1] = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ rgb1[i] = qYUVToARGB32(*lineY1++, rv, guv, bu);
+ rgb1[i + 1] = qYUVToARGB32(*lineY1++, rv, guv, bu);
}
y += yStride << 1; // stride * 2
u += uStride;
v += vStride;
- rgb0 += width;
- rgb1 += width;
+ rgb += width << 1; // width * 2
}
}
@@ -69,31 +68,27 @@ static inline void planarYUV422_to_ARGB32(const uchar *y, int yStride,
quint32 *rgb,
int width, int height)
{
- quint32 *rgb0 = rgb;
-
for (int j = 0; j < height; ++j) {
const uchar *lineY0 = y;
const uchar *lineU = u;
const uchar *lineV = v;
- for (int i = 0; i < width; i += 2) {
+ for (int i = 0; i + 1 < width; i += 2) {
EXPAND_UV(*lineU, *lineV);
lineU += uvPixelStride;
lineV += uvPixelStride;
- *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
- *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ rgb[i] = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ rgb[i+1] = qYUVToARGB32(*lineY0++, rv, guv, bu);
}
y += yStride; // stride * 2
u += uStride;
v += vStride;
- rgb0 += width;
+ rgb += width;
}
}
-
-
static void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_TRIPLANAR(frame)
@@ -187,8 +182,7 @@ static void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, ucha
for (int i = 0; i < height; ++i) {
const uchar *lineSrc = src;
-
- for (int j = 0; j < width; j += 2) {
+ for (int j = 0; j + 1 < width; j += 2) {
int u = *lineSrc++;
int y0 = *lineSrc++;
int v = *lineSrc++;
@@ -196,11 +190,12 @@ static void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, ucha
EXPAND_UV(u, v);
- *rgb++ = qYUVToARGB32(y0, rv, guv, bu);
- *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
+ rgb[j] = qYUVToARGB32(y0, rv, guv, bu);
+ rgb[j+1] = qYUVToARGB32(y1, rv, guv, bu);
}
src += stride;
+ rgb += width;
}
}
@@ -213,8 +208,7 @@ static void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, ucha
for (int i = 0; i < height; ++i) {
const uchar *lineSrc = src;
-
- for (int j = 0; j < width; j += 2) {
+ for (int j = 0; j + 1 < width; j += 2) {
int y0 = *lineSrc++;
int u = *lineSrc++;
int y1 = *lineSrc++;
@@ -222,11 +216,12 @@ static void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, ucha
EXPAND_UV(u, v);
- *rgb++ = qYUVToARGB32(y0, rv, guv, bu);
- *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
+ rgb[j] = qYUVToARGB32(y0, rv, guv, bu);
+ rgb[j+1] = qYUVToARGB32(y1, rv, guv, bu);
}
src += stride;
+ rgb += width;
}
}
@@ -376,23 +371,24 @@ static void QT_FASTCALL qt_convert_premultiplied_to_ARGB32(const QVideoFrame &fr
}
static inline void planarYUV420_16bit_to_ARGB32(const uchar *y, int yStride,
- const uchar *u, int uStride,
- const uchar *v, int vStride,
- int uvPixelStride,
- quint32 *rgb,
- int width, int height)
+ const uchar *u, int uStride,
+ const uchar *v, int vStride,
+ int uvPixelStride,
+ quint32 *rgb,
+ int width, int height)
{
height &= ~1;
- quint32 *rgb0 = rgb;
- quint32 *rgb1 = rgb + width;
- for (int j = 0; j < height; j += 2) {
+ for (int j = 0; j + 1 < height; j += 2) {
const uchar *lineY0 = y;
const uchar *lineY1 = y + yStride;
const uchar *lineU = u;
const uchar *lineV = v;
- for (int i = 0; i < width; i += 2) {
+ quint32 *rgb0 = rgb;
+ quint32 *rgb1 = rgb + width;
+
+ for (int i = 0; i + 1 < width; i += 2) {
EXPAND_UV(*lineU, *lineV);
lineU += uvPixelStride;
lineV += uvPixelStride;
@@ -410,11 +406,11 @@ static inline void planarYUV420_16bit_to_ARGB32(const uchar *y, int yStride,
y += yStride << 1; // stride * 2
u += uStride;
v += vStride;
- rgb0 += width;
- rgb1 += width;
+ rgb += width * 2;
}
}
+
static void QT_FASTCALL qt_convert_P016_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_BIPLANAR(frame)
diff --git a/src/multimedia/video/qvideoframeconverter.cpp b/src/multimedia/video/qvideoframeconverter.cpp
index 82e0a0af5..ad1e96d79 100644
--- a/src/multimedia/video/qvideoframeconverter.cpp
+++ b/src/multimedia/video/qvideoframeconverter.cpp
@@ -286,7 +286,8 @@ static QImage convertCPU(const QVideoFrame &frame, QtVideo::Rotation rotation, b
}
}
-QImage qImageFromVideoFrame(const QVideoFrame &frame, QtVideo::Rotation rotation, bool mirrorX, bool mirrorY)
+QImage qImageFromVideoFrame(const QVideoFrame &frame, QtVideo::Rotation rotation, bool mirrorX,
+ bool mirrorY, bool forceCpu)
{
#ifdef Q_OS_DARWIN
QMacAutoReleasePool releasePool;
@@ -310,6 +311,9 @@ QImage qImageFromVideoFrame(const QVideoFrame &frame, QtVideo::Rotation rotation
if (frame.pixelFormat() == QVideoFrameFormat::Format_Jpeg)
return convertJPEG(frame, rotation, mirrorX, mirrorY);
+ if (forceCpu) // For test purposes
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+
QRhi *rhi = nullptr;
if (frame.videoBuffer())
diff --git a/src/multimedia/video/qvideoframeconverter_p.h b/src/multimedia/video/qvideoframeconverter_p.h
index d22491f66..ad6cea9e4 100644
--- a/src/multimedia/video/qvideoframeconverter_p.h
+++ b/src/multimedia/video/qvideoframeconverter_p.h
@@ -19,7 +19,9 @@
QT_BEGIN_NAMESPACE
-Q_MULTIMEDIA_EXPORT QImage qImageFromVideoFrame(const QVideoFrame &frame, QtVideo::Rotation rotation = QtVideo::Rotation::None, bool mirrorX = false, bool mirrorY = false);
+Q_MULTIMEDIA_EXPORT QImage
+qImageFromVideoFrame(const QVideoFrame &frame, QtVideo::Rotation rotation = QtVideo::Rotation::None,
+ bool mirrorX = false, bool mirrorY = false, bool forceCpu = false);
/**
* @brief Maps the video frame and returns an image having a shared ownership for the video frame
diff --git a/src/plugins/multimedia/android/common/qandroidvideooutput.cpp b/src/plugins/multimedia/android/common/qandroidvideooutput.cpp
index 5a4eebf51..c1ba2c1e9 100644
--- a/src/plugins/multimedia/android/common/qandroidvideooutput.cpp
+++ b/src/plugins/multimedia/android/common/qandroidvideooutput.cpp
@@ -62,8 +62,6 @@ public:
, m_tex(std::move(tex))
{}
- QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
-
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override
@@ -95,7 +93,7 @@ public:
{
return m_atvb.mapTextures(rhi);
}
- QVideoFrame::MapMode mapMode() const override { return QVideoFrame::NotMapped; }
+
MapData map(QVideoFrame::MapMode) override { return {}; }
void unmap() override {}
diff --git a/src/plugins/multimedia/darwin/avfvideobuffer_p.h b/src/plugins/multimedia/darwin/avfvideobuffer_p.h
index 69d7b7f45..1ca19b027 100644
--- a/src/plugins/multimedia/darwin/avfvideobuffer_p.h
+++ b/src/plugins/multimedia/darwin/avfvideobuffer_p.h
@@ -37,7 +37,6 @@ public:
AVFVideoBuffer(AVFVideoSinkInterface *sink, CVImageBufferRef buffer);
~AVFVideoBuffer();
- QVideoFrame::MapMode mapMode() const { return m_mode; }
MapData map(QVideoFrame::MapMode mode);
void unmap();
diff --git a/src/plugins/multimedia/darwin/mediaplayer/avfmediaplayer.mm b/src/plugins/multimedia/darwin/mediaplayer/avfmediaplayer.mm
index b6d9622ac..964964a8e 100644
--- a/src/plugins/multimedia/darwin/mediaplayer/avfmediaplayer.mm
+++ b/src/plugins/multimedia/darwin/mediaplayer/avfmediaplayer.mm
@@ -12,6 +12,7 @@
#include <qpointer.h>
#include <QFileInfo>
#include <QtCore/qmath.h>
+#include <QtCore/qmutex.h>
#import <AVFoundation/AVFoundation.h>
@@ -59,6 +60,12 @@ static void *AVFMediaPlayerObserverCurrentItemDurationObservationContext = &AVFM
- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest;
@end
+#ifdef Q_OS_IOS
+// Alas, no such thing as 'class variable', hence globals:
+static unsigned sessionActivationCount;
+static QMutex sessionMutex;
+#endif // Q_OS_IOS
+
@implementation AVFMediaPlayerObserver
{
@private
@@ -70,10 +77,39 @@ static void *AVFMediaPlayerObserverCurrentItemDurationObservationContext = &AVFM
BOOL m_bufferIsLikelyToKeepUp;
NSData *m_data;
NSString *m_mimeType;
+#ifdef Q_OS_IOS
+ BOOL m_activated;
+#endif
}
@synthesize m_player, m_playerItem, m_playerLayer, m_session;
+#ifdef Q_OS_IOS
+- (void)setSessionActive:(BOOL)active
+{
+ const QMutexLocker lock(&sessionMutex);
+ if (active) {
+ // Don't count the same player twice if already activated,
+ // unless it tried to deactivate first:
+ if (m_activated)
+ return;
+ if (!sessionActivationCount)
+ [AVAudioSession.sharedInstance setActive:YES error:nil];
+ ++sessionActivationCount;
+ m_activated = YES;
+ } else {
+ if (!sessionActivationCount || !m_activated) {
+ qWarning("Unbalanced audio session deactivation, ignoring.");
+ return;
+ }
+ --sessionActivationCount;
+ m_activated = NO;
+ if (!sessionActivationCount)
+ [AVAudioSession.sharedInstance setActive:NO error:nil];
+ }
+}
+#endif // Q_OS_IOS
+
- (AVFMediaPlayerObserver *) initWithMediaPlayerSession:(AVFMediaPlayer *)session
{
if (!(self = [super init]))
@@ -159,7 +195,7 @@ static void *AVFMediaPlayerObserverCurrentItemDurationObservationContext = &AVFM
if (m_playerLayer)
m_playerLayer.player = nil;
#if defined(Q_OS_IOS)
- [[AVAudioSession sharedInstance] setActive:NO error:nil];
+ [self setSessionActive:NO];
#endif
}
@@ -279,7 +315,7 @@ static void *AVFMediaPlayerObserverCurrentItemDurationObservationContext = &AVFM
context:AVFMediaPlayerObserverCurrentItemDurationObservationContext];
#if defined(Q_OS_IOS)
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
- [[AVAudioSession sharedInstance] setActive:YES error:nil];
+ [self setSessionActive:YES];
#endif
}
diff --git a/src/plugins/multimedia/ffmpeg/CMakeLists.txt b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
index b18cea002..c6ab93273 100644
--- a/src/plugins/multimedia/ffmpeg/CMakeLists.txt
+++ b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
@@ -37,7 +37,6 @@ qt_internal_add_plugin(QFFmpegMediaPlugin
qffmpegencodingformatcontext.cpp qffmpegencodingformatcontext_p.h
qgrabwindowsurfacecapture.cpp qgrabwindowsurfacecapture_p.h
qffmpegsurfacecapturegrabber.cpp qffmpegsurfacecapturegrabber_p.h
- qffmpegsymbolsresolve_p.h
qffmpegplaybackengine.cpp qffmpegplaybackengine_p.h
playbackengine/qffmpegplaybackenginedefs_p.h
@@ -67,6 +66,10 @@ qt_internal_add_plugin(QFFmpegMediaPlugin
recordingengine/qffmpegmuxer.cpp
recordingengine/qffmpegrecordingengine_p.h
recordingengine/qffmpegrecordingengine.cpp
+ recordingengine/qffmpegencodinginitializer_p.h
+ recordingengine/qffmpegencodinginitializer.cpp
+ recordingengine/qffmpegrecordingengineutils_p.h
+ recordingengine/qffmpegrecordingengineutils.cpp
recordingengine/qffmpegvideoencoder_p.h
recordingengine/qffmpegvideoencoder.cpp
recordingengine/qffmpegvideoencoderutils_p.h
@@ -81,75 +84,39 @@ qt_internal_add_plugin(QFFmpegMediaPlugin
Qt::CorePrivate
)
-if(DYNAMIC_RESOLVE_OPENSSL_SYMBOLS)
- if(NOT OPENSSL_INCLUDE_DIR AND OPENSSL_ROOT_DIR)
- set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include")
- endif()
-endif()
-
-qt_internal_extend_target(QFFmpegMediaPlugin CONDITION DYNAMIC_RESOLVE_OPENSSL_SYMBOLS
- SOURCES
- qffmpegopensslsymbols.cpp
- INCLUDE_DIRECTORIES
- ${OPENSSL_INCLUDE_DIR}
-)
+if (LINUX OR ANDROID)
+ # We have 2 options: link shared stubs to QFFmpegMediaPlugin vs
+ # static compilation of the needed stubs to the FFmpeg plugin.
+ # Currently, we chose the second option so that user could trivially
+ # remove the FFmpeg libs we ship.
+ # Set QT_LINK_STUBS_TO_FFMPEG_PLUGIN = TRUE to change the behavior.
-if (ENABLE_DYNAMIC_RESOLVE_VAAPI_SYMBOLS)
- if (QT_FEATURE_vaapi AND NOT DYNAMIC_RESOLVE_VAAPI_SYMBOLS)
- if (NOT FFMPEG_SHARED_LIBRARIES)
- message(WARNING
- "QT_FEATURE_vaapi is found but statically built FFmpeg doesn't include vaapi,"
- "however dynamic symbols resolve is possible.")
- endif()
+ # set(QT_LINK_STUBS_TO_FFMPEG_PLUGIN TRUE)
- set(DYNAMIC_RESOLVE_VAAPI_SYMBOLS TRUE CACHE INTERNAL "")
- elseif (NOT QT_FEATURE_vaapi AND DYNAMIC_RESOLVE_VAAPI_SYMBOLS)
-
- message(FATAL_ERROR
- "QT_FEATURE_vaapi is not found "
- "but FFmpeg includes VAAPI and dynamic symbols resolve is enabled.")
- endif()
+ include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtAddFFmpegStubs.cmake")
+ qt_internal_multimedia_add_ffmpeg_stubs()
endif()
-qt_internal_extend_target(QFFmpegMediaPlugin
- CONDITION
- DYNAMIC_RESOLVE_OPENSSL_SYMBOLS OR DYNAMIC_RESOLVE_VAAPI_SYMBOLS
- SOURCES
- qffmpegsymbolsresolveutils.cpp qffmpegsymbolsresolveutils_p.h
-)
-
-function (__propagate_to_compile_definitions VAR)
- if (${VAR})
- target_compile_definitions(QFFmpegMediaPlugin PRIVATE ${VAR})
- endif()
-endfunction()
-__propagate_to_compile_definitions(DYNAMIC_RESOLVE_OPENSSL_SYMBOLS)
-__propagate_to_compile_definitions(DYNAMIC_RESOLVE_VAAPI_SYMBOLS)
-__propagate_to_compile_definitions(DYNAMIC_RESOLVE_VA_DRM_SYMBOLS)
-__propagate_to_compile_definitions(DYNAMIC_RESOLVE_VA_X11_SYMBOLS)
-
-qt_internal_extend_target(QFFmpegMediaPlugin CONDITION DYNAMIC_RESOLVE_VAAPI_SYMBOLS
- SOURCES
- qffmpegvaapisymbols.cpp
- INCLUDE_DIRECTORIES
- "$<TARGET_PROPERTY:VAAPI::VAAPI,INTERFACE_INCLUDE_DIRECTORIES>"
-)
+if (QT_FEATURE_vaapi)
+ qt_internal_extend_target(QFFmpegMediaPlugin
+ SOURCES
+ qffmpeghwaccel_vaapi.cpp qffmpeghwaccel_vaapi_p.h
+ NO_UNITY_BUILD_SOURCES
+ # Conflicts with macros defined in X11.h, and Xlib.h
+ qffmpeghwaccel_vaapi.cpp
+ LIBRARIES
+ EGL::EGL
+ )
-qt_internal_extend_target(QFFmpegMediaPlugin
- CONDITION NOT DYNAMIC_RESOLVE_VAAPI_SYMBOLS AND QT_FEATURE_vaapi
- LIBRARIES VAAPI::VAAPI
-)
+ list(FIND FFMPEG_STUBS "va" va_stub_index)
+ if (NOT QT_LINK_STUBS_TO_FFMPEG_PLUGIN AND (FFMPEG_SHARED_LIBRARIES OR ${va_stub_index} EQUAL -1))
+ target_compile_definitions(QFFmpegMediaPlugin PRIVATE Q_FFMPEG_PLUGIN_STUBS_ONLY)
+ qt_internal_multimedia_find_vaapi_soversion()
+ qt_internal_multimedia_add_private_stub_to_plugin("va")
+ endif()
+endif()
-qt_internal_extend_target(QFFmpegMediaPlugin CONDITION QT_FEATURE_vaapi
- SOURCES
- qffmpeghwaccel_vaapi.cpp qffmpeghwaccel_vaapi_p.h
- NO_UNITY_BUILD_SOURCES
- # Conflicts with macros defined in X11.h, and Xlib.h
- qffmpeghwaccel_vaapi.cpp
- LIBRARIES
- EGL::EGL
-)
qt_internal_extend_target(QFFmpegMediaPlugin CONDITION APPLE
SOURCES
@@ -280,13 +247,14 @@ endif()
# TODO: get libs from FindFFmpeg.cmake
set(ffmpeg_libs FFmpeg::avformat FFmpeg::avcodec FFmpeg::swresample FFmpeg::swscale FFmpeg::avutil)
-if (QT_DEPLOY_FFMPEG AND NOT BUILD_SHARED_LIBS)
+if (QT_DEPLOY_FFMPEG AND NOT BUILD_SHARED_LIBS AND NOT UIKIT)
message(FATAL_ERROR "QT_DEPLOY_FFMPEG is not implemented yet for static builds")
endif()
-if (QT_DEPLOY_FFMPEG AND FFMPEG_SHARED_LIBRARIES AND BUILD_SHARED_LIBS)
+if (QT_DEPLOY_FFMPEG AND FFMPEG_SHARED_LIBRARIES AND (BUILD_SHARED_LIBS OR UIKIT))
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/QtDeployFFmpeg.cmake")
qt_internal_multimedia_copy_or_install_ffmpeg()
endif()
qt_internal_extend_target(QFFmpegMediaPlugin LIBRARIES ${ffmpeg_libs})
+
diff --git a/src/plugins/multimedia/ffmpeg/cmake/QtAddFFmpegStubs.cmake b/src/plugins/multimedia/ffmpeg/cmake/QtAddFFmpegStubs.cmake
new file mode 100644
index 000000000..5778ae4d2
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/cmake/QtAddFFmpegStubs.cmake
@@ -0,0 +1,199 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Utilities
+
+function(qt_internal_multimedia_find_ffmpeg_stubs)
+ foreach (stub ${FFMPEG_STUBS})
+ if (${stub} MATCHES ${vaapi_regex})
+ set(ffmpeg_has_vaapi TRUE PARENT_SCOPE)
+ elseif (${stub} MATCHES ${openssl_regex})
+ set(ffmpeg_has_openssl TRUE PARENT_SCOPE)
+ else()
+ set(unknown_ffmpeg_stubs
+ ${unknown_ffmpeg_stubs} ${stub} PARENT_SCOPE)
+ endif()
+ endforeach()
+endfunction()
+
+function(qt_internal_multimedia_check_ffmpeg_stubs_configuration)
+ if (NOT LINUX AND NOT ANDROID)
+ message(FATAL_ERROR "Currently, stubs are supported on Linux and Android")
+ endif()
+
+ if (unknown_ffmpeg_stubs)
+ message(FATAL_ERROR "Unknown ffmpeg stubs: ${unknown_ffmpeg_stubs}")
+ endif()
+
+ if (BUILD_SHARED_LIBS AND FFMPEG_SHARED_LIBRARIES AND FFMPEG_STUBS AND NOT QT_DEPLOY_FFMPEG)
+ message(FATAL_ERROR
+ "FFmpeg stubs have been found but QT_DEPLOY_FFMPEG is not specified. "
+ "Set -DQT_DEPLOY_FFMPEG=TRUE to continue.")
+ endif()
+
+ if (ffmpeg_has_vaapi AND NOT QT_FEATURE_vaapi)
+ message(FATAL_ERROR
+ "QT_FEATURE_vaapi is OFF but FFmpeg includes VAAPI.")
+ elseif (NOT ffmpeg_has_vaapi AND QT_FEATURE_vaapi)
+ message(WARNING
+ "QT_FEATURE_vaapi is ON "
+ "but FFmpeg includes VAAPI and dynamic symbols resolve is enabled.")
+ elseif(ffmpeg_has_vaapi AND NOT VAAPI_SUFFIX)
+ message(FATAL_ERROR "Cannot find VAAPI_SUFFIX, fix FindVAAPI.cmake")
+ elseif (ffmpeg_has_vaapi AND "${VAAPI_SUFFIX}" MATCHES "^1\\.32.*")
+ # drop the ancient vaapi version to avoid ABI problems
+ message(FATAL_ERROR "VAAPI ${VAAPI_SUFFIX} is not supported")
+ endif()
+
+ if (ffmpeg_has_openssl AND NOT QT_FEATURE_openssl)
+ message(FATAL_ERROR
+ "QT_FEATURE_openssl is OFF but FFmpeg includes OpenSSL.")
+ endif()
+endfunction()
+
+macro(qt_internal_multimedia_find_vaapi_soversion)
+ string(REGEX MATCH "^[0-9]+" va_soversion "${VAAPI_SUFFIX}")
+
+ set(va-drm_soversion "${va_soversion}")
+ set(va-x11_soversion "${va_soversion}")
+endmacro()
+
+macro(qt_internal_multimedia_find_openssl_soversion)
+ # Update OpenSSL variables since OPENSSL_SSL_LIBRARY is not propagated to this place in some cases.
+ qt_find_package(OpenSSL)
+
+ if (NOT OPENSSL_INCLUDE_DIR AND OPENSSL_ROOT_DIR)
+ set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include")
+ endif()
+
+ if (LINUX)
+ if (NOT OPENSSL_SSL_LIBRARY)
+ message(FATAL_ERROR "OPENSSL_SSL_LIBRARY is not found")
+ endif()
+
+ get_filename_component(ssl_lib_realpath "${OPENSSL_SSL_LIBRARY}" REALPATH)
+ string(REGEX MATCH "[0-9]+(\\.[0-9]+)*$" ssl_soversion "${ssl_lib_realpath}")
+ string(REGEX REPLACE "^3(\\..*|$)" "3" ssl_soversion "${ssl_soversion}")
+ endif()
+
+ #TODO: enhance finding openssl version and throw an error if it's not found.
+
+ set(crypto_soversion "${ssl_soversion}")
+endmacro()
+
+function(qt_internal_multimedia_set_stub_version_script stub stub_target)
+ if ("${stub}" MATCHES "${openssl_regex}")
+ if ("${ssl_soversion}" STREQUAL "3" OR
+ (NOT ssl_soversion AND "${OPENSSL_VERSION}" MATCHES "^3\\..*"))
+ # Symbols in OpenSSL 1.* are not versioned.
+ set(file_name "openssl3.ver")
+ endif()
+ elseif("${stub}" STREQUAL "va")
+ set(file_name "va.ver")
+ endif()
+
+ if (file_name)
+ set(version_script "${CMAKE_CURRENT_SOURCE_DIR}/symbolstubs/${file_name}")
+ set_property(TARGET ${stub_target} APPEND_STRING
+ PROPERTY LINK_FLAGS " -Wl,--version-script=${version_script}")
+ set_target_properties(${stub_target} PROPERTIES LINK_DEPENDS ${version_script})
+ source_group("Stubs Version Scripts" FILES ${version_script})
+ endif()
+endfunction()
+
+function(qt_internal_multimedia_set_stub_output stub stub_target)
+ set(output_dir "${QT_BUILD_DIR}/${INSTALL_LIBDIR}")
+
+ set_target_properties(${stub_target} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${output_dir}"
+ LIBRARY_OUTPUT_DIRECTORY "${output_dir}"
+ )
+
+ if (${stub}_soversion)
+ set_target_properties(${stub_target} PROPERTIES
+ VERSION "${${stub}_soversion}"
+ SOVERSION "${${stub}_soversion}")
+ endif()
+
+ qt_apply_rpaths(TARGET ${stub_target} INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH)
+endfunction()
+
+function(qt_internal_multimedia_set_stub_include_directories stub target)
+ qt_internal_extend_target(${target}
+ CONDITION ${stub} MATCHES "${openssl_regex}"
+ INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
+
+ qt_internal_extend_target(${target}
+ CONDITION ${stub} MATCHES "${vaapi_regex}"
+ INCLUDE_DIRECTORIES "${VAAPI_INCLUDE_DIR}")
+endfunction()
+
+function(qt_internal_multimedia_set_stub_symbols_visibility stub stub_target)
+ set_target_properties(${stub_target} PROPERTIES
+ C_VISIBILITY_PRESET hidden
+ CXX_VISIBILITY_PRESET hidden)
+ target_compile_definitions(${stub_target} PRIVATE Q_EXPORT_STUB_SYMBOLS)
+endfunction()
+
+function(qt_internal_multimedia_set_stub_libraries stub stub_target)
+ qt_internal_extend_target(${stub_target} LIBRARIES Qt::Core Qt::MultimediaPrivate)
+
+ if (LINK_STUBS_TO_FFMPEG_PLUGIN AND ${stub} STREQUAL "va")
+ qt_internal_extend_target(QFFmpegMediaPlugin LIBRARIES ${stub_target})
+ endif()
+endfunction()
+
+function(qt_internal_multimedia_define_stub_needed_version stub target)
+ string(TOUPPER ${stub} prefix)
+ string(REPLACE "-" "_" prefix ${prefix})
+
+ target_compile_definitions(${target} PRIVATE
+ "${prefix}_NEEDED_SOVERSION=\"${${stub}_soversion}\"")
+endfunction()
+
+function(qt_internal_multimedia_add_shared_stub stub)
+ set(stub_target "Qt${PROJECT_VERSION_MAJOR}FFmpegStub-${stub}")
+
+ qt_add_library(${stub_target} SHARED "symbolstubs/qffmpegsymbols-${stub}.cpp")
+
+ qt_internal_multimedia_set_stub_include_directories(${stub} ${stub_target})
+ qt_internal_multimedia_set_stub_output(${stub} ${stub_target})
+ qt_internal_multimedia_set_stub_symbols_visibility(${stub} ${stub_target})
+ qt_internal_multimedia_set_stub_version_script(${stub} ${stub_target})
+ qt_internal_multimedia_define_stub_needed_version(${stub} ${stub_target})
+ qt_internal_multimedia_set_stub_libraries(${stub} ${stub_target})
+
+ qt_install(TARGETS ${stub_target} LIBRARY NAMELINK_SKIP)
+endfunction()
+
+function(qt_internal_multimedia_add_private_stub_to_plugin stub)
+ qt_internal_multimedia_set_stub_include_directories(${stub} QFFmpegMediaPlugin)
+ qt_internal_multimedia_define_stub_needed_version(${stub} QFFmpegMediaPlugin)
+ qt_internal_extend_target(QFFmpegMediaPlugin SOURCES "symbolstubs/qffmpegsymbols-${stub}.cpp")
+endfunction()
+
+# Main function
+
+set(vaapi_regex "^(va|va-drm|va-x11)$")
+set(openssl_regex "^(ssl|crypto)$")
+
+function(qt_internal_multimedia_add_ffmpeg_stubs)
+ qt_internal_multimedia_find_ffmpeg_stubs()
+ qt_internal_multimedia_check_ffmpeg_stubs_configuration()
+
+ if (ffmpeg_has_vaapi)
+ qt_internal_multimedia_find_vaapi_soversion()
+ endif()
+
+ if (ffmpeg_has_openssl)
+ qt_internal_multimedia_find_openssl_soversion()
+ endif()
+
+ foreach (stub ${FFMPEG_STUBS})
+ if (FFMPEG_SHARED_LIBRARIES)
+ qt_internal_multimedia_add_shared_stub("${stub}")
+ else()
+ qt_internal_multimedia_add_private_stub_to_plugin("${stub}")
+ endif()
+ endforeach()
+endfunction()
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp
index fbb75dd44..f92f93ddb 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegmediadataholder.cpp
@@ -65,6 +65,25 @@ static int streamOrientation(const AVStream *stream)
return rotation < 0 ? -rotation % 360 : -rotation % 360 + 360;
}
+
+static bool colorTransferSupportsHdr(const AVStream *stream)
+{
+ if (!stream)
+ return false;
+
+ const AVCodecParameters *codecPar = stream->codecpar;
+ if (!codecPar)
+ return false;
+
+ const QVideoFrameFormat::ColorTransfer colorTransfer = fromAvColorTransfer(codecPar->color_trc);
+
+ // Assume that content is using HDR if the color transfer supports high
+ // dynamic range. The video may still not utilize the extended range,
+ // but we can't determine the actual range without decoding frames.
+ return colorTransfer == QVideoFrameFormat::ColorTransfer_ST2084
+ || colorTransfer == QVideoFrameFormat::ColorTransfer_STD_B67;
+}
+
QtVideo::Rotation MediaDataHolder::rotation() const
{
int orientation = m_metaData.value(QMediaMetaData::Orientation).toInt();
@@ -97,6 +116,7 @@ static void insertMediaData(QMediaMetaData &metaData, QPlatformMediaPlayer::Trac
metaData.insert(QMediaMetaData::VideoFrameRate,
qreal(stream->avg_frame_rate.num) / qreal(stream->avg_frame_rate.den));
metaData.insert(QMediaMetaData::Orientation, QVariant::fromValue(streamOrientation(stream)));
+ metaData.insert(QMediaMetaData::HasHdrContent, colorTransferSupportsHdr(stream));
break;
case QPlatformMediaPlayer::AudioStream:
metaData.insert(QMediaMetaData::AudioBitRate, (int)codecPar->bit_rate);
@@ -151,6 +171,10 @@ loadMedia(const QUrl &mediaUrl, QIODevice *stream, const std::shared_ptr<ICancel
constexpr auto NetworkTimeoutUs = "5000000";
av_dict_set(dict, "timeout", NetworkTimeoutUs, 0);
+ const QByteArray protocolWhitelist = qgetenv("QT_FFMPEG_PROTOCOL_WHITELIST");
+ if (!protocolWhitelist.isNull())
+ av_dict_set(dict, "protocol_whitelist", protocolWhitelist.data(), 0);
+
context->interrupt_callback.opaque = cancelToken.get();
context->interrupt_callback.callback = [](void *opaque) {
const auto *cancelToken = static_cast<const ICancelToken *>(opaque);
@@ -189,6 +213,7 @@ loadMedia(const QUrl &mediaUrl, QIODevice *stream, const std::shared_ptr<ICancel
#endif
return context;
}
+
} // namespace
MediaDataHolder::Maybe MediaDataHolder::create(const QUrl &url, QIODevice *stream,
diff --git a/src/plugins/multimedia/ffmpeg/qandroidcamera.cpp b/src/plugins/multimedia/ffmpeg/qandroidcamera.cpp
index bf01a4e30..56725b2bb 100644
--- a/src/plugins/multimedia/ffmpeg/qandroidcamera.cpp
+++ b/src/plugins/multimedia/ffmpeg/qandroidcamera.cpp
@@ -252,7 +252,7 @@ void QAndroidCamera::setActive(bool active)
return;
if (!m_jniCamera.isValid()) {
- emit error(QCamera::CameraError, "No connection to Android Camera2 API");
+ updateError(QCamera::CameraError, QStringLiteral("No connection to Android Camera2 API"));
return;
}
@@ -288,8 +288,8 @@ void QAndroidCamera::setActive(bool active)
if (!canOpen) {
g_qcameras->remove(m_cameraDevice.id());
setState(State::Closed);
- emit error(QCamera::CameraError,
- QString("Failed to start camera: ").append(m_cameraDevice.description()));
+ updateError(QCamera::CameraError,
+ QString("Failed to start camera: ").append(m_cameraDevice.description()));
}
} else {
m_jniCamera.callMethod<void>("stopAndClose");
@@ -316,8 +316,8 @@ void QAndroidCamera::setState(QAndroidCamera::State newState)
m_state = State::Closed;
- emit error(QCamera::CameraError,
- QString("Failed to start Camera %1").arg(m_cameraDevice.description()));
+ updateError(QCamera::CameraError,
+ QString("Failed to start Camera %1").arg(m_cameraDevice.description()));
}
if (m_state == State::Closed && newState == State::WaitingOpen)
@@ -521,10 +521,10 @@ void QAndroidCamera::onCameraDisconnect()
void QAndroidCamera::onCameraError(int reason)
{
- emit error(QCamera::CameraError,
- QString("Capture error with Camera %1. Camera2 Api error code: %2")
- .arg(m_cameraDevice.description())
- .arg(reason));
+ updateError(QCamera::CameraError,
+ QString("Capture error with Camera %1. Camera2 Api error code: %2")
+ .arg(m_cameraDevice.description())
+ .arg(reason));
}
void QAndroidCamera::onSessionActive()
@@ -552,10 +552,10 @@ void QAndroidCamera::onCaptureSessionFailed(int reason, long frameNumber)
{
Q_UNUSED(frameNumber);
- emit error(QCamera::CameraError,
- QString("Capture session failure with Camera %1. Camera2 Api error code: %2")
- .arg(m_cameraDevice.description())
- .arg(reason));
+ updateError(QCamera::CameraError,
+ QStringLiteral("Capture session failure with Camera %1. Camera2 Api error code: %2")
+ .arg(m_cameraDevice.description())
+ .arg(reason));
}
// JNI logic
diff --git a/src/plugins/multimedia/ffmpeg/qandroidcameraframe.cpp b/src/plugins/multimedia/ffmpeg/qandroidcameraframe.cpp
index ef088e6d7..28d02b20e 100644
--- a/src/plugins/multimedia/ffmpeg/qandroidcameraframe.cpp
+++ b/src/plugins/multimedia/ffmpeg/qandroidcameraframe.cpp
@@ -12,10 +12,20 @@ Q_DECLARE_JNI_CLASS(AndroidImageFormat, "android/graphics/ImageFormat");
Q_DECLARE_JNI_CLASS(AndroidImage, "android/media/Image")
Q_DECLARE_JNI_TYPE(AndroidImagePlaneArray, "[Landroid/media/Image$Plane;")
Q_DECLARE_JNI_CLASS(JavaByteBuffer, "java/nio/ByteBuffer")
+Q_DECLARE_JNI_CLASS(QtVideoDeviceManager,
+ "org/qtproject/qt/android/multimedia/QtVideoDeviceManager");
QT_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(qLCAndroidCameraFrame, "qt.multimedia.ffmpeg.android.camera.frame");
+namespace {
+bool isWorkaroundForEmulatorNeeded() {
+ const static bool workaroundForEmulator
+ = QtJniTypes::QtVideoDeviceManager::callStaticMethod<jboolean>("isEmulator");
+ return workaroundForEmulator;
+}
+}
+
bool QAndroidCameraFrame::parse(const QJniObject &frame)
{
QJniEnvironment jniEnv;
@@ -130,12 +140,25 @@ bool QAndroidCameraFrame::parse(const QJniObject &frame)
m_planes[mapIndex].data = buffer[arrayIndex];
};
+ int width = frame.callMethod<jint>("getWidth");
+ int height = frame.callMethod<jint>("getHeight");
+ m_size = QSize(width, height);
+
switch (calculedPixelFormat) {
case QVideoFrameFormat::Format_YUV420P:
m_numberPlanes = 3;
copyPlane(0, 0);
copyPlane(1, 1);
copyPlane(2, 2);
+
+ if (isWorkaroundForEmulatorNeeded()) {
+ for (int i = 0; i < 3; ++i) {
+ const int dataSize = (i == 0) ? width * height : width * height / 4;
+ m_planes[i].data = new uint8_t[dataSize];
+ memcpy(m_planes[i].data, buffer[i], dataSize);
+ }
+ }
+
m_pixelFormat = QVideoFrameFormat::Format_YUV420P;
break;
case QVideoFrameFormat::Format_NV12:
@@ -161,10 +184,6 @@ bool QAndroidCameraFrame::parse(const QJniObject &frame)
long timestamp = frame.callMethod<jlong>("getTimestamp");
m_timestamp = timestamp / 1000;
- int width = frame.callMethod<jint>("getWidth");
- int height = frame.callMethod<jint>("getHeight");
- m_size = QSize(width, height);
-
return true;
}
@@ -193,6 +212,13 @@ QAndroidCameraFrame::~QAndroidCameraFrame()
QJniEnvironment jniEnv;
if (m_frame)
jniEnv->DeleteGlobalRef(m_frame);
+
+ if (isWorkaroundForEmulatorNeeded()) {
+ if (m_pixelFormat == QVideoFrameFormat::Format_YUV420P) {
+ for (int i = 0; i < 3; ++i)
+ delete[] m_planes[i].data;
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/qavfsamplebufferdelegate.mm b/src/plugins/multimedia/ffmpeg/qavfsamplebufferdelegate.mm
index 54dc3e578..94baead18 100644
--- a/src/plugins/multimedia/ffmpeg/qavfsamplebufferdelegate.mm
+++ b/src/plugins/multimedia/ffmpeg/qavfsamplebufferdelegate.mm
@@ -69,8 +69,6 @@ public:
return mapData;
}
- QVideoFrame::MapMode mapMode() const override { return m_mode; }
-
void unmap() override
{
if (m_mode != QVideoFrame::NotMapped) {
diff --git a/src/plugins/multimedia/ffmpeg/qcgwindowcapture.mm b/src/plugins/multimedia/ffmpeg/qcgwindowcapture.mm
index c10868e76..cc6f564ae 100644
--- a/src/plugins/multimedia/ffmpeg/qcgwindowcapture.mm
+++ b/src/plugins/multimedia/ffmpeg/qcgwindowcapture.mm
@@ -48,8 +48,6 @@ public:
~QCGImageVideoBuffer() override { CFRelease(m_data); }
- QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
-
MapData map(QVideoFrame::MapMode mode) override
{
MapData mapData;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpeg.cpp b/src/plugins/multimedia/ffmpeg/qffmpeg.cpp
index e998495d8..ce7dfc682 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpeg.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpeg.cpp
@@ -190,9 +190,7 @@ bool isCodecValid(const AVCodec *codec, const std::vector<AVHWDeviceType> &avail
if (codec->type != AVMEDIA_TYPE_VIDEO)
return true;
- const auto pixFmts = codec->pix_fmts;
-
- if (!pixFmts) {
+ if (!codec->pix_fmts) {
#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
// Disable V4L2 M2M codecs for encoding for now,
// TODO: Investigate on how to get them working
@@ -211,14 +209,14 @@ bool isCodecValid(const AVCodec *codec, const std::vector<AVHWDeviceType> &avail
// and with v4l2m2m codecs, that is suspicious.
}
- if (findAVFormat(pixFmts, &isHwPixelFormat) == AV_PIX_FMT_NONE)
+ if (findAVPixelFormat(codec, &isHwPixelFormat) == AV_PIX_FMT_NONE)
return true;
if ((codec->capabilities & AV_CODEC_CAP_HARDWARE) == 0)
return true;
- auto checkDeviceType = [pixFmts](AVHWDeviceType type) {
- return hasAVFormat(pixFmts, pixelFormatForHwDevice(type));
+ auto checkDeviceType = [codec](AVHWDeviceType type) {
+ return isAVFormatSupported(codec, pixelFormatForHwDevice(type));
};
if (codecAvailableOnDevice && codecAvailableOnDevice->count(codec->id) == 0)
@@ -389,6 +387,8 @@ const AVCodec *findAVCodec(CodecStorageType codecsType, AVCodecID codecId,
const std::optional<AVHWDeviceType> &deviceType,
const std::optional<PixelOrSampleFormat> &format)
{
+ // TODO: remove deviceType and use only isAVFormatSupported to check the format
+
return findAVCodec(codecsType, codecId, [&](const AVCodec *codec) {
if (format && !isAVFormatSupported(codec, *format))
return NotSuitableAVScore;
@@ -414,6 +414,7 @@ const AVCodec *findAVCodec(CodecStorageType codecsType, AVCodecID codecId,
// The situation happens mostly with encoders
// Probably, it's ffmpeg bug: avcodec_get_hw_config returns null even though
// hw acceleration is supported
+ // To be removed: only isAVFormatSupported should be used.
if (hasAVFormat(codec->pix_fmts, pixelFormatForHwDevice(*deviceType)))
return hwCodecNameScores(codec, *deviceType);
}
@@ -444,8 +445,10 @@ const AVCodec *findAVEncoder(AVCodecID codecId,
bool isAVFormatSupported(const AVCodec *codec, PixelOrSampleFormat format)
{
- if (codec->type == AVMEDIA_TYPE_VIDEO)
- return hasAVFormat(codec->pix_fmts, AVPixelFormat(format));
+ if (codec->type == AVMEDIA_TYPE_VIDEO) {
+ auto checkFormat = [format](AVPixelFormat f) { return f == format; };
+ return findAVPixelFormat(codec, checkFormat) != AV_PIX_FMT_NONE;
+ }
if (codec->type == AVMEDIA_TYPE_AUDIO)
return hasAVFormat(codec->sample_fmts, AVSampleFormat(format));
@@ -587,6 +590,36 @@ SwrContextUPtr createResampleContext(const AVAudioFormat &inputFormat,
return SwrContextUPtr(resampler);
}
+QVideoFrameFormat::ColorTransfer fromAvColorTransfer(AVColorTransferCharacteristic colorTrc) {
+ switch (colorTrc) {
+ case AVCOL_TRC_BT709:
+ // The following three cases have transfer characteristics identical to BT709
+ case AVCOL_TRC_BT1361_ECG:
+ case AVCOL_TRC_BT2020_10:
+ case AVCOL_TRC_BT2020_12:
+ case AVCOL_TRC_SMPTE240M: // almost identical to bt709
+ return QVideoFrameFormat::ColorTransfer_BT709;
+ case AVCOL_TRC_GAMMA22:
+ case AVCOL_TRC_SMPTE428: // No idea, let's hope for the best...
+ case AVCOL_TRC_IEC61966_2_1: // sRGB, close enough to 2.2...
+ case AVCOL_TRC_IEC61966_2_4: // not quite, but probably close enough
+ return QVideoFrameFormat::ColorTransfer_Gamma22;
+ case AVCOL_TRC_GAMMA28:
+ return QVideoFrameFormat::ColorTransfer_Gamma28;
+ case AVCOL_TRC_SMPTE170M:
+ return QVideoFrameFormat::ColorTransfer_BT601;
+ case AVCOL_TRC_LINEAR:
+ return QVideoFrameFormat::ColorTransfer_Linear;
+ case AVCOL_TRC_SMPTE2084:
+ return QVideoFrameFormat::ColorTransfer_ST2084;
+ case AVCOL_TRC_ARIB_STD_B67:
+ return QVideoFrameFormat::ColorTransfer_STD_B67;
+ default:
+ break;
+ }
+ return QVideoFrameFormat::ColorTransfer_Unknown;
+}
+
#ifdef Q_OS_DARWIN
bool isCVFormatSupported(uint32_t cvFormat)
{
diff --git a/src/plugins/multimedia/ffmpeg/qffmpeg_p.h b/src/plugins/multimedia/ffmpeg/qffmpeg_p.h
index 6e19b9650..09bf7e4f4 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpeg_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpeg_p.h
@@ -16,6 +16,7 @@
#include "qffmpegdefs_p.h"
#include "qffmpegavaudioformat_p.h"
+#include <QtMultimedia/qvideoframeformat.h>
#include <qstring.h>
#include <optional>
@@ -188,6 +189,34 @@ Format findAVFormat(const Format *fmts, const Predicate &predicate)
return findBestAVFormat(fmts, scoresGetter).first;
}
+template <typename Predicate>
+const AVCodecHWConfig *findHwConfig(const AVCodec *codec, const Predicate &predicate)
+{
+ for (int i = 0; const auto hwConfig = avcodec_get_hw_config(codec, i); ++i) {
+ if (predicate(hwConfig))
+ return hwConfig;
+ }
+
+ return nullptr;
+}
+
+template <typename Predicate>
+AVPixelFormat findAVPixelFormat(const AVCodec *codec, const Predicate &predicate)
+{
+ const AVPixelFormat format = findAVFormat(codec->pix_fmts, predicate);
+ if (format != AV_PIX_FMT_NONE)
+ return format;
+
+ auto checkHwConfig = [&predicate](const AVCodecHWConfig *config) {
+ return config->pix_fmt != AV_PIX_FMT_NONE && predicate(config->pix_fmt);
+ };
+
+ if (auto hwConfig = findHwConfig(codec, checkHwConfig))
+ return hwConfig->pix_fmt;
+
+ return AV_PIX_FMT_NONE;
+}
+
template <typename Value, typename CalculateScore>
auto findBestAVValue(const Value *values, const CalculateScore &calculateScore,
Value invalidValue = {})
@@ -234,6 +263,8 @@ const AVPacketSideData *streamSideData(const AVStream *stream, AVPacketSideDataT
SwrContextUPtr createResampleContext(const AVAudioFormat &inputFormat,
const AVAudioFormat &outputFormat);
+QVideoFrameFormat::ColorTransfer fromAvColorTransfer(AVColorTransferCharacteristic colorTrc);
+
#ifdef Q_OS_DARWIN
bool isCVFormatSupported(uint32_t format);
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegaudioinput_p.h b/src/plugins/multimedia/ffmpeg/qffmpegaudioinput_p.h
index a232978f6..288b3f432 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegaudioinput_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpegaudioinput_p.h
@@ -15,6 +15,7 @@
//
#include <private/qplatformaudioinput_p.h>
+#include <private/qplatformaudiobufferinput_p.h>
#include "qffmpegthread_p.h"
#include <qaudioinput.h>
@@ -28,8 +29,9 @@ class AudioSourceIO;
constexpr int DefaultAudioInputBufferSize = 4096;
-class QFFmpegAudioInput : public QObject, public QPlatformAudioInput
+class QFFmpegAudioInput : public QPlatformAudioBufferInputBase, public QPlatformAudioInput
{
+ // for qobject_cast
Q_OBJECT
public:
QFFmpegAudioInput(QAudioInput *qq);
@@ -44,9 +46,6 @@ public:
int bufferSize() const;
-Q_SIGNALS:
- void newAudioBuffer(const QAudioBuffer &buffer);
-
private:
QFFmpeg::AudioSourceIO *audioIO = nullptr;
std::unique_ptr<QThread> inputThread;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpeghwaccel.cpp b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel.cpp
index 06bd4f4d3..5b140f0ca 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpeghwaccel.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel.cpp
@@ -151,10 +151,11 @@ static const std::vector<AVHWDeviceType> &deviceTypes()
std::unordered_set<AVPixelFormat> hwPixFormats;
void *opaque = nullptr;
while (auto codec = av_codec_iterate(&opaque)) {
- if (auto pixFmt = codec->pix_fmts)
- for (; *pixFmt != AV_PIX_FMT_NONE; ++pixFmt)
- if (isHwPixelFormat(*pixFmt))
- hwPixFormats.insert(*pixFmt);
+ findAVPixelFormat(codec, [&](AVPixelFormat format) {
+ if (isHwPixelFormat(format))
+ hwPixFormats.insert(format);
+ return false;
+ });
}
// create a device types list
@@ -300,7 +301,9 @@ AVPixelFormat getFormat(AVCodecContext *codecContext, const AVPixelFormat *sugge
const bool shouldCheckCodecFormats = config->pix_fmt == AV_PIX_FMT_NONE;
auto scoresGettor = [&](AVPixelFormat format) {
- if (shouldCheckCodecFormats && !isAVFormatSupported(codecContext->codec, format))
+ // check in supported codec->pix_fmts;
+ // no reason to use findAVPixelFormat as we're already in the hw_config loop
+ if (shouldCheckCodecFormats && !hasAVFormat(codecContext->codec->pix_fmts, format))
return NotSuitableAVScore;
if (!shouldCheckCodecFormats && config->pix_fmt != format)
diff --git a/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_vaapi.cpp b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_vaapi.cpp
index 09ffaaf71..7e46e3537 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_vaapi.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_vaapi.cpp
@@ -184,7 +184,7 @@ VAAPITextureConverter::VAAPITextureConverter(QRhi *rhi)
}
const QString platform = QGuiApplication::platformName();
QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface();
- eglDisplay = pni->nativeResourceForIntegration("egldisplay");
+ eglDisplay = pni->nativeResourceForIntegration(QByteArrayLiteral("egldisplay"));
qCDebug(qLHWAccelVAAPI) << " platform is" << platform << eglDisplay;
if (!eglDisplay) {
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession.cpp b/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession.cpp
index f02593d16..1b6db5813 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession.cpp
@@ -6,9 +6,12 @@
#include "private/qplatformaudioinput_p.h"
#include "private/qplatformaudiooutput_p.h"
#include "private/qplatformsurfacecapture_p.h"
+#include "private/qplatformaudiobufferinput_p.h"
+#include "private/qplatformvideoframeinput_p.h"
+#include "private/qplatformcamera_p.h"
+
#include "qffmpegimagecapture_p.h"
#include "qffmpegmediarecorder_p.h"
-#include "private/qplatformcamera_p.h"
#include "qvideosink.h"
#include "qffmpegaudioinput_p.h"
#include "qaudiosink.h"
@@ -72,6 +75,17 @@ void QFFmpegMediaCaptureSession::setWindowCapture(QPlatformSurfaceCapture *windo
emit windowCaptureChanged();
}
+QPlatformVideoFrameInput *QFFmpegMediaCaptureSession::videoFrameInput()
+{
+ return m_videoFrameInput;
+}
+
+void QFFmpegMediaCaptureSession::setVideoFrameInput(QPlatformVideoFrameInput *input)
+{
+ if (setVideoSource(m_videoFrameInput, input))
+ emit videoFrameInputChanged();
+}
+
QPlatformImageCapture *QFFmpegMediaCaptureSession::imageCapture()
{
return m_imageCapture;
@@ -136,6 +150,12 @@ void QFFmpegMediaCaptureSession::setAudioInput(QPlatformAudioInput *input)
updateAudioSink();
}
+void QFFmpegMediaCaptureSession::setAudioBufferInput(QPlatformAudioBufferInput *input)
+{
+ // TODO: implement binding to audio sink like setAudioInput does
+ m_audioBufferInput = input;
+}
+
void QFFmpegMediaCaptureSession::updateAudioSink()
{
if (m_audioSink) {
@@ -191,7 +211,7 @@ void QFFmpegMediaCaptureSession::updateVolume()
m_audioSink->setVolume(m_audioOutput->muted ? 0.f : m_audioOutput->volume);
}
-QPlatformAudioInput *QFFmpegMediaCaptureSession::audioInput()
+QPlatformAudioInput *QFFmpegMediaCaptureSession::audioInput() const
{
return m_audioInput;
}
@@ -281,6 +301,18 @@ QPlatformVideoSource *QFFmpegMediaCaptureSession::primaryActiveVideoSource()
return m_primaryActiveVideoSource;
}
+std::vector<QPlatformAudioBufferInputBase *> QFFmpegMediaCaptureSession::activeAudioInputs() const
+{
+ std::vector<QPlatformAudioBufferInputBase *> result;
+ if (m_audioInput)
+ result.push_back(m_audioInput);
+
+ if (m_audioBufferInput)
+ result.push_back(m_audioBufferInput);
+
+ return result;
+}
+
QT_END_NAMESPACE
#include "moc_qffmpegmediacapturesession_p.cpp"
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession_p.h b/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession_p.h
index 6c80d0b09..25340dad5 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpegmediacapturesession_p.h
@@ -29,6 +29,8 @@ class QAudioSink;
class QFFmpegAudioInput;
class QAudioBuffer;
class QPlatformVideoSource;
+class QPlatformAudioBufferInput;
+class QPlatformAudioBufferInputBase;
class QFFmpegMediaCaptureSession : public QPlatformMediaCaptureSession
{
@@ -49,6 +51,9 @@ public:
QPlatformSurfaceCapture *windowCapture() override;
void setWindowCapture(QPlatformSurfaceCapture *) override;
+ QPlatformVideoFrameInput *videoFrameInput() override;
+ void setVideoFrameInput(QPlatformVideoFrameInput *) override;
+
QPlatformImageCapture *imageCapture() override;
void setImageCapture(QPlatformImageCapture *imageCapture) override;
@@ -56,13 +61,19 @@ public:
void setMediaRecorder(QPlatformMediaRecorder *recorder) override;
void setAudioInput(QPlatformAudioInput *input) override;
- QPlatformAudioInput *audioInput();
+ QPlatformAudioInput *audioInput() const;
+
+ void setAudioBufferInput(QPlatformAudioBufferInput *input) override;
void setVideoPreview(QVideoSink *sink) override;
void setAudioOutput(QPlatformAudioOutput *output) override;
QPlatformVideoSource *primaryActiveVideoSource();
+ // it might be moved to the base class, but it needs QPlatformAudioInput
+ // to be QPlatformAudioBufferInputBase, which might not make sense
+ std::vector<QPlatformAudioBufferInputBase *> activeAudioInputs() const;
+
private Q_SLOTS:
void updateAudioSink();
void updateVolume();
@@ -79,9 +90,12 @@ private:
QPointer<QPlatformCamera> m_camera;
QPointer<QPlatformSurfaceCapture> m_screenCapture;
QPointer<QPlatformSurfaceCapture> m_windowCapture;
+ QPointer<QPlatformVideoFrameInput> m_videoFrameInput;
QPointer<QPlatformVideoSource> m_primaryActiveVideoSource;
- QFFmpegAudioInput *m_audioInput = nullptr;
+ QPointer<QFFmpegAudioInput> m_audioInput;
+ QPointer<QPlatformAudioBufferInput> m_audioBufferInput;
+
QFFmpegImageCapture *m_imageCapture = nullptr;
QFFmpegMediaRecorder *m_mediaRecorder = nullptr;
QPlatformAudioOutput *m_audioOutput = nullptr;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegmediaintegration.cpp b/src/plugins/multimedia/ffmpeg/qffmpegmediaintegration.cpp
index aefe6102e..ba1fff3b3 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegmediaintegration.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegmediaintegration.cpp
@@ -13,7 +13,6 @@
#include "qffmpegaudioinput_p.h"
#include "qffmpegaudiodecoder_p.h"
#include "qffmpegresampler_p.h"
-#include "qffmpegsymbolsresolve_p.h"
#include "qgrabwindowsurfacecapture_p.h"
#include "qffmpegconverter_p.h"
@@ -172,8 +171,6 @@ static QPlatformSurfaceCapture *createWindowCaptureByBackend(QString backend)
QFFmpegMediaIntegration::QFFmpegMediaIntegration()
: QPlatformMediaIntegration(QLatin1String("ffmpeg"))
{
- resolveSymbols();
-
setupFFmpegLogger();
#ifndef QT_NO_DEBUG
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegmediarecorder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegmediarecorder.cpp
index 67eb46eb9..aaa5c2c0f 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegmediarecorder.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegmediarecorder.cpp
@@ -42,8 +42,9 @@ void QFFmpegMediaRecorder::record(QMediaEncoderSettings &settings)
return;
auto videoSources = m_session->activeVideoSources();
+ auto audioInputs = m_session->activeAudioInputs();
const auto hasVideo = !videoSources.empty();
- const auto hasAudio = m_session->audioInput() != nullptr;
+ const auto hasAudio = !audioInputs.empty();
if (!hasVideo && !hasAudio) {
updateError(QMediaRecorder::ResourceError, QMediaRecorder::tr("No video or audio input"));
@@ -83,25 +84,23 @@ void QFFmpegMediaRecorder::record(QMediaEncoderSettings &settings)
&QFFmpegMediaRecorder::newDuration);
connect(m_recordingEngine.get(), &QFFmpeg::RecordingEngine::finalizationDone, this,
&QFFmpegMediaRecorder::finalizationDone);
- connect(m_recordingEngine.get(), &QFFmpeg::RecordingEngine::error, this,
+ connect(m_recordingEngine.get(), &QFFmpeg::RecordingEngine::sessionError, this,
&QFFmpegMediaRecorder::handleSessionError);
- auto *audioInput = m_session->audioInput();
- if (audioInput) {
- if (audioInput->device.isNull())
- qWarning() << "Audio input device is null; cannot encode audio";
- else
- m_recordingEngine->addAudioInput(static_cast<QFFmpegAudioInput *>(audioInput));
- }
+ auto handleStreamInitializationError = [this](QMediaRecorder::Error code,
+ const QString &description) {
+ qCWarning(qLcMediaEncoder) << "Stream initialization error:" << description;
+ updateError(code, description);
+ };
- for (auto source : videoSources)
- m_recordingEngine->addVideoSource(source);
+ connect(m_recordingEngine.get(), &QFFmpeg::RecordingEngine::streamInitializationError, this,
+ handleStreamInitializationError);
durationChanged(0);
stateChanged(QMediaRecorder::RecordingState);
actualLocationChanged(QUrl::fromLocalFile(actualLocation));
- m_recordingEngine->start();
+ m_recordingEngine->initialize(audioInputs, videoSources);
}
void QFFmpegMediaRecorder::pause()
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegopensslsymbols.cpp b/src/plugins/multimedia/ffmpeg/qffmpegopensslsymbols.cpp
deleted file mode 100644
index e0e5de137..000000000
--- a/src/plugins/multimedia/ffmpeg/qffmpegopensslsymbols.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <QtCore/qlibrary.h>
-
-#include "qffmpegsymbolsresolveutils_p.h"
-
-#include <QtCore/qglobal.h>
-#include <qstringliteral.h>
-
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/bn.h>
-#include <openssl/err.h>
-#include <openssl/rand.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace Qt::StringLiterals;
-
-static Libs loadLibs()
-{
- Libs libs(2);
- libs[0] = std::make_unique<QLibrary>();
- libs[1] = std::make_unique<QLibrary>();
-
- const auto majorVersion = OPENSSL_VERSION_NUMBER >> 28;
-
- auto tryLoad = [&](QString sslName, QString cryptoName, auto version) {
- libs[0]->setFileNameAndVersion(sslName, version);
- libs[1]->setFileNameAndVersion(cryptoName, version);
- return LibSymbolsResolver::tryLoad(libs);
- };
-
-// Due to binary compatibility issues between 1.x.x openssl version, let's try taking exact version
-#if defined(SHLIB_VERSION_NUMBER)
- if (majorVersion <= 1 && tryLoad("ssl"_L1, "crypto"_L1, SHLIB_VERSION_NUMBER ""_L1))
- return libs;
-#endif
-
-// openssl on Android has specific suffixes
-#if defined(Q_OS_ANDROID)
- {
- auto suffix = qEnvironmentVariable("ANDROID_OPENSSL_SUFFIX");
- if (suffix.isEmpty())
- suffix = QString("_"_L1) + QString::number(majorVersion);
-
- if (tryLoad("ssl"_L1 + suffix, "crypto"_L1 + suffix, -1))
- return libs;
- }
-#endif
-
- if (tryLoad("ssl"_L1, "crypto"_L1, majorVersion))
- return libs;
-
- return {};
-};
-
-Q_GLOBAL_STATIC(LibSymbolsResolver, resolver, "OpenSsl", 75, loadLibs);
-
-void resolveOpenSsl()
-{
- resolver()->resolve();
-}
-
-QT_END_NAMESPACE
-
-QT_USE_NAMESPACE
-
-// BN functions
-
-DEFINE_FUNC(BN_value_one, 0);
-DEFINE_FUNC(BN_mod_word, 2);
-
-DEFINE_FUNC(BN_div_word, 2)
-DEFINE_FUNC(BN_mul_word, 2)
-DEFINE_FUNC(BN_add_word, 2)
-DEFINE_FUNC(BN_sub_word, 2)
-DEFINE_FUNC(BN_set_word, 2)
-DEFINE_FUNC(BN_new, 0)
-DEFINE_FUNC(BN_cmp, 2)
-
-DEFINE_FUNC(BN_free, 1);
-
-DEFINE_FUNC(BN_copy, 2);
-
-DEFINE_FUNC(BN_CTX_new, 0);
-
-DEFINE_FUNC(BN_CTX_free, 1);
-DEFINE_FUNC(BN_CTX_start, 1);
-
-DEFINE_FUNC(BN_CTX_get, 1);
-DEFINE_FUNC(BN_CTX_end, 1);
-
-DEFINE_FUNC(BN_rand, 4);
-DEFINE_FUNC(BN_mod_exp, 5);
-
-DEFINE_FUNC(BN_num_bits, 1);
-DEFINE_FUNC(BN_num_bits_word, 1);
-
-DEFINE_FUNC(BN_bn2hex, 1);
-DEFINE_FUNC(BN_bn2dec, 1);
-
-DEFINE_FUNC(BN_hex2bn, 2);
-DEFINE_FUNC(BN_dec2bn, 2);
-DEFINE_FUNC(BN_asc2bn, 2);
-
-DEFINE_FUNC(BN_bn2bin, 2);
-DEFINE_FUNC(BN_bin2bn, 3);
-
-// BIO-related functions
-
-DEFINE_FUNC(BIO_new, 1);
-DEFINE_FUNC(BIO_free, 1);
-
-DEFINE_FUNC(BIO_read, 3, -1);
-DEFINE_FUNC(BIO_write, 3, -1);
-DEFINE_FUNC(BIO_s_mem, 0);
-
-DEFINE_FUNC(BIO_set_data, 2);
-
-DEFINE_FUNC(BIO_get_data, 1);
-DEFINE_FUNC(BIO_set_init, 2);
-
-DEFINE_FUNC(BIO_set_flags, 2);
-DEFINE_FUNC(BIO_test_flags, 2);
-DEFINE_FUNC(BIO_clear_flags, 2);
-
-DEFINE_FUNC(BIO_meth_new, 2);
-DEFINE_FUNC(BIO_meth_free, 1);
-
-DEFINE_FUNC(BIO_meth_set_write, 2);
-DEFINE_FUNC(BIO_meth_set_read, 2);
-DEFINE_FUNC(BIO_meth_set_puts, 2);
-DEFINE_FUNC(BIO_meth_set_gets, 2);
-DEFINE_FUNC(BIO_meth_set_ctrl, 2);
-DEFINE_FUNC(BIO_meth_set_create, 2);
-DEFINE_FUNC(BIO_meth_set_destroy, 2);
-DEFINE_FUNC(BIO_meth_set_callback_ctrl, 2);
-
-// SSL functions
-
-DEFINE_FUNC(SSL_CTX_new, 1);
-DEFINE_FUNC(SSL_CTX_up_ref, 1);
-DEFINE_FUNC(SSL_CTX_free, 1);
-
-DEFINE_FUNC(SSL_new, 1);
-DEFINE_FUNC(SSL_up_ref, 1);
-DEFINE_FUNC(SSL_free, 1);
-
-DEFINE_FUNC(SSL_accept, 1);
-DEFINE_FUNC(SSL_stateless, 1);
-DEFINE_FUNC(SSL_connect, 1);
-DEFINE_FUNC(SSL_read, 3, -1);
-DEFINE_FUNC(SSL_peek, 3);
-DEFINE_FUNC(SSL_write, 3, -1);
-DEFINE_FUNC(SSL_ctrl, 4);
-DEFINE_FUNC(SSL_shutdown, 1);
-DEFINE_FUNC(SSL_set_bio, 3);
-
-// options are unsigned long in openssl 1.1.1, and uint64 in 3.x.x
-DEFINE_FUNC(SSL_CTX_set_options, 2);
-
-DEFINE_FUNC(SSL_get_error, 2);
-DEFINE_FUNC(SSL_CTX_load_verify_locations, 3, -1);
-
-DEFINE_FUNC(SSL_CTX_set_verify, 3);
-DEFINE_FUNC(SSL_CTX_use_PrivateKey, 2);
-
-DEFINE_FUNC(SSL_CTX_use_PrivateKey_file, 3);
-DEFINE_FUNC(SSL_CTX_use_certificate_chain_file, 2);
-
-DEFINE_FUNC(ERR_get_error, 0);
-
-static char ErrorString[] = "Ssl not found";
-DEFINE_FUNC(ERR_error_string, 2, ErrorString);
-
-// TLS functions
-
-DEFINE_FUNC(TLS_client_method, 0);
-DEFINE_FUNC(TLS_server_method, 0);
-
-// RAND functions
-
-DEFINE_FUNC(RAND_bytes, 2);
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp b/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp
index 72e542a34..7137533ac 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp
@@ -83,11 +83,6 @@ public:
QD3D11TextureVideoBuffer::unmap();
}
- QVideoFrame::MapMode mapMode() const override
- {
- return m_mapMode;
- }
-
MapData map(QVideoFrame::MapMode mode) override
{
MapData mapData;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolve_p.h b/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolve_p.h
deleted file mode 100644
index 8064b8d85..000000000
--- a/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolve_p.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QFFMPEGSYMBOLSRESOLVE_P_H
-#define QFFMPEGSYMBOLSRESOLVE_P_H
-
-#include "qnamespace.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.
-//
-
-QT_BEGIN_NAMESPACE
-
-inline void resolveSymbols()
-{
-#ifdef DYNAMIC_RESOLVE_OPENSSL_SYMBOLS
- extern bool resolveOpenSsl();
- resolveOpenSsl();
-#endif
-
-#ifdef DYNAMIC_RESOLVE_VAAPI_SYMBOLS
- extern bool resolveVAAPI();
- resolveVAAPI();
-#endif
-}
-
-QT_END_NAMESPACE
-
-#endif // QFFMPEGSYMBOLSRESOLVE_P_H
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils.cpp b/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils.cpp
deleted file mode 100644
index c4a4d9666..000000000
--- a/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qffmpegsymbolsresolveutils_p.h"
-
-#include <qdebug.h>
-#include <algorithm>
-#include <qloggingcategory.h>
-
-QT_BEGIN_NAMESPACE
-
-static Q_LOGGING_CATEGORY(qLcLibSymbolsRelolver, "qt.multimedia.ffmpeg.libsymbolsresolver");
-
-LibSymbolsResolver::LibSymbolsResolver(const char *libName, size_t symbolsCount,
- LibsLoader libsLoader)
- : m_libName(libName), m_libsLoader(libsLoader)
-{
- Q_ASSERT(m_libName);
- Q_ASSERT(m_libsLoader);
- m_symbols.reserve(symbolsCount);
-}
-
-bool LibSymbolsResolver::resolve()
-{
- if (m_state.testAndSetRelaxed(Initial, Requested)
- || !m_state.testAndSetAcquire(Ready, Finished))
- return false;
-
- qCDebug(qLcLibSymbolsRelolver)
- << "Start" << m_libName << "symbols resolving:" << m_symbols.size() << "symbols";
-
- Q_ASSERT(m_symbols.size() == m_symbols.capacity());
-
- auto cleanup = qScopeGuard([this]() { m_symbols = {}; });
-
- auto libs = m_libsLoader();
- if (libs.empty()) {
- qCWarning(qLcLibSymbolsRelolver) << "Couldn't load" << m_libName << "library";
- return false;
- }
-
- std::vector<QFunctionPointer> functions(m_symbols.size());
-
- auto resolveElement = [&libs](const SymbolElement &element) {
- return resolve(libs, element.name);
- };
-
- std::transform(m_symbols.begin(), m_symbols.end(), functions.begin(), resolveElement);
-
- if (std::find(functions.begin(), functions.end(), nullptr) != functions.end()) {
- unload(libs);
- qCWarning(qLcLibSymbolsRelolver) << "Couldn't resolve" << m_libName << "symbols";
- return false;
- }
-
- for (size_t i = 0; i < functions.size(); ++i)
- m_symbols[i].setter(functions[i]);
-
- qCDebug(qLcLibSymbolsRelolver) << m_libName << "symbols resolved";
- return true;
-}
-
-void LibSymbolsResolver::registerSymbol(const char *name, FunctionSetter setter)
-{
- Q_ASSERT(setter);
- Q_ASSERT(m_symbols.size() < m_symbols.capacity());
-
- m_symbols.push_back({ name, setter });
-
- // handle the corner case: a user has initialized QtMM with global vars construction
- // and it happened before the symbols initializing
- if (m_symbols.size() == m_symbols.capacity() && !m_state.testAndSetRelease(Initial, Ready)
- && m_state.testAndSetRelease(Requested, Ready))
- resolve();
-}
-
-void LibSymbolsResolver::unload(const Libs &libs)
-{
- for (auto &lib : libs)
- lib->unload();
-}
-
-bool LibSymbolsResolver::tryLoad(const Libs &libs)
-{
- auto load = [](auto &lib) { return lib->load(); };
- if (std::all_of(libs.begin(), libs.end(), load))
- return true;
-
- unload(libs);
- return false;
-}
-
-QFunctionPointer LibSymbolsResolver::resolve(const Libs &libs, const char *symbolName)
-{
- for (auto &lib : libs)
- if (auto pointer = lib->resolve(symbolName))
- return pointer;
-
- qWarning() << "Cannot resolve symbol" << symbolName;
- return nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils_p.h b/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils_p.h
deleted file mode 100644
index f7a2169d3..000000000
--- a/src/plugins/multimedia/ffmpeg/qffmpegsymbolsresolveutils_p.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QFFMPEGSYMBOLSRESOLVEUTILS_P_H
-#define QFFMPEGSYMBOLSRESOLVEUTILS_P_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 <QtCore/qlibrary.h>
-
-#include <qatomic.h>
-
-#include <vector>
-#include <memory>
-#include <tuple>
-
-QT_BEGIN_NAMESPACE
-
-using Libs = std::vector<std::unique_ptr<QLibrary>>;
-
-class LibSymbolsResolver
-{
-public:
- using FunctionSetter = void (*)(QFunctionPointer);
- using LibsLoader = Libs (*)();
-
- LibSymbolsResolver(const char *libName, size_t symbolsCount, LibsLoader libsLoader);
-
- bool resolve();
-
- void registerSymbol(const char *name, FunctionSetter setter);
-
- static void unload(const Libs &libs);
-
- static bool tryLoad(const Libs &libs);
-
-private:
- static QFunctionPointer resolve(const Libs &libs, const char *symbolName);
-
-private:
- const char *const m_libName;
- LibsLoader m_libsLoader;
-
- struct SymbolElement
- {
- const char *name;
- FunctionSetter setter;
- };
-
- std::vector<SymbolElement> m_symbols;
-
- enum State { Initial, Requested, Ready, Finished };
-
- QAtomicInteger<int> m_state = Initial;
-};
-
-QT_END_NAMESPACE
-
-template <typename T>
-struct DefaultReturn
-{
- template <typename... Arg>
- T operator()(Arg &&...) { return val; }
- T val;
-};
-
-template <>
-struct DefaultReturn<void>
-{
- DefaultReturn(int = 0){};
- template <typename... Arg>
- void operator()(Arg &&...) { }
-};
-
-template <typename...>
-struct FuncInfo;
-
-template <typename R, typename... A>
-struct FuncInfo<R(A...)>
-{
- using Return = R;
- using Args = std::tuple<A...>;
-};
-
-// clang-format off
-
-#define DEFINE_FUNC_IMPL(F, Vars, TypesWithVars, ReturnFunc) \
- using F##_ReturnType = FuncInfo<decltype(F)>::Return; \
- using q_##F##_Type = F##_ReturnType (*)(TypesWithVars(F)); \
- static q_##F##_Type q_##F = []() { \
- auto setter = [](QFunctionPointer ptr) { q_##F = (q_##F##_Type)ptr; }; \
- resolver()->registerSymbol(#F, setter); \
- return [](TypesWithVars(F)) { return ReturnFunc(Vars()); }; \
- }(); \
- extern "C" [[maybe_unused]] F##_ReturnType F(TypesWithVars(F)) { return q_##F(Vars()); }
-
-#define VAR(I) a##I
-#define VARS0()
-#define VARS1() VAR(0)
-#define VARS2() VARS1(), VAR(1)
-#define VARS3() VARS2(), VAR(2)
-#define VARS4() VARS3(), VAR(3)
-#define VARS5() VARS4(), VAR(4)
-#define VARS6() VARS5(), VAR(5)
-#define VARS7() VARS6(), VAR(6)
-#define VARS8() VARS7(), VAR(7)
-#define VARS9() VARS8(), VAR(8)
-#define VARS10() VARS9(), VAR(9)
-#define VARS11() VARS10(), VAR(10)
-
-#define TYPE_WITH_VAR(F, I) std::tuple_element_t<I, FuncInfo<decltype(F)>::Args> VAR(I)
-#define TYPES_WITH_VARS0(F)
-#define TYPES_WITH_VARS1(F) TYPE_WITH_VAR(F, 0)
-#define TYPES_WITH_VARS2(F) TYPES_WITH_VARS1(F), TYPE_WITH_VAR(F, 1)
-#define TYPES_WITH_VARS3(F) TYPES_WITH_VARS2(F), TYPE_WITH_VAR(F, 2)
-#define TYPES_WITH_VARS4(F) TYPES_WITH_VARS3(F), TYPE_WITH_VAR(F, 3)
-#define TYPES_WITH_VARS5(F) TYPES_WITH_VARS4(F), TYPE_WITH_VAR(F, 4)
-#define TYPES_WITH_VARS6(F) TYPES_WITH_VARS5(F), TYPE_WITH_VAR(F, 5)
-#define TYPES_WITH_VARS7(F) TYPES_WITH_VARS6(F), TYPE_WITH_VAR(F, 6)
-#define TYPES_WITH_VARS8(F) TYPES_WITH_VARS7(F), TYPE_WITH_VAR(F, 7)
-#define TYPES_WITH_VARS9(F) TYPES_WITH_VARS8(F), TYPE_WITH_VAR(F, 8)
-#define TYPES_WITH_VARS10(F) TYPES_WITH_VARS9(F), TYPE_WITH_VAR(F, 9)
-#define TYPES_WITH_VARS11(F) TYPES_WITH_VARS10(F), TYPE_WITH_VAR(F, 10)
-
-
-#define RET(F, ...) DefaultReturn<FuncInfo<decltype(F)>::Return>{__VA_ARGS__}
-
-#define DEFINE_FUNC(F, ArgsCount, /*Return value*/...) \
- DEFINE_FUNC_IMPL(F, VARS##ArgsCount, TYPES_WITH_VARS##ArgsCount, RET(F, __VA_ARGS__));
-
-// clang-format on
-
-#endif // QFFMPEGSYMBOLSRESOLVEUTILS_P_H
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer.cpp b/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer.cpp
index 5b79af5b3..1f2f362b4 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer.cpp
@@ -111,33 +111,7 @@ QVideoFrameFormat::ColorSpace QFFmpegVideoBuffer::colorSpace() const
QVideoFrameFormat::ColorTransfer QFFmpegVideoBuffer::colorTransfer() const
{
- switch (m_frame->color_trc) {
- case AVCOL_TRC_BT709:
- // The following three cases have transfer characteristics identical to BT709
- case AVCOL_TRC_BT1361_ECG:
- case AVCOL_TRC_BT2020_10:
- case AVCOL_TRC_BT2020_12:
- case AVCOL_TRC_SMPTE240M: // almost identical to bt709
- return QVideoFrameFormat::ColorTransfer_BT709;
- case AVCOL_TRC_GAMMA22:
- case AVCOL_TRC_SMPTE428 : // No idea, let's hope for the best...
- case AVCOL_TRC_IEC61966_2_1: // sRGB, close enough to 2.2...
- case AVCOL_TRC_IEC61966_2_4: // not quite, but probably close enough
- return QVideoFrameFormat::ColorTransfer_Gamma22;
- case AVCOL_TRC_GAMMA28:
- return QVideoFrameFormat::ColorTransfer_Gamma28;
- case AVCOL_TRC_SMPTE170M:
- return QVideoFrameFormat::ColorTransfer_BT601;
- case AVCOL_TRC_LINEAR:
- return QVideoFrameFormat::ColorTransfer_Linear;
- case AVCOL_TRC_SMPTE2084:
- return QVideoFrameFormat::ColorTransfer_ST2084;
- case AVCOL_TRC_ARIB_STD_B67:
- return QVideoFrameFormat::ColorTransfer_STD_B67;
- default:
- break;
- }
- return QVideoFrameFormat::ColorTransfer_Unknown;
+ return QFFmpeg::fromAvColorTransfer(m_frame->color_trc);
}
QVideoFrameFormat::ColorRange QFFmpegVideoBuffer::colorRange() const
@@ -168,11 +142,6 @@ float QFFmpegVideoBuffer::maxNits()
return maxNits;
}
-QVideoFrame::MapMode QFFmpegVideoBuffer::mapMode() const
-{
- return m_mode;
-}
-
QAbstractVideoBuffer::MapData QFFmpegVideoBuffer::map(QVideoFrame::MapMode mode)
{
if (!m_swFrame) {
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer_p.h b/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer_p.h
index 18a580528..8ccf58bd8 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer_p.h
+++ b/src/plugins/multimedia/ffmpeg/qffmpegvideobuffer_p.h
@@ -33,7 +33,6 @@ public:
QFFmpegVideoBuffer(AVFrameUPtr frame, AVRational pixelAspectRatio = { 1, 1 });
~QFFmpegVideoBuffer() override;
- QVideoFrame::MapMode mapMode() const override;
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override;
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegwindowcapture_uwp.cpp b/src/plugins/multimedia/ffmpeg/qffmpegwindowcapture_uwp.cpp
index 70746ea4c..d55728c70 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegwindowcapture_uwp.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegwindowcapture_uwp.cpp
@@ -89,8 +89,6 @@ public:
~QUwpTextureVideoBuffer() override { QUwpTextureVideoBuffer::unmap(); }
- QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
-
MapData map(QVideoFrame::MapMode mode) override
{
if (m_mapMode != QVideoFrame::NotMapped)
diff --git a/src/plugins/multimedia/ffmpeg/qopenglvideobuffer.cpp b/src/plugins/multimedia/ffmpeg/qopenglvideobuffer.cpp
index c3e739ffd..f55bc9787 100644
--- a/src/plugins/multimedia/ffmpeg/qopenglvideobuffer.cpp
+++ b/src/plugins/multimedia/ffmpeg/qopenglvideobuffer.cpp
@@ -62,11 +62,6 @@ QOpenGLVideoBuffer::QOpenGLVideoBuffer(std::unique_ptr<QOpenGLFramebufferObject>
QOpenGLVideoBuffer::~QOpenGLVideoBuffer() { }
-QVideoFrame::MapMode QOpenGLVideoBuffer::mapMode() const
-{
- return m_imageBuffer ? m_imageBuffer->mapMode() : QVideoFrame::NotMapped;
-}
-
QAbstractVideoBuffer::MapData QOpenGLVideoBuffer::map(QVideoFrame::MapMode mode)
{
return ensureImageBuffer().map(mode);
diff --git a/src/plugins/multimedia/ffmpeg/qopenglvideobuffer_p.h b/src/plugins/multimedia/ffmpeg/qopenglvideobuffer_p.h
index bbbb2f2c7..b0978caae 100644
--- a/src/plugins/multimedia/ffmpeg/qopenglvideobuffer_p.h
+++ b/src/plugins/multimedia/ffmpeg/qopenglvideobuffer_p.h
@@ -28,7 +28,6 @@ public:
QOpenGLVideoBuffer(std::unique_ptr<QOpenGLFramebufferObject> fbo);
~QOpenGLVideoBuffer();
- QVideoFrame::MapMode mapMode() const override;
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override;
quint64 textureHandle(QRhi *, int plane) const override;
diff --git a/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp b/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp
index 2086af10d..1ba05364d 100644
--- a/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp
+++ b/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp
@@ -394,7 +394,7 @@ void QV4L2Camera::readFrame()
void QV4L2Camera::setCameraBusy()
{
m_cameraBusy = true;
- emit error(QCamera::CameraError, QLatin1String("Camera is in use"));
+ updateError(QCamera::CameraError, QLatin1String("Camera is in use"));
}
void QV4L2Camera::initV4L2Controls()
@@ -412,7 +412,7 @@ void QV4L2Camera::initV4L2Controls()
qCWarning(qLcV4L2Camera) << "Unable to open the camera" << deviceName
<< "for read to query the parameter info:"
<< qt_error_string(errno);
- emit error(QCamera::CameraError, QLatin1String("Cannot open camera"));
+ updateError(QCamera::CameraError, QLatin1String("Cannot open camera"));
return;
}
@@ -651,7 +651,7 @@ void QV4L2Camera::initV4L2MemoryTransfer()
if (!m_memoryTransfer) {
qCWarning(qLcV4L2Camera) << "Cannot init v4l2 memory transfer," << qt_error_string(errno);
- emit error(QCamera::CameraError, QLatin1String("Cannot init V4L2 memory transfer"));
+ updateError(QCamera::CameraError, QLatin1String("Cannot init V4L2 memory transfer"));
}
}
diff --git a/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp b/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp
index 39aac3527..d298e2c99 100644
--- a/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp
+++ b/src/plugins/multimedia/ffmpeg/qwindowscamera.cpp
@@ -186,7 +186,7 @@ public:
{
if (FAILED(status)) {
const std::string msg{ std::system_category().message(status) };
- emit m_windowsCamera.error(QCamera::CameraError, QString::fromStdString(msg));
+ m_windowsCamera.updateError(QCamera::CameraError, QString::fromStdString(msg));
return;
}
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder.cpp
index 9948952e8..8dd97833e 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpegaudioencoder_p.h"
+#include "qffmpegrecordingengineutils_p.h"
#include "qffmpegaudioencoderutils_p.h"
#include "qffmpegaudioinput_p.h"
#include "qffmpegencoderoptions_p.h"
@@ -15,14 +16,13 @@ namespace QFFmpeg {
static Q_LOGGING_CATEGORY(qLcFFmpegAudioEncoder, "qt.multimedia.ffmpeg.audioencoder");
-AudioEncoder::AudioEncoder(RecordingEngine &recordingEngine, QFFmpegAudioInput *input,
+AudioEncoder::AudioEncoder(RecordingEngine &recordingEngine, const QAudioFormat &sourceFormat,
const QMediaEncoderSettings &settings)
- : EncoderThread(recordingEngine), m_input(input), m_settings(settings)
+ : EncoderThread(recordingEngine), m_format(sourceFormat), m_settings(settings)
{
setObjectName(QLatin1String("AudioEncoder"));
qCDebug(qLcFFmpegAudioEncoder) << "AudioEncoder" << settings.audioCodec();
- m_format = input->device.preferredFormat();
auto codecID = QFFmpegMediaFormatInfo::codecIdForAudioCodec(settings.audioCodec());
Q_ASSERT(avformat_query_codec(recordingEngine.avFormatContext()->oformat, codecID,
FF_COMPLIANCE_NORMAL));
@@ -87,35 +87,46 @@ void AudioEncoder::open()
qCDebug(qLcFFmpegAudioEncoder) << "audio codec params: fmt=" << m_codecContext->sample_fmt
<< "rate=" << m_codecContext->sample_rate;
- const AVAudioFormat requestedAudioFormat(m_format);
- const AVAudioFormat codecAudioFormat(m_codecContext.get());
-
- if (requestedAudioFormat != codecAudioFormat)
- m_resampler = createResampleContext(requestedAudioFormat, codecAudioFormat);
+ updateResampler();
}
void AudioEncoder::addBuffer(const QAudioBuffer &buffer)
{
- QMutexLocker locker = lockLoopData();
- if (!m_paused.loadRelaxed()) {
+ if (!buffer.isValid()) // TODO: report endOfStream
+ return;
+
+ {
+ const std::chrono::microseconds bufferDuration(buffer.duration());
+ auto guard = lockLoopData();
+
+ if (m_paused)
+ return;
+
+ // TODO: apply logic with canPushFrame
+
m_audioBufferQueue.push(buffer);
- locker.unlock();
- dataReady();
+ m_queueDuration += bufferDuration;
}
+
+ dataReady();
}
QAudioBuffer AudioEncoder::takeBuffer()
{
- QMutexLocker locker = lockLoopData();
- return dequeueIfPossible(m_audioBufferQueue);
+ auto locker = lockLoopData();
+ QAudioBuffer result = dequeueIfPossible(m_audioBufferQueue);
+ m_queueDuration -= std::chrono::microseconds(result.duration());
+ return result;
}
void AudioEncoder::init()
{
open();
- if (m_input) {
- m_input->setFrameSize(m_codecContext->frame_size);
- }
+
+ // TODO: try to address this dependency here.
+ if (auto input = qobject_cast<QFFmpegAudioInput *>(source()))
+ input->setFrameSize(m_codecContext->frame_size);
+
qCDebug(qLcFFmpegAudioEncoder) << "AudioEncoder::init started audio device thread.";
}
@@ -159,13 +170,11 @@ void AudioEncoder::retrievePackets()
void AudioEncoder::processOne()
{
QAudioBuffer buffer = takeBuffer();
- if (!buffer.isValid())
- return;
+ Q_ASSERT(buffer.isValid());
if (buffer.format() != m_format) {
- // should we recreate recreate resampler here?
- qWarning() << "Get invalid audio format:" << buffer.format() << ", expected:" << m_format;
- return;
+ m_format = buffer.format();
+ updateResampler();
}
// qCDebug(qLcFFmpegEncoder) << "new audio buffer" << buffer.byteCount() << buffer.format()
@@ -214,6 +223,29 @@ void AudioEncoder::processOne()
}
}
+bool AudioEncoder::checkIfCanPushFrame() const
+{
+ if (isRunning())
+ return m_audioBufferQueue.size() <= 1 || m_queueDuration < m_maxQueueDuration;
+ if (!isFinished())
+ return m_audioBufferQueue.empty();
+
+ return false;
+}
+
+void AudioEncoder::updateResampler()
+{
+ m_resampler.reset();
+
+ const AVAudioFormat requestedAudioFormat(m_format);
+ const AVAudioFormat codecAudioFormat(m_codecContext.get());
+
+ if (requestedAudioFormat != codecAudioFormat)
+ m_resampler = createResampleContext(requestedAudioFormat, codecAudioFormat);
+
+ qCDebug(qLcFFmpegAudioEncoder)
+ << "Resampler updated. Input format:" << m_format << "Resampler:" << m_resampler.get();
+}
} // namespace QFFmpeg
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder_p.h
index 16d8d81a1..3601356cd 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder_p.h
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegaudioencoder_p.h
@@ -8,28 +8,31 @@
#include "private/qplatformmediarecorder_p.h"
#include <qaudiobuffer.h>
#include <queue>
+#include <chrono>
QT_BEGIN_NAMESPACE
class QMediaEncoderSettings;
-class QFFmpegAudioInput;
namespace QFFmpeg {
class AudioEncoder : public EncoderThread
{
public:
- AudioEncoder(RecordingEngine &recordingEngine, QFFmpegAudioInput *input,
+ AudioEncoder(RecordingEngine &recordingEngine, const QAudioFormat &sourceFormat,
const QMediaEncoderSettings &settings);
- void open();
void addBuffer(const QAudioBuffer &buffer);
- QFFmpegAudioInput *audioInput() const { return m_input; }
+protected:
+ bool checkIfCanPushFrame() const override;
private:
+ void open();
+
QAudioBuffer takeBuffer();
void retrievePackets();
+ void updateResampler();
void init() override;
void cleanup() override;
@@ -39,9 +42,13 @@ private:
private:
std::queue<QAudioBuffer> m_audioBufferQueue;
+ // Arbitrarily chosen to limit audio queue duration
+ const std::chrono::microseconds m_maxQueueDuration = std::chrono::seconds(5);
+
+ std::chrono::microseconds m_queueDuration{ 0 };
+
AVStream *m_stream = nullptr;
AVCodecContextUPtr m_codecContext;
- QFFmpegAudioInput *m_input = nullptr;
QAudioFormat m_format;
SwrContextUPtr m_resampler;
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread.cpp
index b673af450..d55b5810d 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpegencoderthread_p.h"
+#include "qmetaobject.h"
QT_BEGIN_NAMESPACE
@@ -10,11 +11,14 @@ EncoderThread::EncoderThread(RecordingEngine &recordingEngine) : m_recordingEngi
{
}
-void EncoderThread::setPaused(bool b)
+void EncoderThread::setPaused(bool paused)
{
- m_paused.storeRelease(b);
+ auto guard = lockLoopData();
+ m_paused = paused;
}
} // namespace QFFmpeg
QT_END_NAMESPACE
+
+#include "moc_qffmpegencoderthread_p.cpp"
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread_p.h
index 1fe35303b..2e413f9dd 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread_p.h
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencoderthread_p.h
@@ -4,6 +4,9 @@
#define QFFMPEGENCODERTHREAD_P_H
#include "qffmpegthread_p.h"
+#include "qpointer.h"
+
+#include "private/qmediainputencoderinterface_p.h"
QT_BEGIN_NAMESPACE
@@ -11,15 +14,43 @@ namespace QFFmpeg {
class RecordingEngine;
-class EncoderThread : public ConsumerThread
+class EncoderThread : public ConsumerThread, public QMediaInputEncoderInterface
{
+ Q_OBJECT
public:
EncoderThread(RecordingEngine &recordingEngine);
- virtual void setPaused(bool b);
+
+ void setPaused(bool paused);
+
+ void setSource(QObject *source) { m_source = source; }
+
+ QObject *source() const { return m_source; }
+
+ bool canPushFrame() const override { return m_canPushFrame.load(std::memory_order_relaxed); }
+
+protected:
+ void updateCanPushFrame();
+
+ virtual bool checkIfCanPushFrame() const = 0;
+
+ auto lockLoopData()
+ {
+ return QScopeGuard([this, locker = ConsumerThread::lockLoopData()]() mutable {
+ const bool canPush = !m_paused && checkIfCanPushFrame();
+ locker.unlock();
+ if (m_canPushFrame.exchange(canPush, std::memory_order_relaxed) != canPush)
+ emit canPushFrameChanged();
+ });
+ }
+
+Q_SIGNALS:
+ void canPushFrameChanged();
protected:
- QAtomicInteger<bool> m_paused = false;
+ bool m_paused = false;
+ std::atomic_bool m_canPushFrame = false;
RecordingEngine &m_recordingEngine;
+ QPointer<QObject> m_source;
};
} // namespace QFFmpeg
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer.cpp
new file mode 100644
index 000000000..4f8c21bd5
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer.cpp
@@ -0,0 +1,165 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qffmpegencodinginitializer_p.h"
+#include "qffmpegrecordingengineutils_p.h"
+#include "qffmpegrecordingengine_p.h"
+#include "qffmpegaudioinput_p.h"
+#include "qvideoframe.h"
+
+#include "private/qplatformvideoframeinput_p.h"
+#include "private/qplatformaudiobufferinput_p.h"
+#include "private/qplatformaudiobufferinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+EncodingInitializer::EncodingInitializer(RecordingEngine &engine) : m_recordingEngine(engine) { }
+
+EncodingInitializer::~EncodingInitializer()
+{
+ for (QObject *source : m_pendingSources)
+ setEncoderInterface(source, nullptr);
+}
+
+void EncodingInitializer::start(const std::vector<QPlatformAudioBufferInputBase *> &audioSources,
+ const std::vector<QPlatformVideoSource *> &videoSources)
+{
+ for (auto source : audioSources) {
+ if (auto audioInput = qobject_cast<QFFmpegAudioInput *>(source))
+ m_recordingEngine.addAudioInput(audioInput);
+ else if (auto audioBufferInput = qobject_cast<QPlatformAudioBufferInput *>(source))
+ addAudioBufferInput(audioBufferInput);
+ else
+ Q_ASSERT(!"Undefined source type");
+ }
+
+ for (auto source : videoSources)
+ addVideoSource(source);
+
+ tryStartRecordingEngine();
+}
+
+void EncodingInitializer::addAudioBufferInput(QPlatformAudioBufferInput *input)
+{
+ Q_ASSERT(input);
+
+ if (input->audioFormat().isValid())
+ m_recordingEngine.addAudioBufferInput(input, {});
+ else
+ addPendingAudioBufferInput(input);
+}
+
+void EncodingInitializer::addPendingAudioBufferInput(QPlatformAudioBufferInput *input)
+{
+ addPendingSource(input);
+
+ connect(input, &QPlatformAudioBufferInput::destroyed, this, [this, input]() {
+ erasePendingSource(input, QStringLiteral("Audio source deleted"), true);
+ });
+
+ connect(input, &QPlatformAudioBufferInput::newAudioBuffer, this,
+ [this, input](const QAudioBuffer &buffer) {
+ if (buffer.isValid())
+ erasePendingSource(
+ input, [&]() { m_recordingEngine.addAudioBufferInput(input, buffer); });
+ else
+ erasePendingSource(input,
+ QStringLiteral("Audio source has sent the end frame"));
+ });
+}
+
+void EncodingInitializer::addVideoSource(QPlatformVideoSource *source)
+{
+ Q_ASSERT(source);
+ Q_ASSERT(source->isActive());
+
+ if (source->frameFormat().isValid())
+ m_recordingEngine.addVideoSource(source, {});
+ else if (source->hasError())
+ emitStreamInitializationError(QStringLiteral("Video source error: ")
+ + source->errorString());
+ else
+ addPendingVideoSource(source);
+}
+
+void EncodingInitializer::addPendingVideoSource(QPlatformVideoSource *source)
+{
+ addPendingSource(source);
+
+ connect(source, &QPlatformVideoSource::errorChanged, this, [this, source]() {
+ if (source->hasError())
+ erasePendingSource(source,
+ QStringLiteral("Videio source error: ") + source->errorString());
+ });
+
+ connect(source, &QPlatformVideoSource::destroyed, this, [this, source]() {
+ erasePendingSource(source, QStringLiteral("Source deleted"), true);
+ });
+
+ connect(source, &QPlatformVideoSource::activeChanged, this, [this, source]() {
+ if (!source->isActive())
+ erasePendingSource(source, QStringLiteral("Video source deactivated"));
+ });
+
+ connect(source, &QPlatformVideoSource::newVideoFrame, this,
+ [this, source](const QVideoFrame &frame) {
+ if (frame.isValid())
+ erasePendingSource(source,
+ [&]() { m_recordingEngine.addVideoSource(source, frame); });
+ else
+ erasePendingSource(source,
+ QStringLiteral("Video source has sent the end frame"));
+ });
+}
+
+void EncodingInitializer::tryStartRecordingEngine()
+{
+ if (m_pendingSources.empty())
+ m_recordingEngine.start();
+}
+
+void EncodingInitializer::emitStreamInitializationError(QString error)
+{
+ emit m_recordingEngine.streamInitializationError(
+ QMediaRecorder::ResourceError,
+ QStringLiteral("Video steam initialization error. ") + error);
+}
+
+void EncodingInitializer::addPendingSource(QObject *source)
+{
+ Q_ASSERT(m_pendingSources.count(source) == 0);
+
+ setEncoderInterface(source, this);
+ m_pendingSources.emplace(source);
+}
+
+template <typename F>
+void EncodingInitializer::erasePendingSource(QObject *source, F &&functionOrError, bool destroyed)
+{
+ const auto erasedCount = m_pendingSources.erase(source);
+ if (erasedCount == 0)
+ return; // got a queued event, just ignore it.
+
+ if (!destroyed) {
+ setEncoderInterface(source, nullptr);
+ disconnect(source, nullptr, this, nullptr);
+ }
+
+ if constexpr (std::is_invocable_v<F>)
+ functionOrError();
+ else
+ emitStreamInitializationError(functionOrError);
+
+ tryStartRecordingEngine();
+}
+
+bool EncodingInitializer::canPushFrame() const
+{
+ return true;
+}
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer_p.h
new file mode 100644
index 000000000..e3bcb3428
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegencodinginitializer_p.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QENCODINGINITIALIZER_P_H
+#define QENCODINGINITIALIZER_P_H
+
+#include "qobject.h"
+#include "private/qmediainputencoderinterface_p.h"
+#include <unordered_set>
+#include <vector>
+
+//
+// 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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QFFmpegAudioInput;
+class QPlatformVideoSource;
+class QPlatformAudioBufferInput;
+class QPlatformAudioBufferInputBase;
+class QMediaInputEncoderInterface;
+
+namespace QFFmpeg {
+
+class RecordingEngine;
+
+// Initializes RecordingEngine with audio and video sources, potentially lazily
+// upon first frame arrival if video frame format is not pre-determined.
+class EncodingInitializer : public QObject, private QMediaInputEncoderInterface
+{
+public:
+ EncodingInitializer(RecordingEngine &engine);
+
+ ~EncodingInitializer() override;
+
+ void start(const std::vector<QPlatformAudioBufferInputBase *> &audioSources,
+ const std::vector<QPlatformVideoSource *> &videoSources);
+
+private:
+ void addAudioBufferInput(QPlatformAudioBufferInput *input);
+
+ void addPendingAudioBufferInput(QPlatformAudioBufferInput *input);
+
+ void addVideoSource(QPlatformVideoSource *source);
+
+ void addPendingVideoSource(QPlatformVideoSource *source);
+
+ void addPendingSource(QObject *source);
+
+ void tryStartRecordingEngine();
+
+private:
+ void emitStreamInitializationError(QString error);
+
+ template <typename F>
+ void erasePendingSource(QObject *source, F &&functionOrError, bool destroyed = false);
+
+ bool canPushFrame() const override;
+
+private:
+ RecordingEngine &m_recordingEngine;
+ std::unordered_set<QObject *> m_pendingSources;
+};
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
+
+#endif // QENCODINGINITIALIZER_P_H
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegmuxer.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegmuxer.cpp
index 2df594017..6a33e79dd 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegmuxer.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegmuxer.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpegmuxer_p.h"
#include "qffmpegrecordingengine_p.h"
+#include "qffmpegrecordingengineutils_p.h"
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp
index 23bd4c02d..4e4925962 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine.cpp
@@ -1,19 +1,21 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpegrecordingengine_p.h"
-#include "qffmpegmediaformatinfo_p.h"
-#include "qffmpegvideoframeencoder_p.h"
-#include "private/qmultimediautils_p.h"
-
-#include <qdebug.h>
+#include "qffmpegencodinginitializer_p.h"
#include "qffmpegaudioencoder_p.h"
#include "qffmpegaudioinput_p.h"
-#include <private/qplatformcamera_p.h>
-#include "qffmpegvideobuffer_p.h"
+#include "qffmpegrecordingengineutils_p.h"
+
+#include "private/qmultimediautils_p.h"
+#include "private/qplatformaudiobufferinput_p.h"
+#include "private/qplatformvideosource_p.h"
+#include "private/qplatformvideoframeinput_p.h"
+
+#include "qdebug.h"
#include "qffmpegvideoencoder_p.h"
#include "qffmpegmediametadata_p.h"
#include "qffmpegmuxer_p.h"
-#include <qloggingcategory.h>
+#include "qloggingcategory.h"
QT_BEGIN_NAMESPACE
@@ -36,21 +38,67 @@ RecordingEngine::~RecordingEngine()
void RecordingEngine::addAudioInput(QFFmpegAudioInput *input)
{
- m_audioEncoder = new AudioEncoder(*this, input, m_settings);
- addMediaFrameHandler(input, &QFFmpegAudioInput::newAudioBuffer, m_audioEncoder,
- &AudioEncoder::addBuffer);
+ Q_ASSERT(input);
+
+ if (input->device.isNull()) {
+ emit streamInitializationError(QMediaRecorder::ResourceError,
+ QLatin1StringView("Audio device is null"));
+ return;
+ }
+
+ const QAudioFormat format = input->device.preferredFormat();
+
+ if (!format.isValid()) {
+ emit streamInitializationError(
+ QMediaRecorder::FormatError,
+ QLatin1StringView("Audio device has invalid preferred format"));
+ return;
+ }
+
+ AudioEncoder *audioEncoder = createAudioEncoder(format);
+ connectEncoderToSource(audioEncoder, input);
+
input->setRunning(true);
}
-void RecordingEngine::addVideoSource(QPlatformVideoSource * source)
+void RecordingEngine::addAudioBufferInput(QPlatformAudioBufferInput *input,
+ const QAudioBuffer &firstBuffer)
{
- auto frameFormat = source->frameFormat();
+ Q_ASSERT(input);
+ const QAudioFormat format = firstBuffer.isValid() ? firstBuffer.format() : input->audioFormat();
- if (!frameFormat.isValid()) {
- qCWarning(qLcFFmpegEncoder) << "Cannot add source; invalid vide frame format";
- emit error(QMediaRecorder::ResourceError,
- QLatin1StringView("Cannot get video source format"));
- return;
+ AudioEncoder *audioEncoder = createAudioEncoder(format);
+
+ // set the buffer before connecting to avoid potential races
+ if (firstBuffer.isValid())
+ audioEncoder->addBuffer(firstBuffer);
+
+ connectEncoderToSource(audioEncoder, input);
+}
+
+AudioEncoder *RecordingEngine::createAudioEncoder(const QAudioFormat &format)
+{
+ Q_ASSERT(format.isValid());
+
+ auto audioEncoder = new AudioEncoder(*this, format, m_settings);
+ m_audioEncoders.push_back(audioEncoder);
+
+ return audioEncoder;
+}
+
+void RecordingEngine::addVideoSource(QPlatformVideoSource *source, const QVideoFrame &firstFrame)
+{
+ QVideoFrameFormat frameFormat =
+ firstFrame.isValid() ? firstFrame.surfaceFormat() : source->frameFormat();
+
+ Q_ASSERT(frameFormat.isValid());
+
+ if (firstFrame.isValid() && frameFormat.streamFrameRate() <= 0.f) {
+ const qint64 startTime = firstFrame.startTime();
+ const qint64 endTime = firstFrame.endTime();
+ if (startTime != -1 && endTime > startTime)
+ frameFormat.setStreamFrameRate(static_cast<qreal>(VideoFrameTimeBase)
+ / (endTime - startTime));
}
std::optional<AVPixelFormat> hwPixelFormat = source->ffmpegHWPixelFormat()
@@ -65,17 +113,32 @@ void RecordingEngine::addVideoSource(QPlatformVideoSource * source)
auto veUPtr = std::make_unique<VideoEncoder>(*this, m_settings, frameFormat, hwPixelFormat);
if (!veUPtr->isValid()) {
- emit error(QMediaRecorder::FormatError, QLatin1StringView("Cannot initialize encoder"));
+ emit streamInitializationError(QMediaRecorder::FormatError,
+ QLatin1StringView("Cannot initialize encoder"));
return;
}
- auto ve = veUPtr.release();
- addMediaFrameHandler(source, &QPlatformVideoSource::newVideoFrame, ve, &VideoEncoder::addFrame);
- m_videoEncoders.append(ve);
+ auto videoEncoder = veUPtr.release();
+ m_videoEncoders.append(videoEncoder);
+
+ // set the frame before connecting to avoid potential races
+ if (firstFrame.isValid())
+ videoEncoder->addFrame(firstFrame);
+
+ connectEncoderToSource(videoEncoder, source);
}
void RecordingEngine::start()
{
+ Q_ASSERT(m_initializer);
+ m_initializer.reset();
+
+ if (m_audioEncoders.empty() && m_videoEncoders.empty()) {
+ emit sessionError(QMediaRecorder::ResourceError,
+ QLatin1StringView("No valid stream found for encoding"));
+ return;
+ }
+
qCDebug(qLcFFmpegEncoder) << "RecordingEngine::start!";
avFormatContext()->metadata = QFFmpegMetaData::toAVMetaData(m_metaData);
@@ -85,7 +148,8 @@ void RecordingEngine::start()
int res = avformat_write_header(avFormatContext(), nullptr);
if (res < 0) {
qWarning() << "could not write header, error:" << res << err2str(res);
- emit error(QMediaRecorder::ResourceError, "Cannot start writing the stream");
+ emit sessionError(QMediaRecorder::ResourceError,
+ QLatin1StringView("Cannot start writing the stream"));
return;
}
@@ -94,11 +158,17 @@ void RecordingEngine::start()
qCDebug(qLcFFmpegEncoder) << "stream header is successfully written";
m_muxer->start();
- if (m_audioEncoder)
- m_audioEncoder->start();
- for (auto *videoEncoder : m_videoEncoders)
- if (videoEncoder->isValid())
- videoEncoder->start();
+
+ forEachEncoder([](QThread *thread) { thread->start(); });
+}
+
+void RecordingEngine::initialize(const std::vector<QPlatformAudioBufferInputBase *> &audioSources,
+ const std::vector<QPlatformVideoSource *> &videoSources)
+{
+ qCDebug(qLcFFmpegEncoder) << ">>>>>>>>>>>>>>> initialize";
+
+ m_initializer = std::make_unique<EncodingInitializer>(*this);
+ m_initializer->start(audioSources, videoSources);
}
RecordingEngine::EncodingFinalizer::EncodingFinalizer(RecordingEngine &recordingEngine)
@@ -109,10 +179,7 @@ RecordingEngine::EncodingFinalizer::EncodingFinalizer(RecordingEngine &recording
void RecordingEngine::EncodingFinalizer::run()
{
- if (m_recordingEngine.m_audioEncoder)
- m_recordingEngine.m_audioEncoder->stopAndDelete();
- for (auto &videoEncoder : m_recordingEngine.m_videoEncoders)
- videoEncoder->stopAndDelete();
+ m_recordingEngine.forEachEncoder(&EncoderThread::stopAndDelete);
m_recordingEngine.m_muxer->stopAndDelete();
if (m_recordingEngine.m_isHeaderWritten) {
@@ -120,9 +187,9 @@ void RecordingEngine::EncodingFinalizer::run()
if (res < 0) {
const auto errorDescription = err2str(res);
qCWarning(qLcFFmpegEncoder) << "could not write trailer" << res << errorDescription;
- emit m_recordingEngine.error(QMediaRecorder::FormatError,
- QLatin1String("Cannot write trailer: ")
- + errorDescription);
+ emit m_recordingEngine.sessionError(QMediaRecorder::FormatError,
+ QLatin1String("Cannot write trailer: ")
+ + errorDescription);
}
}
// else ffmpeg might crash
@@ -140,19 +207,17 @@ void RecordingEngine::finalize()
{
qCDebug(qLcFFmpegEncoder) << ">>>>>>>>>>>>>>> finalize";
- for (auto &conn : m_connections)
- disconnect(conn);
+ m_initializer.reset();
+
+ forEachEncoder(&disconnectEncoderFromSource);
auto *finalizer = new EncodingFinalizer(*this);
finalizer->start();
}
-void RecordingEngine::setPaused(bool p)
+void RecordingEngine::setPaused(bool paused)
{
- if (m_audioEncoder)
- m_audioEncoder->setPaused(p);
- for (auto &videoEncoder : m_videoEncoders)
- videoEncoder->setPaused(p);
+ forEachEncoder(&EncoderThread::setPaused, paused);
}
void RecordingEngine::setMetaData(const QMediaMetaData &metaData)
@@ -169,11 +234,13 @@ void RecordingEngine::newTimeStamp(qint64 time)
}
}
-template<typename... Args>
-void RecordingEngine::addMediaFrameHandler(Args &&...args)
+template <typename F, typename... Args>
+void RecordingEngine::forEachEncoder(F &&f, Args &&...args)
{
- auto connection = connect(std::forward<Args>(args)..., Qt::DirectConnection);
- m_connections.append(connection);
+ for (AudioEncoder *audioEncoder : m_audioEncoders)
+ std::invoke(f, audioEncoder, args...);
+ for (VideoEncoder *videoEncoder : m_videoEncoders)
+ std::invoke(f, videoEncoder, args...);
}
}
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h
index b74fbba9f..61f198fa1 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengine_p.h
@@ -20,12 +20,13 @@
#include <private/qplatformmediarecorder_p.h>
#include <qmediarecorder.h>
-#include <queue>
-
QT_BEGIN_NAMESPACE
class QFFmpegAudioInput;
+class QPlatformAudioBufferInput;
+class QPlatformAudioBufferInputBase;
class QVideoFrame;
+class QAudioBuffer;
class QPlatformVideoSource;
namespace QFFmpeg
@@ -36,17 +37,7 @@ class Muxer;
class AudioEncoder;
class VideoEncoder;
class VideoFrameEncoder;
-
-template <typename T>
-T dequeueIfPossible(std::queue<T> &queue)
-{
- if (queue.empty())
- return T{};
-
- auto result = std::move(queue.front());
- queue.pop();
- return result;
-}
+class EncodingInitializer;
class RecordingEngine : public QObject
{
@@ -55,10 +46,8 @@ public:
RecordingEngine(const QMediaEncoderSettings &settings, std::unique_ptr<EncodingFormatContext> context);
~RecordingEngine();
- void addAudioInput(QFFmpegAudioInput *input);
- void addVideoSource(QPlatformVideoSource *source);
-
- void start();
+ void initialize(const std::vector<QPlatformAudioBufferInputBase *> &audioSources,
+ const std::vector<QPlatformVideoSource *> &videoSources);
void finalize();
void setPaused(bool p);
@@ -72,13 +61,11 @@ public Q_SLOTS:
Q_SIGNALS:
void durationChanged(qint64 duration);
- void error(QMediaRecorder::Error code, const QString &description);
+ void sessionError(QMediaRecorder::Error code, const QString &description);
+ void streamInitializationError(QMediaRecorder::Error code, const QString &description);
void finalizationDone();
private:
- template<typename... Args>
- void addMediaFrameHandler(Args &&...args);
-
class EncodingFinalizer : public QThread
{
public:
@@ -90,15 +77,27 @@ private:
RecordingEngine &m_recordingEngine;
};
+ friend class EncodingInitializer;
+ void addAudioInput(QFFmpegAudioInput *input);
+ void addAudioBufferInput(QPlatformAudioBufferInput *input, const QAudioBuffer &firstBuffer);
+ AudioEncoder *createAudioEncoder(const QAudioFormat &format);
+
+ void addVideoSource(QPlatformVideoSource *source, const QVideoFrame &firstFrame);
+
+ void start();
+
+ template <typename F, typename... Args>
+ void forEachEncoder(F &&f, Args &&...args);
+
private:
QMediaEncoderSettings m_settings;
QMediaMetaData m_metaData;
std::unique_ptr<EncodingFormatContext> m_formatContext;
Muxer *m_muxer = nullptr;
- AudioEncoder *m_audioEncoder = nullptr;
+ QList<AudioEncoder *> m_audioEncoders;
QList<VideoEncoder *> m_videoEncoders;
- QList<QMetaObject::Connection> m_connections;
+ std::unique_ptr<EncodingInitializer> m_initializer;
QMutex m_timeMutex;
qint64 m_timeRecorded = 0;
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils.cpp
new file mode 100644
index 000000000..6c2ba8b15
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "recordingengine/qffmpegrecordingengineutils_p.h"
+#include "recordingengine/qffmpegencoderthread_p.h"
+#include "private/qplatformaudiobufferinput_p.h"
+#include "private/qplatformvideoframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QFFmpeg {
+
+template <typename F>
+void doWithMediaFrameInput(QObject *source, F &&f)
+{
+ if (auto videoFrameInput = qobject_cast<QPlatformVideoFrameInput *>(source))
+ f(videoFrameInput);
+ else if (auto audioBufferInput = qobject_cast<QPlatformAudioBufferInput *>(source))
+ f(audioBufferInput);
+}
+
+void setEncoderInterface(QObject *source, QMediaInputEncoderInterface *interface)
+{
+ doWithMediaFrameInput(source, [&](auto source) {
+ using Source = std::remove_pointer_t<decltype(source)>;
+
+ source->setEncoderInterface(interface);
+ if (interface)
+ // Postpone emit 'encoderUpdated' as the encoding pipeline may be not
+ // completely ready at the moment. The case is calling QMediaRecorder::stop
+ // upon handling 'readyToSendFrame'
+ QMetaObject::invokeMethod(source, &Source::encoderUpdated, Qt::QueuedConnection);
+ else
+ emit source->encoderUpdated();
+ });
+}
+
+void setEncoderUpdateConnection(QObject *source, EncoderThread *encoder)
+{
+ doWithMediaFrameInput(source, [&](auto source) {
+ using Source = std::remove_pointer_t<decltype(source)>;
+ QObject::connect(encoder, &EncoderThread::canPushFrameChanged, source,
+ &Source::encoderUpdated);
+ });
+}
+
+void disconnectEncoderFromSource(EncoderThread *encoder)
+{
+ QObject *source = encoder->source();
+ if (!source)
+ return;
+
+ // We should address the dependency AudioEncoder from QFFmpegAudioInput to
+ // set null source here.
+ // encoder->setSource(nullptr);
+
+ QObject::disconnect(source, nullptr, encoder, nullptr);
+ setEncoderInterface(source, nullptr);
+}
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils_p.h
new file mode 100644
index 000000000..c04932b55
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegrecordingengineutils_p.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFFMPEGRECORDINGENGINEUTILS_P_H
+#define QFFMPEGRECORDINGENGINEUTILS_P_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 "qobject.h"
+#include <queue>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaInputEncoderInterface;
+class QPlatformVideoSource;
+
+namespace QFFmpeg {
+
+constexpr qint64 VideoFrameTimeBase = 1000000; // us in sec
+
+class EncoderThread;
+
+template <typename T>
+T dequeueIfPossible(std::queue<T> &queue)
+{
+ if (queue.empty())
+ return T{};
+
+ auto result = std::move(queue.front());
+ queue.pop();
+ return result;
+}
+
+void setEncoderInterface(QObject *source, QMediaInputEncoderInterface *interface);
+
+void setEncoderUpdateConnection(QObject *source, EncoderThread *encoder);
+
+template <typename Encoder, typename Source>
+void connectEncoderToSource(Encoder *encoder, Source *source)
+{
+ Q_ASSERT(!encoder->source());
+ encoder->setSource(source);
+
+ if constexpr (std::is_same_v<Source, QPlatformVideoSource>)
+ QObject::connect(source, &Source::newVideoFrame, encoder, &Encoder::addFrame,
+ Qt::DirectConnection);
+ else
+ QObject::connect(source, &Source::newAudioBuffer, encoder, &Encoder::addBuffer,
+ Qt::DirectConnection);
+
+ setEncoderUpdateConnection(source, encoder);
+ setEncoderInterface(source, encoder);
+}
+
+void disconnectEncoderFromSource(EncoderThread *encoder);
+
+} // namespace QFFmpeg
+
+QT_END_NAMESPACE
+
+#endif // QFFMPEGRECORDINGENGINEUTILS_P_H
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp
index 5f9dd83c4..ab44c89fb 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder.cpp
@@ -5,6 +5,7 @@
#include "qffmpegvideobuffer_p.h"
#include "qffmpegrecordingengine_p.h"
#include "qffmpegvideoframeencoder_p.h"
+#include "qffmpegrecordingengineutils_p.h"
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
@@ -48,25 +49,36 @@ bool VideoEncoder::isValid() const
void VideoEncoder::addFrame(const QVideoFrame &frame)
{
- QMutexLocker locker = lockLoopData();
+ if (!frame.isValid()) // TODO: report endOfStream
+ return;
+
+ {
+ auto guard = lockLoopData();
- // Drop frames if encoder can not keep up with the video source data rate
- const bool queueFull = m_videoFrameQueue.size() >= m_maxQueueSize;
+ if (m_paused) {
+ m_shouldAdjustTimeBaseForNextFrame = true;
+ return;
+ }
- if (queueFull) {
- qCDebug(qLcFFmpegVideoEncoder) << "RecordingEngine frame queue full. Frame lost.";
- } else if (!m_paused.loadRelaxed()) {
- m_videoFrameQueue.push(frame);
+ // Drop frames if encoder can not keep up with the video source data rate;
+ // canPushFrame might be used instead
+ const bool queueFull = m_videoFrameQueue.size() >= m_maxQueueSize;
- locker.unlock(); // Avoid context switch on wake wake-up
+ if (queueFull) {
+ qCDebug(qLcFFmpegVideoEncoder) << "RecordingEngine frame queue full. Frame lost.";
+ return;
+ }
- dataReady();
+ m_videoFrameQueue.push({ frame, m_shouldAdjustTimeBaseForNextFrame });
+ m_shouldAdjustTimeBaseForNextFrame = false;
}
+
+ dataReady();
}
-QVideoFrame VideoEncoder::takeFrame()
+VideoEncoder::FrameInfo VideoEncoder::takeFrame()
{
- QMutexLocker locker = lockLoopData();
+ auto guard = lockLoopData();
return dequeueIfPossible(m_videoFrameQueue);
}
@@ -80,10 +92,13 @@ void VideoEncoder::retrievePackets()
void VideoEncoder::init()
{
+ Q_ASSERT(isValid());
+
qCDebug(qLcFFmpegVideoEncoder) << "VideoEncoder::init started video device thread.";
bool ok = m_frameEncoder->open();
if (!ok)
- emit m_recordingEngine.error(QMediaRecorder::ResourceError, "Could not initialize encoder");
+ emit m_recordingEngine.sessionError(QMediaRecorder::ResourceError,
+ "Could not initialize encoder");
}
void VideoEncoder::cleanup()
@@ -117,9 +132,9 @@ void VideoEncoder::processOne()
{
retrievePackets();
- auto frame = takeFrame();
- if (!frame.isValid())
- return;
+ FrameInfo frameInfo = takeFrame();
+ QVideoFrame &frame = frameInfo.frame;
+ Q_ASSERT(frame.isValid());
if (!isValid())
return;
@@ -164,14 +179,16 @@ void VideoEncoder::processOne()
new QVideoFrameHolder{ frame, img }, 0);
}
- if (m_baseTime.loadAcquire() == std::numeric_limits<qint64>::min()) {
- m_baseTime.storeRelease(frame.startTime() - m_lastFrameTime);
- qCDebug(qLcFFmpegVideoEncoder) << ">>>> adjusting base time to" << m_baseTime.loadAcquire()
- << frame.startTime() << m_lastFrameTime;
+ const auto [startTime, endTime] = frameTimeStamps(frame);
+
+ if (frameInfo.shouldAdjustTimeBase) {
+ m_baseTime += startTime - m_lastFrameTime;
+ qCDebug(qLcFFmpegVideoEncoder)
+ << ">>>> adjusting base time to" << m_baseTime << startTime << m_lastFrameTime;
}
- qint64 time = frame.startTime() - m_baseTime.loadAcquire();
- m_lastFrameTime = frame.endTime() - m_baseTime.loadAcquire();
+ const qint64 time = startTime - m_baseTime;
+ m_lastFrameTime = endTime;
setAVFrameTime(*avFrame, m_frameEncoder->getPts(time), m_frameEncoder->getTimeBase());
@@ -182,10 +199,42 @@ void VideoEncoder::processOne()
int ret = m_frameEncoder->sendFrame(std::move(avFrame));
if (ret < 0) {
qCDebug(qLcFFmpegVideoEncoder) << "error sending frame" << ret << err2str(ret);
- emit m_recordingEngine.error(QMediaRecorder::ResourceError, err2str(ret));
+ emit m_recordingEngine.sessionError(QMediaRecorder::ResourceError, err2str(ret));
}
}
+bool VideoEncoder::checkIfCanPushFrame() const
+{
+ if (isRunning())
+ return m_videoFrameQueue.size() < m_maxQueueSize;
+ if (!isFinished())
+ return m_videoFrameQueue.empty();
+
+ return false;
+}
+
+std::pair<qint64, qint64> VideoEncoder::frameTimeStamps(const QVideoFrame &frame) const
+{
+ qint64 startTime = frame.startTime();
+ qint64 endTime = frame.endTime();
+
+ if (startTime == -1) {
+ startTime = m_lastFrameTime;
+ endTime = -1;
+ }
+
+ if (endTime == -1) {
+ qreal frameRate = frame.streamFrameRate();
+ if (frameRate <= 0.)
+ frameRate = m_frameEncoder->settings().videoFrameRate();
+
+ Q_ASSERT(frameRate > 0.f);
+ endTime = startTime + static_cast<qint64>(std::round(VideoFrameTimeBase / frameRate));
+ }
+
+ return { startTime, endTime };
+}
+
} // namespace QFFmpeg
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h
index 8f9a943de..ff6a74fc8 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoder_p.h
@@ -27,15 +27,17 @@ public:
void addFrame(const QVideoFrame &frame);
- void setPaused(bool b) override
- {
- EncoderThread::setPaused(b);
- if (b)
- m_baseTime.storeRelease(-1);
- }
+protected:
+ bool checkIfCanPushFrame() const override;
private:
- QVideoFrame takeFrame();
+ struct FrameInfo
+ {
+ QVideoFrame frame;
+ bool shouldAdjustTimeBase = false;
+ };
+
+ FrameInfo takeFrame();
void retrievePackets();
void init() override;
@@ -43,12 +45,15 @@ private:
bool hasData() const override;
void processOne() override;
+ std::pair<qint64, qint64> frameTimeStamps(const QVideoFrame &frame) const;
+
private:
- std::queue<QVideoFrame> m_videoFrameQueue;
+ std::queue<FrameInfo> m_videoFrameQueue;
const size_t m_maxQueueSize = 10; // Arbitrarily chosen to limit memory usage (332 MB @ 4K)
std::unique_ptr<VideoFrameEncoder> m_frameEncoder;
- QAtomicInteger<qint64> m_baseTime = std::numeric_limits<qint64>::min();
+ qint64 m_baseTime = 0;
+ bool m_shouldAdjustTimeBaseForNextFrame = true;
qint64 m_lastFrameTime = 0;
};
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoderutils.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoderutils.cpp
index 83b9575b4..eef2a64bf 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoderutils.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoencoderutils.cpp
@@ -108,8 +108,9 @@ AVPixelFormat findTargetFormat(AVPixelFormat sourceFormat, AVPixelFormat sourceS
if (constraints && hasAVFormat(constraints->valid_hw_formats, hwFormat))
return hwFormat;
- // Some codecs, don't expose constraints, let's find the format in codec->pix_fmts
- if (hasAVFormat(codec->pix_fmts, hwFormat))
+ // Some codecs, don't expose constraints,
+ // let's find the format in codec->pix_fmts and hw_config
+ if (isAVFormatSupported(codec, hwFormat))
return hwFormat;
}
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder.cpp b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder.cpp
index 18d9c1401..6c52f1e87 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder.cpp
@@ -244,18 +244,8 @@ int VideoFrameEncoder::sendFrame(AVFrameUPtr frame)
if (!frame)
return avcodec_send_frame(m_codecContext.get(), frame.get());
- if (frame->format != m_sourceFormat) {
- qWarning() << "Frame format has changed:" << m_sourceFormat << "->" << frame->format;
+ if (!updateSourceFormatAndSize(frame.get()))
return AVERROR(EINVAL);
- }
-
- const QSize frameSize(frame->width, frame->height);
- if (frameSize != m_sourceSize) {
- qCDebug(qLcVideoFrameEncoder) << "Update conversions on the fly. Source size"
- << m_sourceSize << "->" << frameSize;
- m_sourceSize = frameSize;
- updateConversions();
- }
int64_t pts = 0;
AVRational timeBase = {};
@@ -377,6 +367,44 @@ AVPacketUPtr VideoFrameEncoder::retrievePacket()
return nullptr;
}
+bool VideoFrameEncoder::updateSourceFormatAndSize(const AVFrame *frame)
+{
+ Q_ASSERT(frame);
+
+ const QSize frameSize(frame->width, frame->height);
+ const AVPixelFormat frameFormat = static_cast<AVPixelFormat>(frame->format);
+
+ if (frameSize == m_sourceSize && frameFormat == m_sourceFormat)
+ return true;
+
+ auto applySourceFormatAndSize = [&](AVPixelFormat swFormat) {
+ m_sourceSize = frameSize;
+ m_sourceFormat = frameFormat;
+ m_sourceSWFormat = swFormat;
+ updateConversions();
+ return true;
+ };
+
+ if (frameFormat == m_sourceFormat)
+ return applySourceFormatAndSize(m_sourceSWFormat);
+
+ if (frameFormat == AV_PIX_FMT_NONE) {
+ qWarning() << "Got a frame with invalid pixel format";
+ return false;
+ }
+
+ if (isSwPixelFormat(frameFormat))
+ return applySourceFormatAndSize(frameFormat);
+
+ auto framesCtx = reinterpret_cast<const AVHWFramesContext *>(frame->hw_frames_ctx->data);
+ if (!framesCtx || framesCtx->sw_format == AV_PIX_FMT_NONE) {
+ qWarning() << "Cannot update conversions as hw frame has invalid framesCtx" << framesCtx;
+ return false;
+ }
+
+ return applySourceFormatAndSize(framesCtx->sw_format);
+}
+
void VideoFrameEncoder::updateConversions()
{
const bool needToScale = m_sourceSize != m_settings.videoResolution();
diff --git a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder_p.h b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder_p.h
index b8e51e6c1..af57730f2 100644
--- a/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder_p.h
+++ b/src/plugins/multimedia/ffmpeg/recordingengine/qffmpegvideoframeencoder_p.h
@@ -48,9 +48,13 @@ public:
int sendFrame(AVFrameUPtr frame);
AVPacketUPtr retrievePacket();
+ const QMediaEncoderSettings &settings() { return m_settings; }
+
private:
VideoFrameEncoder() = default;
+ bool updateSourceFormatAndSize(const AVFrame *frame);
+
void updateConversions();
bool initCodec();
diff --git a/src/plugins/multimedia/ffmpeg/symbolstubs/openssl3.ver b/src/plugins/multimedia/ffmpeg/symbolstubs/openssl3.ver
new file mode 100644
index 000000000..88235a94c
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/symbolstubs/openssl3.ver
@@ -0,0 +1,7 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+OPENSSL_3.0.0 {
+ global:
+ *;
+};
diff --git a/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-crypto.cpp b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-crypto.cpp
new file mode 100644
index 000000000..fbf3b783c
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-crypto.cpp
@@ -0,0 +1,6 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtMultimedia/private/qsymbolsresolveutils_p.h>
+
+// No stub functions are needed for ffmpeg
diff --git a/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-ssl.cpp b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-ssl.cpp
new file mode 100644
index 000000000..3e38e398c
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-ssl.cpp
@@ -0,0 +1,300 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtMultimedia/private/qsymbolsresolveutils_p.h>
+
+#include <qstringliteral.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+using namespace Qt::StringLiterals;
+
+[[maybe_unused]] static constexpr auto SHLIB_VERSION =
+#if defined(OPENSSL_SHLIB_VERSION)
+ OPENSSL_SHLIB_VERSION;
+#elif defined(SHLIB_VERSION_NUMBER)
+ SHLIB_VERSION_NUMBER;
+#endif
+
+
+#if !defined(Q_OS_ANDROID)
+CHECK_VERSIONS("ssl", SSL_NEEDED_SOVERSION, SHLIB_VERSION);
+#endif
+
+static std::unique_ptr<QLibrary> loadLib()
+{
+ auto lib = std::make_unique<QLibrary>();
+
+ auto tryLoad = [&](QString sslName, auto version) {
+ lib->setFileNameAndVersion(sslName, version);
+ return lib->load();
+ };
+
+// openssl on Android has specific suffixes
+#if defined(Q_OS_ANDROID)
+ {
+ auto suffix = qEnvironmentVariable("ANDROID_OPENSSL_SUFFIX");
+ if (suffix.isEmpty()) {
+#if (OPENSSL_VERSION_NUMBER >> 28) < 3 // major version < 3
+ suffix = "_1_1"_L1;
+#elif OPENSSL_VERSION_MAJOR == 3
+ suffix = "_3"_L1;
+#else
+ static_assert(false, "Unexpected openssl version");
+#endif
+ }
+
+ if (tryLoad("ssl"_L1 + suffix, -1))
+ return lib;
+ }
+#endif
+
+ if (tryLoad("ssl"_L1, SSL_NEEDED_SOVERSION ""_L1))
+ return lib;
+
+ return {};
+};
+
+
+BEGIN_INIT_FUNCS("ssl", loadLib)
+
+// BN functions
+
+INIT_FUNC(BN_value_one);
+INIT_FUNC(BN_mod_word);
+
+INIT_FUNC(BN_div_word)
+INIT_FUNC(BN_mul_word)
+INIT_FUNC(BN_add_word)
+INIT_FUNC(BN_sub_word)
+INIT_FUNC(BN_set_word)
+INIT_FUNC(BN_new)
+INIT_FUNC(BN_cmp)
+
+INIT_FUNC(BN_free);
+
+INIT_FUNC(BN_copy);
+
+INIT_FUNC(BN_CTX_new);
+
+INIT_FUNC(BN_CTX_free);
+INIT_FUNC(BN_CTX_start);
+
+INIT_FUNC(BN_CTX_get);
+INIT_FUNC(BN_CTX_end);
+
+INIT_FUNC(BN_rand);
+INIT_FUNC(BN_mod_exp);
+
+INIT_FUNC(BN_num_bits);
+INIT_FUNC(BN_num_bits_word);
+
+INIT_FUNC(BN_bn2hex);
+INIT_FUNC(BN_bn2dec);
+
+INIT_FUNC(BN_hex2bn);
+INIT_FUNC(BN_dec2bn);
+INIT_FUNC(BN_asc2bn);
+
+INIT_FUNC(BN_bn2bin);
+INIT_FUNC(BN_bin2bn);
+
+// BIO-related functions
+
+INIT_FUNC(BIO_new);
+INIT_FUNC(BIO_free);
+
+INIT_FUNC(BIO_read);
+INIT_FUNC(BIO_write);
+INIT_FUNC(BIO_s_mem);
+
+INIT_FUNC(BIO_set_data);
+
+INIT_FUNC(BIO_get_data);
+INIT_FUNC(BIO_set_init);
+
+INIT_FUNC(BIO_set_flags);
+INIT_FUNC(BIO_test_flags);
+INIT_FUNC(BIO_clear_flags);
+
+INIT_FUNC(BIO_meth_new);
+INIT_FUNC(BIO_meth_free);
+
+INIT_FUNC(BIO_meth_set_write);
+INIT_FUNC(BIO_meth_set_read);
+INIT_FUNC(BIO_meth_set_puts);
+INIT_FUNC(BIO_meth_set_gets);
+INIT_FUNC(BIO_meth_set_ctrl);
+INIT_FUNC(BIO_meth_set_create);
+INIT_FUNC(BIO_meth_set_destroy);
+INIT_FUNC(BIO_meth_set_callback_ctrl);
+
+// SSL functions
+
+INIT_FUNC(SSL_CTX_new);
+INIT_FUNC(SSL_CTX_up_ref);
+INIT_FUNC(SSL_CTX_free);
+
+INIT_FUNC(SSL_new);
+INIT_FUNC(SSL_up_ref);
+INIT_FUNC(SSL_free);
+
+INIT_FUNC(SSL_accept);
+INIT_FUNC(SSL_stateless);
+INIT_FUNC(SSL_connect);
+INIT_FUNC(SSL_read);
+INIT_FUNC(SSL_peek);
+INIT_FUNC(SSL_write);
+INIT_FUNC(SSL_ctrl);
+INIT_FUNC(SSL_shutdown);
+INIT_FUNC(SSL_set_bio);
+
+// options are unsigned long in openssl 1.1.1, and uint64 in 3.x.x
+INIT_FUNC(SSL_CTX_set_options);
+
+INIT_FUNC(SSL_get_error);
+INIT_FUNC(SSL_CTX_load_verify_locations);
+
+INIT_FUNC(SSL_CTX_set_verify);
+INIT_FUNC(SSL_CTX_use_PrivateKey);
+
+INIT_FUNC(SSL_CTX_use_PrivateKey_file);
+INIT_FUNC(SSL_CTX_use_certificate_chain_file);
+
+INIT_FUNC(ERR_get_error);
+
+INIT_FUNC(ERR_error_string);
+
+// TLS functions
+
+INIT_FUNC(TLS_client_method);
+INIT_FUNC(TLS_server_method);
+
+// RAND functions
+
+INIT_FUNC(RAND_bytes);
+
+END_INIT_FUNCS()
+
+//////////// Define
+
+// BN functions
+
+DEFINE_FUNC(BN_value_one, 0);
+DEFINE_FUNC(BN_mod_word, 2);
+
+DEFINE_FUNC(BN_div_word, 2)
+DEFINE_FUNC(BN_mul_word, 2)
+DEFINE_FUNC(BN_add_word, 2)
+DEFINE_FUNC(BN_sub_word, 2)
+DEFINE_FUNC(BN_set_word, 2)
+DEFINE_FUNC(BN_new, 0)
+DEFINE_FUNC(BN_cmp, 2)
+
+DEFINE_FUNC(BN_free, 1);
+
+DEFINE_FUNC(BN_copy, 2);
+
+DEFINE_FUNC(BN_CTX_new, 0);
+
+DEFINE_FUNC(BN_CTX_free, 1);
+DEFINE_FUNC(BN_CTX_start, 1);
+
+DEFINE_FUNC(BN_CTX_get, 1);
+DEFINE_FUNC(BN_CTX_end, 1);
+
+DEFINE_FUNC(BN_rand, 4);
+DEFINE_FUNC(BN_mod_exp, 5);
+
+DEFINE_FUNC(BN_num_bits, 1);
+DEFINE_FUNC(BN_num_bits_word, 1);
+
+DEFINE_FUNC(BN_bn2hex, 1);
+DEFINE_FUNC(BN_bn2dec, 1);
+
+DEFINE_FUNC(BN_hex2bn, 2);
+DEFINE_FUNC(BN_dec2bn, 2);
+DEFINE_FUNC(BN_asc2bn, 2);
+
+DEFINE_FUNC(BN_bn2bin, 2);
+DEFINE_FUNC(BN_bin2bn, 3);
+
+// BIO-related functions
+
+DEFINE_FUNC(BIO_new, 1);
+DEFINE_FUNC(BIO_free, 1);
+
+DEFINE_FUNC(BIO_read, 3, -1);
+DEFINE_FUNC(BIO_write, 3, -1);
+DEFINE_FUNC(BIO_s_mem, 0);
+
+DEFINE_FUNC(BIO_set_data, 2);
+
+DEFINE_FUNC(BIO_get_data, 1);
+DEFINE_FUNC(BIO_set_init, 2);
+
+DEFINE_FUNC(BIO_set_flags, 2);
+DEFINE_FUNC(BIO_test_flags, 2);
+DEFINE_FUNC(BIO_clear_flags, 2);
+
+DEFINE_FUNC(BIO_meth_new, 2);
+DEFINE_FUNC(BIO_meth_free, 1);
+
+DEFINE_FUNC(BIO_meth_set_write, 2);
+DEFINE_FUNC(BIO_meth_set_read, 2);
+DEFINE_FUNC(BIO_meth_set_puts, 2);
+DEFINE_FUNC(BIO_meth_set_gets, 2);
+DEFINE_FUNC(BIO_meth_set_ctrl, 2);
+DEFINE_FUNC(BIO_meth_set_create, 2);
+DEFINE_FUNC(BIO_meth_set_destroy, 2);
+DEFINE_FUNC(BIO_meth_set_callback_ctrl, 2);
+
+// SSL functions
+
+DEFINE_FUNC(SSL_CTX_new, 1);
+DEFINE_FUNC(SSL_CTX_up_ref, 1);
+DEFINE_FUNC(SSL_CTX_free, 1);
+
+DEFINE_FUNC(SSL_new, 1);
+DEFINE_FUNC(SSL_up_ref, 1);
+DEFINE_FUNC(SSL_free, 1);
+
+DEFINE_FUNC(SSL_accept, 1);
+DEFINE_FUNC(SSL_stateless, 1);
+DEFINE_FUNC(SSL_connect, 1);
+DEFINE_FUNC(SSL_read, 3, -1);
+DEFINE_FUNC(SSL_peek, 3);
+DEFINE_FUNC(SSL_write, 3, -1);
+DEFINE_FUNC(SSL_ctrl, 4);
+DEFINE_FUNC(SSL_shutdown, 1);
+DEFINE_FUNC(SSL_set_bio, 3);
+
+// options are unsigned long in openssl 1.1.1, and uint64 in 3.x.x
+DEFINE_FUNC(SSL_CTX_set_options, 2);
+
+DEFINE_FUNC(SSL_get_error, 2);
+DEFINE_FUNC(SSL_CTX_load_verify_locations, 3, -1);
+
+DEFINE_FUNC(SSL_CTX_set_verify, 3);
+DEFINE_FUNC(SSL_CTX_use_PrivateKey, 2);
+
+DEFINE_FUNC(SSL_CTX_use_PrivateKey_file, 3);
+DEFINE_FUNC(SSL_CTX_use_certificate_chain_file, 2);
+
+DEFINE_FUNC(ERR_get_error, 0);
+
+static char ErrorString[] = "Ssl not found";
+DEFINE_FUNC(ERR_error_string, 2, ErrorString);
+
+// TLS functions
+
+DEFINE_FUNC(TLS_client_method, 0);
+DEFINE_FUNC(TLS_server_method, 0);
+
+// RAND functions
+
+DEFINE_FUNC(RAND_bytes, 2);
diff --git a/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-drm.cpp b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-drm.cpp
new file mode 100644
index 000000000..655a6b2b6
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-drm.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtMultimedia/private/qsymbolsresolveutils_p.h>
+
+#include <va/va_drm.h>
+
+CHECK_VERSIONS("va-drm", VA_DRM_NEEDED_SOVERSION, VA_MAJOR_VERSION + 1);
+
+BEGIN_INIT_FUNCS("va-drm", VA_DRM_NEEDED_SOVERSION)
+INIT_FUNC(vaGetDisplayDRM)
+END_INIT_FUNCS()
+
+DEFINE_FUNC(vaGetDisplayDRM, 1);
diff --git a/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-x11.cpp b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-x11.cpp
new file mode 100644
index 000000000..3bada9e69
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va-x11.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtMultimedia/private/qsymbolsresolveutils_p.h>
+
+#include <va/va_x11.h>
+
+CHECK_VERSIONS("va-x11", VA_X11_NEEDED_SOVERSION, VA_MAJOR_VERSION + 1);
+
+BEGIN_INIT_FUNCS("va-x11", VA_X11_NEEDED_SOVERSION)
+INIT_FUNC(vaGetDisplay)
+END_INIT_FUNCS()
+
+DEFINE_FUNC(vaGetDisplay, 1);
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegvaapisymbols.cpp b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va.cpp
index 9860b53a0..cfd2e5686 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegvaapisymbols.cpp
+++ b/src/plugins/multimedia/ffmpeg/symbolstubs/qffmpegsymbols-va.cpp
@@ -1,65 +1,96 @@
-// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qlibrary.h>
-
-#include "qffmpegsymbolsresolveutils_p.h"
-
-#include <QtCore/qglobal.h>
-#include <qstringliteral.h>
+#include <QtMultimedia/private/qsymbolsresolveutils_p.h>
#include <va/va.h>
-#ifdef DYNAMIC_RESOLVE_VA_DRM_SYMBOLS
-#include <va/va_drm.h>
-#endif
-#ifdef DYNAMIC_RESOLVE_VA_X11_SYMBOLS
-#include <va/va_x11.h>
-#endif
#include <va/va_str.h>
-QT_BEGIN_NAMESPACE
-
-static Libs loadLibs()
-{
- constexpr int version = VA_MAJOR_VERSION + 1;
- Libs libs;
- libs.push_back(std::make_unique<QLibrary>("va", version));
-#ifdef DYNAMIC_RESOLVE_VA_DRM_SYMBOLS
- libs.push_back(std::make_unique<QLibrary>("va-drm", version));
+// VAAPI generated the actual *.so name due to the rule:
+// https://github.com/intel/libva/blob/master/configure.ac
+//
+// The library name is generated libva.<x>.<y>.0 where
+// <x> = VA-API major version + 1
+// <y> = 100 * VA-API minor version + VA-API micro version
+CHECK_VERSIONS("va", VA_NEEDED_SOVERSION, VA_MAJOR_VERSION + 1);
+
+#ifdef Q_FFMPEG_PLUGIN_STUBS_ONLY
+constexpr const char *loggingName = "va(in plugin)";
+#else
+constexpr const char *loggingName = nullptr;
#endif
-#ifdef DYNAMIC_RESOLVE_VA_X11_SYMBOLS
- libs.push_back(std::make_unique<QLibrary>("va-x11", version));
-#endif
+BEGIN_INIT_FUNCS("va", VA_NEEDED_SOVERSION, loggingName)
+
+
+INIT_FUNC(vaExportSurfaceHandle);
+INIT_FUNC(vaSyncSurface);
+INIT_FUNC(vaQueryVendorString);
- if (LibSymbolsResolver::tryLoad(libs))
- return libs;
+#ifndef Q_FFMPEG_PLUGIN_STUBS_ONLY
- return {};
-}
+INIT_FUNC(vaInitialize);
+INIT_FUNC(vaTerminate);
+INIT_FUNC(vaErrorStr);
+INIT_FUNC(vaSetErrorCallback);
+INIT_FUNC(vaSetInfoCallback);
-constexpr size_t symbolsCount = 40
+INIT_FUNC(vaCreateImage);
+INIT_FUNC(vaGetImage);
+INIT_FUNC(vaPutImage);
+INIT_FUNC(vaDeriveImage);
+INIT_FUNC(vaDestroyImage);
+INIT_FUNC(vaQueryImageFormats);
+
+INIT_FUNC(vaBeginPicture);
+INIT_FUNC(vaRenderPicture);
+INIT_FUNC(vaEndPicture);
+
+INIT_FUNC(vaCreateBuffer);
+INIT_FUNC(vaMapBuffer);
+INIT_FUNC(vaUnmapBuffer);
#if VA_CHECK_VERSION(1, 9, 0)
- + 1
+INIT_FUNC(vaSyncBuffer);
#endif
-#ifdef DYNAMIC_RESOLVE_VA_DRM_SYMBOLS
- + 1
-#endif
-#ifdef DYNAMIC_RESOLVE_VA_X11_SYMBOLS
- + 1
+INIT_FUNC(vaDestroyBuffer);
+
+INIT_FUNC(vaCreateSurfaces);
+INIT_FUNC(vaDestroySurfaces);
+
+INIT_FUNC(vaCreateConfig);
+INIT_FUNC(vaGetConfigAttributes);
+INIT_FUNC(vaMaxNumProfiles);
+INIT_FUNC(vaMaxNumImageFormats);
+INIT_FUNC(vaMaxNumEntrypoints);
+INIT_FUNC(vaQueryConfigProfiles);
+INIT_FUNC(vaQueryConfigEntrypoints);
+INIT_FUNC(vaQuerySurfaceAttributes);
+INIT_FUNC(vaDestroyConfig);
+
+INIT_FUNC(vaCreateContext);
+INIT_FUNC(vaDestroyContext);
+
+INIT_FUNC(vaProfileStr);
+INIT_FUNC(vaEntrypointStr);
+
+INIT_FUNC(vaGetDisplayAttributes);
+
+INIT_FUNC(vaSetDriverName);
+
+INIT_FUNC(vaAcquireBufferHandle);
+INIT_FUNC(vaReleaseBufferHandle);
+
#endif
- ;
-Q_GLOBAL_STATIC(LibSymbolsResolver, resolver, "VAAPI", symbolsCount, loadLibs);
+END_INIT_FUNCS()
-void resolveVAAPI()
-{
- resolver()->resolve();
-}
+constexpr auto emptyString = "";
-QT_END_NAMESPACE
+DEFINE_FUNC(vaExportSurfaceHandle, 5, VA_STATUS_ERROR_OPERATION_FAILED);
+DEFINE_FUNC(vaSyncSurface, 2, VA_STATUS_ERROR_OPERATION_FAILED);
+DEFINE_FUNC(vaQueryVendorString, 1, emptyString);
-QT_USE_NAMESPACE
+#ifndef Q_FFMPEG_PLUGIN_STUBS_ONLY
DEFINE_FUNC(vaInitialize, 3, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaTerminate, 1, VA_STATUS_ERROR_OPERATION_FAILED);
@@ -89,8 +120,6 @@ DEFINE_FUNC(vaSyncBuffer, 3, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaDestroyBuffer, 2, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaCreateSurfaces, 8, VA_STATUS_ERROR_OPERATION_FAILED);
-DEFINE_FUNC(vaSyncSurface, 2, VA_STATUS_ERROR_OPERATION_FAILED);
-DEFINE_FUNC(vaExportSurfaceHandle, 5, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaDestroySurfaces, 3, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaCreateConfig, 6, VA_STATUS_ERROR_OPERATION_FAILED);
@@ -106,8 +135,7 @@ DEFINE_FUNC(vaDestroyConfig, 2, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaCreateContext, 8);
DEFINE_FUNC(vaDestroyContext, 2);
-constexpr auto emptyString = "";
-DEFINE_FUNC(vaQueryVendorString, 1, emptyString);
+
DEFINE_FUNC(vaProfileStr, 1, emptyString);
DEFINE_FUNC(vaEntrypointStr, 1, emptyString);
@@ -118,10 +146,5 @@ DEFINE_FUNC(vaSetDriverName, 2, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaAcquireBufferHandle, 3, VA_STATUS_ERROR_OPERATION_FAILED);
DEFINE_FUNC(vaReleaseBufferHandle, 2, VA_STATUS_ERROR_OPERATION_FAILED);
-#ifdef DYNAMIC_RESOLVE_VA_DRM_SYMBOLS
-DEFINE_FUNC(vaGetDisplayDRM, 1); // va-drm
#endif
-#ifdef DYNAMIC_RESOLVE_VA_X11_SYMBOLS
-DEFINE_FUNC(vaGetDisplay, 1); // va-x11
-#endif
diff --git a/src/plugins/multimedia/ffmpeg/symbolstubs/va.ver b/src/plugins/multimedia/ffmpeg/symbolstubs/va.ver
new file mode 100644
index 000000000..80c9a6dc0
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/symbolstubs/va.ver
@@ -0,0 +1,7 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+VA_API_0.33.0 {
+ global:
+ vaCreateSurfaces;
+};
diff --git a/src/plugins/multimedia/gstreamer/CMakeLists.txt b/src/plugins/multimedia/gstreamer/CMakeLists.txt
index 80fc1fce0..1ef1f9a36 100644
--- a/src/plugins/multimedia/gstreamer/CMakeLists.txt
+++ b/src/plugins/multimedia/gstreamer/CMakeLists.txt
@@ -8,8 +8,6 @@ qt_internal_add_module(QGstreamerMediaPluginPrivate
INTERNAL_MODULE
SOURCES
audio/qgstreameraudiodevice.cpp audio/qgstreameraudiodevice_p.h
- audio/qgstreameraudiosource.cpp audio/qgstreameraudiosource_p.h
- audio/qgstreameraudiosink.cpp audio/qgstreameraudiosink_p.h
audio/qgstreameraudiodecoder.cpp audio/qgstreameraudiodecoder_p.h
common/qglist_helper_p.h
common/qgst.cpp common/qgst_p.h
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp
index 0cfa28169..513ab8dae 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp
@@ -21,8 +21,6 @@
#include <QtCore/qurl.h>
#include <QtCore/qloggingcategory.h>
-#define MAX_BUFFERS_IN_QUEUE 4
-
QT_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(qLcGstreamerAudioDecoder, "qt.multimedia.gstreameraudiodecoder");
@@ -42,23 +40,22 @@ typedef enum {
QMaybe<QPlatformAudioDecoder *> QGstreamerAudioDecoder::create(QAudioDecoder *parent)
{
- QGstElement audioconvert = QGstElement::createFromFactory("audioconvert", "audioconvert");
- if (!audioconvert)
- return errorMessageCannotFindElement("audioconvert");
-
- QGstPipeline playbin = QGstPipeline::adopt(
- GST_PIPELINE_CAST(QGstElement::createFromFactory("playbin", "playbin").element()));
- if (!playbin)
- return errorMessageCannotFindElement("playbin");
+ static const auto error = qGstErrorMessageIfElementsNotAvailable("audioconvert", "playbin");
+ if (error)
+ return *error;
- return new QGstreamerAudioDecoder(playbin, audioconvert, parent);
+ return new QGstreamerAudioDecoder(parent);
}
-QGstreamerAudioDecoder::QGstreamerAudioDecoder(QGstPipeline playbin, QGstElement audioconvert,
- QAudioDecoder *parent)
+QGstreamerAudioDecoder::QGstreamerAudioDecoder(QAudioDecoder *parent)
: QPlatformAudioDecoder(parent),
- m_playbin(std::move(playbin)),
- m_audioConvert(std::move(audioconvert))
+ m_playbin{
+ QGstPipeline::adopt(GST_PIPELINE_CAST(
+ QGstElement::createFromFactory("playbin", "playbin").element())),
+ },
+ m_audioConvert{
+ QGstElement::createFromFactory("audioconvert", "audioconvert"),
+ }
{
// Sort out messages
m_playbin.installMessageFilter(this);
@@ -336,14 +333,14 @@ void QGstreamerAudioDecoder::stop()
bufferAvailableChanged(false);
}
- if (m_position != -1) {
- m_position = -1;
- positionChanged(m_position);
+ if (m_position != invalidPosition) {
+ m_position = invalidPosition;
+ positionChanged(m_position.count());
}
- if (m_duration != -1) {
- m_duration = -1;
- durationChanged(m_duration);
+ if (m_duration != invalidDuration) {
+ m_duration = invalidDuration;
+ durationChanged(m_duration.count());
}
setIsDecoding(false);
@@ -364,6 +361,8 @@ void QGstreamerAudioDecoder::setAudioFormat(const QAudioFormat &format)
QAudioBuffer QGstreamerAudioDecoder::read()
{
+ using namespace std::chrono;
+
QAudioBuffer audioBuffer;
if (m_buffersAvailable == 0)
@@ -385,12 +384,16 @@ QAudioBuffer QGstreamerAudioDecoder::read()
if (format.isValid()) {
// XXX At the moment we have to copy data from GstBuffer into QAudioBuffer.
// We could improve performance by implementing QAbstractAudioBuffer for GstBuffer.
- qint64 position = getPositionFromBuffer(buffer);
- audioBuffer = QAudioBuffer(QByteArray(bufferData, bufferSize), format, position);
- position /= 1000; // convert to milliseconds
+ nanoseconds position = getPositionFromBuffer(buffer);
+ audioBuffer = QAudioBuffer{
+ QByteArray(bufferData, bufferSize),
+ format,
+ round<microseconds>(position).count(),
+ };
+ milliseconds positionInMs = round<milliseconds>(position);
if (position != m_position) {
- m_position = position;
- positionChanged(m_position);
+ m_position = positionInMs;
+ positionChanged(m_position.count());
}
}
gst_buffer_unmap(buffer, &mapInfo);
@@ -400,12 +403,12 @@ QAudioBuffer QGstreamerAudioDecoder::read()
qint64 QGstreamerAudioDecoder::position() const
{
- return m_position;
+ return m_position.count();
}
qint64 QGstreamerAudioDecoder::duration() const
{
- return m_duration;
+ return m_duration.count();
}
void QGstreamerAudioDecoder::processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString)
@@ -452,6 +455,8 @@ void QGstreamerAudioDecoder::setAudioFlags(bool wantNativeAudio)
void QGstreamerAudioDecoder::addAppSink()
{
+ using namespace std::chrono_literals;
+
if (m_appSink)
return;
@@ -460,8 +465,17 @@ void QGstreamerAudioDecoder::addAppSink()
GstAppSinkCallbacks callbacks{};
callbacks.new_sample = new_sample;
m_appSink.setCallbacks(callbacks, this, nullptr);
- gst_app_sink_set_max_buffers(m_appSink.appSink(), MAX_BUFFERS_IN_QUEUE);
- gst_base_sink_set_sync(m_appSink.baseSink(), FALSE);
+
+#if GST_CHECK_VERSION(1, 24, 0)
+ static constexpr auto maxBufferTime = 500ms;
+ m_appSink.setMaxBufferTime(maxBufferTime);
+#else
+ static constexpr int maxBuffers = 16;
+ m_appSink.setMaxBuffers(maxBuffers);
+#endif
+
+ static constexpr bool sync = false;
+ m_appSink.setSync(sync);
QGstPipeline::modifyPipelineWhileNotRunning(m_playbin.getPipeline(), [&] {
m_outputBin.add(m_appSink);
@@ -485,14 +499,14 @@ void QGstreamerAudioDecoder::removeAppSink()
void QGstreamerAudioDecoder::updateDuration()
{
- int duration = m_playbin.duration() / 1000000;
+ std::chrono::milliseconds duration = m_playbin.durationInMs();
if (m_duration != duration) {
m_duration = duration;
- durationChanged(m_duration);
+ durationChanged(m_duration.count());
}
- if (m_duration > 0)
+ if (m_duration.count() > 0)
m_durationQueries = 0;
if (m_durationQueries > 0) {
@@ -503,14 +517,15 @@ void QGstreamerAudioDecoder::updateDuration()
}
}
-qint64 QGstreamerAudioDecoder::getPositionFromBuffer(GstBuffer* buffer)
+std::chrono::nanoseconds QGstreamerAudioDecoder::getPositionFromBuffer(GstBuffer *buffer)
{
- qint64 position = GST_BUFFER_TIMESTAMP(buffer);
- if (position >= 0)
- position = position / G_GINT64_CONSTANT(1000); // microseconds
+ using namespace std::chrono;
+ using namespace std::chrono_literals;
+ nanoseconds position{ GST_BUFFER_TIMESTAMP(buffer) };
+ if (position >= 0ns)
+ return position;
else
- position = -1;
- return position;
+ return invalidPosition;
}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h
index eba1025fa..6415fa824 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h
@@ -68,7 +68,7 @@ private slots:
void updateDuration();
private:
- QGstreamerAudioDecoder(QGstPipeline playbin, QGstElement audioconvert, QAudioDecoder *parent);
+ explicit QGstreamerAudioDecoder(QAudioDecoder *parent);
#if QT_CONFIG(gstreamer_app)
static GstFlowReturn new_sample(GstAppSink *sink, gpointer user_data);
@@ -85,7 +85,7 @@ private:
bool handlePlaybinMessage(const QGstreamerMessage &);
void processInvalidMedia(QAudioDecoder::Error errorCode, const QString &errorString);
- static qint64 getPositionFromBuffer(GstBuffer* buffer);
+ static std::chrono::nanoseconds getPositionFromBuffer(GstBuffer *buffer);
QGstPipeline m_playbin;
QGstBin m_outputBin;
@@ -98,8 +98,11 @@ private:
QAudioFormat mFormat;
int m_buffersAvailable = 0;
- qint64 m_position = -1;
- qint64 m_duration = -1;
+
+ static constexpr auto invalidDuration = std::chrono::milliseconds::max();
+ static constexpr auto invalidPosition = std::chrono::milliseconds::max();
+ std::chrono::milliseconds m_position{ invalidPosition };
+ std::chrono::milliseconds m_duration{ invalidDuration };
int m_durationQueries = 0;
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp
index 2c6b57e55..dc6975030 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp
@@ -49,6 +49,29 @@ QGStreamerAudioDeviceInfo::QGStreamerAudioDeviceInfo(GstDevice *d, const QByteAr
preferredFormat.setSampleFormat(f);
}
-QGStreamerAudioDeviceInfo::~QGStreamerAudioDeviceInfo() = default;
+QGStreamerCustomAudioDeviceInfo::QGStreamerCustomAudioDeviceInfo(
+ const QByteArray &gstreamerPipeline, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate{
+ gstreamerPipeline,
+ mode,
+ }
+{
+}
+
+QAudioDevice qMakeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline)
+{
+ auto deviceInfo = std::make_unique<QGStreamerCustomAudioDeviceInfo>(gstreamerPipeline,
+ QAudioDevice::Mode::Input);
+
+ return deviceInfo.release()->create();
+}
+
+QAudioDevice qMakeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline)
+{
+ auto deviceInfo = std::make_unique<QGStreamerCustomAudioDeviceInfo>(gstreamerPipeline,
+ QAudioDevice::Mode::Output);
+
+ return deviceInfo.release()->create();
+}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h
index dee0c40bc..34d25bceb 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h
@@ -19,11 +19,11 @@
#include <QtCore/qstringlist.h>
#include <QtCore/qlist.h>
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiodevice_p.h>
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodevice.h>
+#include <QtMultimedia/private/qaudiodevice_p.h>
-#include <common/qgst_handle_types_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgst_handle_types_p.h>
#include <gst/gst.h>
@@ -33,11 +33,19 @@ class QGStreamerAudioDeviceInfo : public QAudioDevicePrivate
{
public:
QGStreamerAudioDeviceInfo(GstDevice *gstDevice, const QByteArray &device, QAudioDevice::Mode mode);
- ~QGStreamerAudioDeviceInfo();
QGstDeviceHandle gstDevice;
};
+class QGStreamerCustomAudioDeviceInfo : public QAudioDevicePrivate
+{
+public:
+ QGStreamerCustomAudioDeviceInfo(const QByteArray &gstreamerPipeline, QAudioDevice::Mode mode);
+};
+
+QAudioDevice qMakeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline);
+QAudioDevice qMakeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline);
+
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp
deleted file mode 100644
index 6fd972524..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <QtMultimedia/private/qaudiohelpers_p.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <audio/qgstreameraudiosink_p.h>
-#include <audio/qgstreameraudiodevice_p.h>
-#include <common/qgst_debug_p.h>
-#include <common/qgstappsource_p.h>
-#include <common/qgstpipeline_p.h>
-#include <common/qgstreamermessage_p.h>
-#include <common/qgstutils_p.h>
-
-#include <utility>
-
-QT_BEGIN_NAMESPACE
-
-QMaybe<QPlatformAudioSink *> QGStreamerAudioSink::create(const QAudioDevice &device, QObject *parent)
-{
- auto maybeAppSrc = QGstAppSource::create();
- if (!maybeAppSrc)
- return maybeAppSrc.error();
-
- QGstElement audioconvert = QGstElement::createFromFactory("audioconvert", "conv");
- if (!audioconvert)
- return errorMessageCannotFindElement("audioconvert");
-
- QGstElement volume = QGstElement::createFromFactory("volume", "volume");
- if (!volume)
- return errorMessageCannotFindElement("volume");
-
- return new QGStreamerAudioSink(device, maybeAppSrc.value(), audioconvert, volume, parent);
-}
-
-QGStreamerAudioSink::QGStreamerAudioSink(const QAudioDevice &device, QGstAppSource *appsrc,
- QGstElement audioconvert, QGstElement volume,
- QObject *parent)
- : QPlatformAudioSink(parent),
- m_device(device.id()),
- gstPipeline(QGstPipeline::create("audioSinkPipeline")),
- gstVolume(std::move(volume)),
- m_appSrc(appsrc)
-{
- gstPipeline.installMessageFilter(this);
-
- connect(m_appSrc, &QGstAppSource::bytesProcessed, this, &QGStreamerAudioSink::bytesProcessedByAppSrc);
- connect(m_appSrc, &QGstAppSource::noMoreData, this, &QGStreamerAudioSink::needData);
- gstAppSrc = m_appSrc->element();
-
- QGstElement queue = QGstElement::createFromFactory("queue", "audioSinkQueue");
-
- if (m_volume != 1.)
- gstVolume.set("volume", m_volume);
-
- // link decodeBin to audioconvert in a callback once we get a pad from the decoder
- // g_signal_connect (gstDecodeBin, "pad-added", (GCallback) padAdded, conv);
-
- const auto *audioInfo = static_cast<const QGStreamerAudioDeviceInfo *>(device.handle());
- gstOutput = QGstElement::createFromDevice(audioInfo->gstDevice, nullptr);
-
- gstPipeline.add(gstAppSrc, queue, /*gstDecodeBin, */ audioconvert, gstVolume, gstOutput);
- qLinkGstElements(gstAppSrc, queue, audioconvert, gstVolume, gstOutput);
-}
-
-QGStreamerAudioSink::~QGStreamerAudioSink()
-{
- close();
- gstPipeline.removeMessageFilter(this);
-
- gstPipeline = {};
- gstVolume = {};
- gstAppSrc = {};
- delete m_appSrc;
- m_appSrc = nullptr;
-}
-
-void QGStreamerAudioSink::setError(QAudio::Error error)
-{
- if (m_errorState == error)
- return;
-
- m_errorState = error;
- emit errorChanged(error);
-}
-
-QAudio::Error QGStreamerAudioSink::error() const
-{
- return m_errorState;
-}
-
-void QGStreamerAudioSink::setState(QAudio::State state)
-{
- if (m_deviceState == state)
- return;
-
- m_deviceState = state;
- emit stateChanged(state);
-}
-
-QAudio::State QGStreamerAudioSink::state() const
-{
- return m_deviceState;
-}
-
-void QGStreamerAudioSink::start(QIODevice *device)
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!m_format.isValid()) {
- setError(QAudio::OpenError);
- return;
- }
-
- m_pullMode = true;
- m_audioSource = device;
-
- if (!open()) {
- m_audioSource = nullptr;
- setError(QAudio::OpenError);
- return;
- }
-
- setState(QAudio::ActiveState);
-}
-
-QIODevice *QGStreamerAudioSink::start()
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!m_format.isValid()) {
- setError(QAudio::OpenError);
- return nullptr;
- }
-
- m_pullMode = false;
-
- if (!open())
- return nullptr;
-
- m_audioSource = new GStreamerOutputPrivate(this);
- m_audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
-
- setState(QAudio::IdleState);
-
- return m_audioSource;
-}
-
-#if 0
-static void padAdded(GstElement *element, GstPad *pad, gpointer data)
-{
- GstElement *other = static_cast<GstElement *>(data);
-
- QGString name { gst_pad_get_name(pad)};
- qDebug("A new pad %s was created for %s\n", name, gst_element_get_name(element));
-
- qDebug("element %s will be linked to %s\n",
- gst_element_get_name(element),
- gst_element_get_name(other));
- gst_element_link(element, other);
-}
-#endif
-
-bool QGStreamerAudioSink::processBusMessage(const QGstreamerMessage &message)
-{
- auto *msg = message.message();
- switch (GST_MESSAGE_TYPE (msg)) {
- case GST_MESSAGE_EOS:
- setState(QAudio::IdleState);
- break;
- case GST_MESSAGE_ERROR: {
- setError(QAudio::IOError);
- qDebug() << "Error:" << QCompactGstMessageAdaptor(message);
- break;
- }
- default:
- break;
- }
-
- return true;
-}
-
-bool QGStreamerAudioSink::open()
-{
- if (m_opened)
- return true;
-
- if (gstOutput.isNull()) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
-// qDebug() << "GST caps:" << gst_caps_to_string(caps);
- m_appSrc->setup(m_audioSource, m_audioSource ? m_audioSource->pos() : 0);
- m_appSrc->setAudioFormat(m_format);
-
- /* run */
- gstPipeline.setState(GST_STATE_PLAYING);
-
- m_opened = true;
-
- m_timeStamp.restart();
- m_bytesProcessed = 0;
-
- return true;
-}
-
-void QGStreamerAudioSink::close()
-{
- if (!m_opened)
- return;
-
- if (!gstPipeline.setStateSync(GST_STATE_NULL))
- qWarning() << "failed to close the audio output stream";
-
- if (!m_pullMode && m_audioSource)
- delete m_audioSource;
- m_audioSource = nullptr;
- m_opened = false;
-}
-
-qint64 QGStreamerAudioSink::write(const char *data, qint64 len)
-{
- if (!len)
- return 0;
- if (m_errorState == QAudio::UnderrunError)
- m_errorState = QAudio::NoError;
-
- m_appSrc->write(data, len);
- return len;
-}
-
-void QGStreamerAudioSink::stop()
-{
- if (m_deviceState == QAudio::StoppedState)
- return;
-
- close();
-
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
-}
-
-qsizetype QGStreamerAudioSink::bytesFree() const
-{
- if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState)
- return 0;
-
- return m_appSrc->canAcceptMoreData() ? 4096*4 : 0;
-}
-
-void QGStreamerAudioSink::setBufferSize(qsizetype value)
-{
- m_bufferSize = value;
- if (!gstAppSrc.isNull())
- gst_app_src_set_max_bytes(GST_APP_SRC(gstAppSrc.element()), value);
-}
-
-qsizetype QGStreamerAudioSink::bufferSize() const
-{
- return m_bufferSize;
-}
-
-qint64 QGStreamerAudioSink::processedUSecs() const
-{
- qint64 result = qint64(1000000) * m_bytesProcessed /
- m_format.bytesPerFrame() /
- m_format.sampleRate();
-
- return result;
-}
-
-void QGStreamerAudioSink::resume()
-{
- if (m_deviceState == QAudio::SuspendedState) {
- m_appSrc->resume();
- gstPipeline.setState(GST_STATE_PLAYING);
-
- setState(m_suspendedInState);
- setError(QAudio::NoError);
- }
-}
-
-void QGStreamerAudioSink::setFormat(const QAudioFormat &format)
-{
- m_format = format;
-}
-
-QAudioFormat QGStreamerAudioSink::format() const
-{
- return m_format;
-}
-
-void QGStreamerAudioSink::suspend()
-{
- if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::IdleState) {
- m_suspendedInState = m_deviceState;
- setError(QAudio::NoError);
- setState(QAudio::SuspendedState);
-
- gstPipeline.setState(GST_STATE_PAUSED);
- m_appSrc->suspend();
- // ### elapsed time
- }
-}
-
-void QGStreamerAudioSink::reset()
-{
- stop();
-}
-
-GStreamerOutputPrivate::GStreamerOutputPrivate(QGStreamerAudioSink *audio)
-{
- m_audioDevice = audio;
-}
-
-qint64 GStreamerOutputPrivate::readData(char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- return 0;
-}
-
-qint64 GStreamerOutputPrivate::writeData(const char *data, qint64 len)
-{
- if (m_audioDevice->state() == QAudio::IdleState)
- m_audioDevice->setState(QAudio::ActiveState);
- return m_audioDevice->write(data, len);
-}
-
-void QGStreamerAudioSink::setVolume(qreal vol)
-{
- if (m_volume == vol)
- return;
-
- m_volume = vol;
- if (!gstVolume.isNull())
- gstVolume.set("volume", vol);
-}
-
-qreal QGStreamerAudioSink::volume() const
-{
- return m_volume;
-}
-
-void QGStreamerAudioSink::bytesProcessedByAppSrc(int bytes)
-{
- m_bytesProcessed += bytes;
- setState(QAudio::ActiveState);
- setError(QAudio::NoError);
-}
-
-void QGStreamerAudioSink::needData()
-{
- if (state() != QAudio::StoppedState && state() != QAudio::IdleState) {
- setState(QAudio::IdleState);
- setError(m_audioSource && m_audioSource->atEnd() ? QAudio::NoError : QAudio::UnderrunError);
- }
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qgstreameraudiosink_p.cpp"
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h
deleted file mode 100644
index 1aadb2290..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QAUDIOOUTPUTGSTREAMER_H
-#define QAUDIOOUTPUTGSTREAMER_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 <QtCore/qfile.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/private/qringbuffer_p.h>
-
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiosystem_p.h>
-#include <private/qmultimediautils_p.h>
-
-#include <common/qgst_p.h>
-#include <common/qgstpipeline_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstAppSource;
-
-class QGStreamerAudioSink
- : public QPlatformAudioSink,
- public QGstreamerBusMessageFilter
-{
- friend class GStreamerOutputPrivate;
- Q_OBJECT
-
-public:
- static QMaybe<QPlatformAudioSink *> create(const QAudioDevice &device, QObject *parent);
- ~QGStreamerAudioSink();
-
- void start(QIODevice *device) override;
- QIODevice *start() override;
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- qsizetype bytesFree() const override;
- void setBufferSize(qsizetype value) override;
- qsizetype bufferSize() const override;
- qint64 processedUSecs() const override;
- QAudio::Error error() const override;
- QAudio::State state() const override;
- void setFormat(const QAudioFormat &format) override;
- QAudioFormat format() const override;
-
- void setVolume(qreal volume) override;
- qreal volume() const override;
-
-private Q_SLOTS:
- void bytesProcessedByAppSrc(int bytes);
- void needData();
-
-private:
- QGStreamerAudioSink(const QAudioDevice &device, QGstAppSource *appsrc, QGstElement audioconvert,
- QGstElement volume, QObject *parent);
-
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
- bool processBusMessage(const QGstreamerMessage &message) override;
-
- bool open();
- void close();
- qint64 write(const char *data, qint64 len);
-
-private:
- QByteArray m_device;
- QAudioFormat m_format;
- QAudio::Error m_errorState = QAudio::NoError;
- QAudio::State m_deviceState = QAudio::StoppedState;
- QAudio::State m_suspendedInState = QAudio::SuspendedState;
- bool m_pullMode = true;
- bool m_opened = false;
- QIODevice *m_audioSource = nullptr;
- int m_bufferSize = 0;
- qint64 m_bytesProcessed = 0;
- QElapsedTimer m_timeStamp;
- qreal m_volume = 1.;
- QByteArray pushData;
-
- QGstPipeline gstPipeline;
- QGstElement gstOutput;
- QGstElement gstVolume;
- QGstElement gstAppSrc;
- QGstAppSource *m_appSrc = nullptr;
-};
-
-class GStreamerOutputPrivate : public QIODevice
-{
- friend class QGStreamerAudioSink;
- Q_OBJECT
-
-public:
- explicit GStreamerOutputPrivate(QGStreamerAudioSink *audio);
-
-protected:
- qint64 readData(char *data, qint64 len) override;
- qint64 writeData(const char *data, qint64 len) override;
-
-private:
- QGStreamerAudioSink *m_audioDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp
deleted file mode 100644
index 829d116a2..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp
+++ /dev/null
@@ -1,366 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <QtMultimedia/private/qaudiohelpers_p.h>
-
-#include "qgstreameraudiosource_p.h"
-#include "qgstreameraudiodevice_p.h"
-#include "common/qgst_p.h"
-#include "common/qgst_debug_p.h"
-
-#include <sys/types.h>
-#include <unistd.h>
-
-Q_DECLARE_OPAQUE_POINTER(GstSample *);
-Q_DECLARE_METATYPE(GstSample *);
-
-QT_BEGIN_NAMESPACE
-
-QGStreamerAudioSource::QGStreamerAudioSource(const QAudioDevice &device, QObject *parent)
- : QPlatformAudioSource(parent),
- m_info(device),
- m_device(device.id())
-{
- qRegisterMetaType<GstSample *>();
-}
-
-QGStreamerAudioSource::~QGStreamerAudioSource()
-{
- close();
-}
-
-void QGStreamerAudioSource::setError(QAudio::Error error)
-{
- if (m_errorState == error)
- return;
-
- m_errorState = error;
- emit errorChanged(error);
-}
-
-QAudio::Error QGStreamerAudioSource::error() const
-{
- return m_errorState;
-}
-
-void QGStreamerAudioSource::setState(QAudio::State state)
-{
- if (m_deviceState == state)
- return;
-
- m_deviceState = state;
- emit stateChanged(state);
-}
-
-QAudio::State QGStreamerAudioSource::state() const
-{
- return m_deviceState;
-}
-
-void QGStreamerAudioSource::setFormat(const QAudioFormat &format)
-{
- if (m_deviceState == QAudio::StoppedState)
- m_format = format;
-}
-
-QAudioFormat QGStreamerAudioSource::format() const
-{
- return m_format;
-}
-
-void QGStreamerAudioSource::start(QIODevice *device)
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!open())
- return;
-
- m_pullMode = true;
- m_audioSink = device;
-
- setState(QAudio::ActiveState);
-}
-
-QIODevice *QGStreamerAudioSource::start()
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!open())
- return nullptr;
-
- m_pullMode = false;
- m_audioSink = new GStreamerInputPrivate(this);
- m_audioSink->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
-
- setState(QAudio::IdleState);
-
- return m_audioSink;
-}
-
-void QGStreamerAudioSource::stop()
-{
- if (m_deviceState == QAudio::StoppedState)
- return;
-
- close();
-
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
-}
-
-bool QGStreamerAudioSource::open()
-{
- if (m_opened)
- return true;
-
- const auto *deviceInfo = static_cast<const QGStreamerAudioDeviceInfo *>(m_info.handle());
- if (!deviceInfo->gstDevice) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
- gstInput = QGstElement::createFromDevice(deviceInfo->gstDevice);
- if (gstInput.isNull()) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
- auto gstCaps = QGstUtils::capsForAudioFormat(m_format);
-
- if (gstCaps.isNull()) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
-
-#ifdef DEBUG_AUDIO
- qDebug() << "Opening input" << QTime::currentTime();
- qDebug() << "Caps: " << gst_caps_to_string(gstCaps);
-#endif
-
- gstPipeline = QGstPipeline::create("audioSourcePipeline");
-
- auto *gstBus = gst_pipeline_get_bus(gstPipeline.pipeline());
- gst_bus_add_watch(gstBus, &QGStreamerAudioSource::busMessage, this);
- gst_object_unref (gstBus);
-
- gstAppSink = createAppSink();
- gstAppSink.set("caps", gstCaps);
-
- QGstElement conv = QGstElement::createFromFactory("audioconvert", "conv");
- gstVolume = QGstElement::createFromFactory("volume", "volume");
- Q_ASSERT(gstVolume);
- if (m_volume != 1.)
- gstVolume.set("volume", m_volume);
-
- gstPipeline.add(gstInput, gstVolume, conv, gstAppSink);
- qLinkGstElements(gstInput, gstVolume, conv, gstAppSink);
-
- gstPipeline.setState(GST_STATE_PLAYING);
-
- m_opened = true;
-
- m_timeStamp.restart();
- m_elapsedTimeOffset = 0;
- m_bytesWritten = 0;
-
- return true;
-}
-
-void QGStreamerAudioSource::close()
-{
- if (!m_opened)
- return;
-
- gstPipeline.setState(GST_STATE_NULL);
- gstPipeline = {};
- gstVolume = {};
- gstAppSink = {};
- gstInput = {};
-
- if (!m_pullMode && m_audioSink) {
- delete m_audioSink;
- }
- m_audioSink = nullptr;
- m_opened = false;
-}
-
-gboolean QGStreamerAudioSource::busMessage(GstBus *, GstMessage *msg, gpointer user_data)
-{
- QGStreamerAudioSource *input = static_cast<QGStreamerAudioSource *>(user_data);
- switch (GST_MESSAGE_TYPE (msg)) {
- case GST_MESSAGE_EOS:
- input->stop();
- break;
- case GST_MESSAGE_ERROR: {
- input->setError(QAudio::IOError);
- qDebug() << "Error:" << QCompactGstMessageAdaptor(msg);
- break;
- }
- default:
- break;
- }
- return false;
-}
-
-qsizetype QGStreamerAudioSource::bytesReady() const
-{
- return m_buffer.size();
-}
-
-void QGStreamerAudioSource::resume()
-{
- if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) {
- gstPipeline.setState(GST_STATE_PLAYING);
- setState(QAudio::ActiveState);
- setError(QAudio::NoError);
- }
-}
-
-void QGStreamerAudioSource::setVolume(qreal vol)
-{
- if (m_volume == vol)
- return;
-
- m_volume = vol;
- if (!gstVolume.isNull())
- gstVolume.set("volume", vol);
-}
-
-qreal QGStreamerAudioSource::volume() const
-{
- return m_volume;
-}
-
-void QGStreamerAudioSource::setBufferSize(qsizetype value)
-{
- m_bufferSize = value;
-}
-
-qsizetype QGStreamerAudioSource::bufferSize() const
-{
- return m_bufferSize;
-}
-
-qint64 QGStreamerAudioSource::processedUSecs() const
-{
- return m_format.durationForBytes(m_bytesWritten);
-}
-
-void QGStreamerAudioSource::suspend()
-{
- if (m_deviceState == QAudio::ActiveState) {
- setError(QAudio::NoError);
- setState(QAudio::SuspendedState);
-
- gstPipeline.setState(GST_STATE_PAUSED);
- }
-}
-
-void QGStreamerAudioSource::reset()
-{
- stop();
- m_buffer.clear();
-}
-
-//#define MAX_BUFFERS_IN_QUEUE 4
-
-QGstAppSink QGStreamerAudioSource::createAppSink()
-{
- QGstAppSink sink = QGstAppSink::create("appsink");
-
- GstAppSinkCallbacks callbacks{};
- callbacks.eos = eos;
- callbacks.new_sample = new_sample;
- sink.setCallbacks(callbacks, this, nullptr);
- // gst_app_sink_set_max_buffers(sink.appSink(), MAX_BUFFERS_IN_QUEUE);
- gst_base_sink_set_sync(sink.baseSink(), FALSE);
-
- return sink;
-}
-
-void QGStreamerAudioSource::newDataAvailable(QGstSampleHandle sample)
-{
- if (m_audioSink) {
- GstBuffer *buffer = gst_sample_get_buffer(sample.get());
- GstMapInfo mapInfo;
- gst_buffer_map(buffer, &mapInfo, GST_MAP_READ);
- const char *bufferData = (const char*)mapInfo.data;
- gsize bufferSize = mapInfo.size;
-
- if (!m_pullMode) {
- // need to store that data in the QBuffer
- m_buffer.append(bufferData, bufferSize);
- m_audioSink->readyRead();
- } else {
- m_bytesWritten += bufferSize;
- m_audioSink->write(bufferData, bufferSize);
- }
-
- gst_buffer_unmap(buffer, &mapInfo);
- }
-}
-
-GstFlowReturn QGStreamerAudioSource::new_sample(GstAppSink *sink, gpointer user_data)
-{
- // "Note that the preroll buffer will also be returned as the first buffer when calling gst_app_sink_pull_buffer()."
- QGStreamerAudioSource *control = static_cast<QGStreamerAudioSource*>(user_data);
-
- QGstSampleHandle sample{
- gst_app_sink_pull_sample(sink),
- QGstSampleHandle::HasRef,
- };
-
- QMetaObject::invokeMethod(control, [control, sample = std::move(sample)]() mutable {
- control->newDataAvailable(std::move(sample));
- });
-
- return GST_FLOW_OK;
-}
-
-void QGStreamerAudioSource::eos(GstAppSink *, gpointer user_data)
-{
- QGStreamerAudioSource *control = static_cast<QGStreamerAudioSource*>(user_data);
- control->setState(QAudio::StoppedState);
-}
-
-GStreamerInputPrivate::GStreamerInputPrivate(QGStreamerAudioSource *audio)
-{
- m_audioDevice = audio;
-}
-
-qint64 GStreamerInputPrivate::readData(char *data, qint64 len)
-{
- if (m_audioDevice->state() == QAudio::IdleState)
- m_audioDevice->setState(QAudio::ActiveState);
- qint64 bytes = m_audioDevice->m_buffer.read(data, len);
- m_audioDevice->m_bytesWritten += bytes;
- return bytes;
-}
-
-qint64 GStreamerInputPrivate::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
- return 0;
-}
-
-qint64 GStreamerInputPrivate::bytesAvailable() const
-{
- return m_audioDevice->m_buffer.size();
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h
deleted file mode 100644
index 9021f1ddd..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of other Qt classes. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#ifndef QAUDIOINPUTGSTREAMER_H
-#define QAUDIOINPUTGSTREAMER_H
-
-#include <QtCore/qfile.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/private/qringbuffer_p.h>
-
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiosystem_p.h>
-
-#include <common/qgstutils_p.h>
-#include <common/qgstpipeline_p.h>
-
-#include <gst/app/gstappsink.h>
-
-QT_BEGIN_NAMESPACE
-
-class GStreamerInputPrivate;
-
-class QGStreamerAudioSource
- : public QPlatformAudioSource
-{
- friend class GStreamerInputPrivate;
-public:
- QGStreamerAudioSource(const QAudioDevice &device, QObject *parent);
- ~QGStreamerAudioSource();
-
- void start(QIODevice *device) override;
- QIODevice *start() override;
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- qsizetype bytesReady() const override;
- void setBufferSize(qsizetype value) override;
- qsizetype bufferSize() const override;
- qint64 processedUSecs() const override;
- QAudio::Error error() const override;
- QAudio::State state() const override;
- void setFormat(const QAudioFormat &format) override;
- QAudioFormat format() const override;
-
- void setVolume(qreal volume) override;
- qreal volume() const override;
-
-private:
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
- QGstAppSink createAppSink();
- static GstFlowReturn new_sample(GstAppSink *, gpointer user_data);
- static void eos(GstAppSink *, gpointer user_data);
-
- bool open();
- void close();
-
- static gboolean busMessage(GstBus *bus, GstMessage *msg, gpointer user_data);
-
- void newDataAvailable(QGstSampleHandle sample);
-
- QAudioDevice m_info;
- qint64 m_bytesWritten = 0;
- QIODevice *m_audioSink = nullptr;
- QAudioFormat m_format;
- QAudio::Error m_errorState = QAudio::NoError;
- QAudio::State m_deviceState = QAudio::StoppedState;
- qreal m_volume = 1.;
-
- QRingBuffer m_buffer;
- QAtomicInteger<bool> m_pullMode = true;
- bool m_opened = false;
- int m_bufferSize = 0;
- qint64 m_elapsedTimeOffset = 0;
- QElapsedTimer m_timeStamp;
- QByteArray m_device;
- QByteArray m_tempBuffer;
-
- QGstElement gstInput;
- QGstPipeline gstPipeline;
- QGstElement gstVolume;
- QGstAppSink gstAppSink;
-};
-
-class GStreamerInputPrivate : public QIODevice
-{
-public:
- explicit GStreamerInputPrivate(QGStreamerAudioSource *audio);
-
- qint64 readData(char *data, qint64 len) override;
- qint64 writeData(const char *data, qint64 len) override;
- qint64 bytesAvailable() const override;
- bool isSequential() const override { return true; }
-private:
- QGStreamerAudioSource *m_audioDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/multimedia/gstreamer/common/qgst.cpp b/src/plugins/multimedia/gstreamer/common/qgst.cpp
index 9e0a63488..4050ea06f 100644
--- a/src/plugins/multimedia/gstreamer/common/qgst.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgst.cpp
@@ -127,11 +127,11 @@ std::optional<QGRange<int>> QGValue::toIntRange() const
return QGRange<int>{ gst_value_get_int_range_min(value), gst_value_get_int_range_max(value) };
}
-QGstStructure QGValue::toStructure() const
+QGstStructureView QGValue::toStructure() const
{
if (!value || !GST_VALUE_HOLDS_STRUCTURE(value))
- return QGstStructure();
- return QGstStructure(gst_value_get_structure(value));
+ return QGstStructureView(nullptr);
+ return QGstStructureView(gst_value_get_structure(value));
}
QGstCaps QGValue::toCaps() const
@@ -156,38 +156,52 @@ QGValue QGValue::at(int index) const
return QGValue{ gst_value_list_get_value(value, index) };
}
-// QGstStructure
+// QGstStructureView
-QGstStructure::QGstStructure(const GstStructure *s) : structure(s) { }
+QGstStructureView::QGstStructureView(const GstStructure *s) : structure(s) { }
-void QGstStructure::free()
+QGstStructureView::QGstStructureView(const QUniqueGstStructureHandle &handle)
+ : QGstStructureView{ handle.get() }
{
- if (structure)
- gst_structure_free(const_cast<GstStructure *>(structure));
- structure = nullptr;
}
-bool QGstStructure::isNull() const
+QUniqueGstStructureHandle QGstStructureView::clone() const
+{
+ return QUniqueGstStructureHandle{ gst_structure_copy(structure) };
+}
+
+bool QGstStructureView::isNull() const
{
return !structure;
}
-QByteArrayView QGstStructure::name() const
+QByteArrayView QGstStructureView::name() const
{
return gst_structure_get_name(structure);
}
-QGValue QGstStructure::operator[](const char *name) const
+QGValue QGstStructureView::operator[](const char *fieldname) const
+{
+ return QGValue{ gst_structure_get_value(structure, fieldname) };
+}
+
+QGstCaps QGstStructureView::caps() const
{
- return QGValue{ gst_structure_get_value(structure, name) };
+ return operator[]("caps").toCaps();
}
-QGstStructure QGstStructure::copy() const
+QGstTagListHandle QGstStructureView::tags() const
{
- return gst_structure_copy(structure);
+ QGValue tags = operator[]("tags");
+ if (tags.isNull())
+ return {};
+
+ QGstTagListHandle tagList;
+ gst_structure_get(structure, "tags", GST_TYPE_TAG_LIST, &tagList, nullptr);
+ return tagList;
}
-QSize QGstStructure::resolution() const
+QSize QGstStructureView::resolution() const
{
QSize size;
@@ -201,7 +215,7 @@ QSize QGstStructure::resolution() const
return size;
}
-QVideoFrameFormat::PixelFormat QGstStructure::pixelFormat() const
+QVideoFrameFormat::PixelFormat QGstStructureView::pixelFormat() const
{
QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
@@ -224,7 +238,7 @@ QVideoFrameFormat::PixelFormat QGstStructure::pixelFormat() const
return pixelFormat;
}
-QGRange<float> QGstStructure::frameRateRange() const
+QGRange<float> QGstStructureView::frameRateRange() const
{
float minRate = 0.;
float maxRate = 0.;
@@ -276,14 +290,14 @@ QGRange<float> QGstStructure::frameRateRange() const
return { minRate, maxRate };
}
-QGstreamerMessage QGstStructure::getMessage()
+QGstreamerMessage QGstStructureView::getMessage()
{
GstMessage *message = nullptr;
gst_structure_get(structure, "message", GST_TYPE_MESSAGE, &message, nullptr);
return QGstreamerMessage(message, QGstreamerMessage::HasRef);
}
-std::optional<Fraction> QGstStructure::pixelAspectRatio() const
+std::optional<Fraction> QGstStructureView::pixelAspectRatio() const
{
gint numerator;
gint denominator;
@@ -297,7 +311,20 @@ std::optional<Fraction> QGstStructure::pixelAspectRatio() const
return std::nullopt;
}
-QSize QGstStructure::nativeSize() const
+// QTBUG-125249: gstreamer tries "to keep the input height (because of interlacing)". Can we align
+// the behavior between gstreamer and ffmpeg?
+static QSize qCalculateFrameSizeGStreamer(QSize resolution, Fraction par)
+{
+ if (par.numerator == par.denominator || par.numerator < 1 || par.denominator < 1)
+ return resolution;
+
+ return QSize{
+ resolution.width() * par.numerator / par.denominator,
+ resolution.height(),
+ };
+}
+
+QSize QGstStructureView::nativeSize() const
{
QSize size = resolution();
if (!size.isValid()) {
@@ -307,7 +334,7 @@ QSize QGstStructure::nativeSize() const
std::optional<Fraction> par = pixelAspectRatio();
if (par)
- size = qCalculateFrameSize(size, *par);
+ size = qCalculateFrameSizeGStreamer(size, *par);
return size;
}
@@ -505,9 +532,11 @@ int QGstCaps::size() const
return int(gst_caps_get_size(get()));
}
-QGstStructure QGstCaps::at(int index) const
+QGstStructureView QGstCaps::at(int index) const
{
- return gst_caps_get_structure(get(), index);
+ return QGstStructureView{
+ gst_caps_get_structure(get(), index),
+ };
}
GstCaps *QGstCaps::caps() const
@@ -574,11 +603,11 @@ QGString QGstObject::getString(const char *property) const
return QGString(s);
}
-QGstStructure QGstObject::getStructure(const char *property) const
+QGstStructureView QGstObject::getStructure(const char *property) const
{
GstStructure *s = nullptr;
g_object_get(get(), property, &s, nullptr);
- return QGstStructure(s);
+ return QGstStructureView(s);
}
bool QGstObject::getBool(const char *property) const
@@ -656,9 +685,11 @@ GType QGstObject::type() const
return G_OBJECT_TYPE(get());
}
-const char *QGstObject::typeName() const
+QLatin1StringView QGstObject::typeName() const
{
- return g_type_name(type());
+ return QLatin1StringView{
+ g_type_name(type()),
+ };
}
GstObject *QGstObject::object() const
@@ -666,9 +697,11 @@ GstObject *QGstObject::object() const
return get();
}
-const char *QGstObject::name() const
+QLatin1StringView QGstObject::name() const
{
- return get() ? GST_OBJECT_NAME(get()) : "(null)";
+ using namespace Qt::StringLiterals;
+
+ return get() ? QLatin1StringView{ GST_OBJECT_NAME(get()) } : "(null)"_L1;
}
// QGObjectHandlerConnection
@@ -736,6 +769,28 @@ QGstCaps QGstPad::queryCaps() const
return QGstCaps(gst_pad_query_caps(pad(), nullptr), QGstCaps::HasRef);
}
+QGstTagListHandle QGstPad::tags() const
+{
+ QGstTagListHandle tagList;
+ g_object_get(object(), "tags", &tagList, nullptr);
+ return tagList;
+}
+
+std::optional<QPlatformMediaPlayer::TrackType> QGstPad::inferTrackTypeFromName() const
+{
+ using namespace Qt::Literals;
+ QLatin1StringView padName = name();
+
+ if (padName.startsWith("video_"_L1))
+ return QPlatformMediaPlayer::TrackType::VideoStream;
+ if (padName.startsWith("audio_"_L1))
+ return QPlatformMediaPlayer::TrackType::AudioStream;
+ if (padName.startsWith("text_"_L1))
+ return QPlatformMediaPlayer::TrackType::SubtitleStream;
+
+ return std::nullopt;
+}
+
bool QGstPad::isLinked() const
{
return gst_pad_is_linked(pad());
@@ -882,6 +937,19 @@ QGstElement QGstElement::createFromPipelineDescription(const QByteArray &str)
return createFromPipelineDescription(str.constData());
}
+QGstElementFactoryHandle QGstElement::findFactory(const char *name)
+{
+ return QGstElementFactoryHandle{
+ gst_element_factory_find(name),
+ QGstElementFactoryHandle::HasRef,
+ };
+}
+
+QGstElementFactoryHandle QGstElement::findFactory(const QByteArray &name)
+{
+ return findFactory(name.constData());
+}
+
QGstPad QGstElement::staticPad(const char *name) const
{
return QGstPad(gst_element_get_static_pad(element(), name), HasRef);
@@ -933,14 +1001,23 @@ GstStateChangeReturn QGstElement::setState(GstState state)
bool QGstElement::setStateSync(GstState state, std::chrono::nanoseconds timeout)
{
+ if (state == GST_STATE_NULL) {
+ // QTBUG-125251: when changing pipeline state too quickly between NULL->PAUSED->NULL there
+ // may be a pending task to activate pads while we try to switch to NULL. This can cause an
+ // assertion failure in gstreamer. we therefore finish the state change when called on a bin
+ // or pipeline.
+ if (qIsGstObjectOfType<GstBin>(element()))
+ finishStateChange();
+ }
+
GstStateChangeReturn change = gst_element_set_state(element(), state);
- if (change == GST_STATE_CHANGE_ASYNC) {
+ if (change == GST_STATE_CHANGE_ASYNC)
change = gst_element_get_state(element(), nullptr, &state, timeout.count());
- }
-#ifndef QT_NO_DEBUG
- if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL)
+
+ if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) {
qWarning() << "Could not change state of" << name() << "to" << state << change;
-#endif
+ dumpPipelineGraph("setStatSyncFailure");
+ }
return change == GST_STATE_CHANGE_SUCCESS;
}
@@ -956,18 +1033,10 @@ bool QGstElement::finishStateChange(std::chrono::nanoseconds timeout)
GstStateChangeReturn change =
gst_element_get_state(element(), &state, &pending, timeout.count());
-#ifndef QT_NO_DEBUG
if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) {
qWarning() << "Could not finish change state of" << name() << change << state << pending;
-
- static const bool dumpEnabled = qEnvironmentVariableIsSet("GST_DEBUG_DUMP_DOT_DIR");
- if (dumpEnabled) {
- QGstPipeline pipeline = getPipeline();
- if (pipeline)
- pipeline.dumpGraph("finishStateChangeFailure");
- }
+ dumpPipelineGraph("finishStateChangeFailure");
}
-#endif
return change == GST_STATE_CHANGE_SUCCESS;
}
@@ -1031,6 +1100,16 @@ QGstPipeline QGstElement::getPipeline() const
}
}
+void QGstElement::dumpPipelineGraph(const char *filename) const
+{
+ static const bool dumpEnabled = qEnvironmentVariableIsSet("GST_DEBUG_DUMP_DOT_DIR");
+ if (dumpEnabled) {
+ QGstPipeline pipeline = getPipeline();
+ if (pipeline)
+ pipeline.dumpGraph(filename);
+ }
+}
+
// QGstBin
QGstBin QGstBin::create(const char *name)
@@ -1111,8 +1190,7 @@ void QGstBin::dumpGraph(const char *fileNamePrefix)
if (isNull())
return;
- GST_DEBUG_BIN_TO_DOT_FILE(bin(), GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL),
- fileNamePrefix);
+ GST_DEBUG_BIN_TO_DOT_FILE(bin(), GST_DEBUG_GRAPH_SHOW_VERBOSE, fileNamePrefix);
}
QGstElement QGstBin::findByName(const char *name)
@@ -1133,6 +1211,11 @@ QGstBaseSink::QGstBaseSink(GstBaseSink *element, RefMode mode)
{
}
+void QGstBaseSink::setSync(bool arg)
+{
+ gst_base_sink_set_sync(baseSink(), arg ? TRUE : FALSE);
+}
+
GstBaseSink *QGstBaseSink::baseSink() const
{
return qGstCheckedCast<GstBaseSink>(element());
@@ -1179,6 +1262,18 @@ GstAppSink *QGstAppSink::appSink() const
return qGstCheckedCast<GstAppSink>(element());
}
+# if GST_CHECK_VERSION(1, 24, 0)
+void QGstAppSink::setMaxBufferTime(std::chrono::nanoseconds ns)
+{
+ gst_app_sink_set_max_time(appSink(), qGstClockTimeFromChrono(ns));
+}
+# endif
+
+void QGstAppSink::setMaxBuffers(int n)
+{
+ gst_app_sink_set_max_buffers(appSink(), n);
+}
+
void QGstAppSink::setCaps(const QGstCaps &caps)
{
gst_app_sink_set_caps(appSink(), caps.caps());
@@ -1235,4 +1330,10 @@ GstFlowReturn QGstAppSrc::pushBuffer(GstBuffer *buffer)
#endif
+QString qGstErrorMessageCannotFindElement(std::string_view element)
+{
+ return QStringLiteral("Could not find the %1 GStreamer element")
+ .arg(QLatin1StringView(element));
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/common/qgst_debug.cpp b/src/plugins/multimedia/gstreamer/common/qgst_debug.cpp
index 6a7fdce6f..05b4d3f67 100644
--- a/src/plugins/multimedia/gstreamer/common/qgst_debug.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgst_debug.cpp
@@ -20,7 +20,7 @@ QDebug operator<<(QDebug dbg, const QGstCaps &caps)
return dbg << caps.caps();
}
-QDebug operator<<(QDebug dbg, const QGstStructure &structure)
+QDebug operator<<(QDebug dbg, const QGstStructureView &structure)
{
return dbg << structure.structure;
}
@@ -45,6 +45,16 @@ QDebug operator<<(QDebug dbg, const QUniqueGStringHandle &handle)
return dbg << handle.get();
}
+QDebug operator<<(QDebug dbg, const QGstStreamCollectionHandle &handle)
+{
+ return dbg << handle.get();
+}
+
+QDebug operator<<(QDebug dbg, const QGstStreamHandle &handle)
+{
+ return dbg << handle.get();
+}
+
QDebug operator<<(QDebug dbg, const QGstElement &element)
{
return dbg << element.element();
@@ -236,8 +246,26 @@ QDebug operator<<(QDebug dbg, const GstMessage *msg)
gst_message_parse_state_changed(const_cast<GstMessage *>(msg), &oldState, &newState,
&pending);
- dbg << ", OldState: " << oldState << ", NewState: " << newState
- << ", Pending State: " << pending;
+ dbg << ", Transition: " << oldState << "->" << newState;
+
+ if (pending != GST_STATE_VOID_PENDING)
+ dbg << ", Pending State: " << pending;
+ break;
+ }
+
+ case GST_MESSAGE_STREAM_COLLECTION: {
+ QGstStreamCollectionHandle collection;
+ gst_message_parse_stream_collection(const_cast<GstMessage *>(msg), &collection);
+
+ dbg << ", " << collection;
+ break;
+ }
+
+ case GST_MESSAGE_STREAMS_SELECTED: {
+ QGstStreamCollectionHandle collection;
+ gst_message_parse_streams_selected(const_cast<GstMessage *>(msg), &collection);
+
+ dbg << ", " << collection;
break;
}
@@ -275,6 +303,35 @@ QDebug operator<<(QDebug dbg, const GstPadTemplate *padTemplate)
return dbg;
}
+QDebug operator<<(QDebug dbg, const GstStreamCollection *streamCollection)
+{
+ GstStreamCollection *collection = const_cast<GstStreamCollection *>(streamCollection);
+ guint size = gst_stream_collection_get_size(collection);
+
+ dbg << "Stream Collection: {";
+ for (guint index = 0; index != size; ++index) {
+ dbg << gst_stream_collection_get_stream(collection, index);
+ if (index + 1 != size)
+ dbg << ", ";
+ }
+
+ dbg << "}";
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, const GstStream *cstream)
+{
+ GstStream *stream = const_cast<GstStream *>(cstream);
+
+ dbg << "GstStream { ";
+ dbg << "Type: " << gst_stream_type_get_name(gst_stream_get_stream_type(stream));
+ dbg << ", Tags: " << gst_stream_get_tags(stream);
+ dbg << ", Caps: " << gst_stream_get_caps(stream);
+ dbg << "}";
+
+ return dbg;
+}
+
QDebug operator<<(QDebug dbg, GstState state)
{
return dbg << gst_element_state_get_name(state);
@@ -435,7 +492,9 @@ QDebug operator<<(QDebug dbg, const QCompactGstMessageAdaptor &m)
gst_message_parse_state_changed(m.msg, &oldState, &newState, &pending);
- dbg << oldState << " -> " << newState << " (pending: " << pending << ")";
+ dbg << oldState << " -> " << newState;
+ if (pending != GST_STATE_VOID_PENDING)
+ dbg << " (pending: " << pending << ")";
return dbg;
}
diff --git a/src/plugins/multimedia/gstreamer/common/qgst_debug_p.h b/src/plugins/multimedia/gstreamer/common/qgst_debug_p.h
index 31c722a90..52f734b9e 100644
--- a/src/plugins/multimedia/gstreamer/common/qgst_debug_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgst_debug_p.h
@@ -23,7 +23,7 @@ QT_BEGIN_NAMESPACE
class QGstreamerMessage;
QDebug operator<<(QDebug, const QGstCaps &);
-QDebug operator<<(QDebug, const QGstStructure &);
+QDebug operator<<(QDebug, const QGstStructureView &);
QDebug operator<<(QDebug, const QGstElement &);
QDebug operator<<(QDebug, const QGstPad &);
QDebug operator<<(QDebug, const QGString &);
@@ -31,6 +31,8 @@ QDebug operator<<(QDebug, const QGValue &);
QDebug operator<<(QDebug, const QGstreamerMessage &);
QDebug operator<<(QDebug, const QUniqueGErrorHandle &);
QDebug operator<<(QDebug, const QUniqueGStringHandle &);
+QDebug operator<<(QDebug, const QGstStreamCollectionHandle &);
+QDebug operator<<(QDebug, const QGstStreamHandle &);
QDebug operator<<(QDebug, const GstCaps *);
QDebug operator<<(QDebug, const GstVideoInfo *);
@@ -44,6 +46,8 @@ QDebug operator<<(QDebug, const GstTagList *);
QDebug operator<<(QDebug, const GstQuery *);
QDebug operator<<(QDebug, const GstEvent *);
QDebug operator<<(QDebug, const GstPadTemplate *);
+QDebug operator<<(QDebug, const GstStreamCollection *);
+QDebug operator<<(QDebug, const GstStream *);
QDebug operator<<(QDebug, GstState);
QDebug operator<<(QDebug, GstStateChange);
diff --git a/src/plugins/multimedia/gstreamer/common/qgst_handle_types_p.h b/src/plugins/multimedia/gstreamer/common/qgst_handle_types_p.h
index 5cbbfaf19..9c4f5683a 100644
--- a/src/plugins/multimedia/gstreamer/common/qgst_handle_types_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgst_handle_types_p.h
@@ -238,10 +238,12 @@ struct QGstMiniObjectHandleHelper
using QGstClockHandle = QGstImpl::QGstHandleHelper<GstClock>::UniqueHandle;
using QGstElementHandle = QGstImpl::QGstHandleHelper<GstElement>::UniqueHandle;
-using QGstElementFactoryHandle = QGstImpl::QGstHandleHelper<GstElementFactory>::UniqueHandle;
+using QGstElementFactoryHandle = QGstImpl::QGstHandleHelper<GstElementFactory>::SharedHandle;
using QGstDeviceHandle = QGstImpl::QGstHandleHelper<GstDevice>::SharedHandle;
using QGstDeviceMonitorHandle = QGstImpl::QGstHandleHelper<GstDeviceMonitor>::UniqueHandle;
using QGstBusHandle = QGstImpl::QGstHandleHelper<GstBus>::UniqueHandle;
+using QGstStreamCollectionHandle = QGstImpl::QGstHandleHelper<GstStreamCollection>::SharedHandle;
+using QGstStreamHandle = QGstImpl::QGstHandleHelper<GstStream>::SharedHandle;
using QGstTagListHandle = QGstImpl::QSharedHandle<QGstImpl::QGstTagListHandleTraits>;
using QGstSampleHandle = QGstImpl::QSharedHandle<QGstImpl::QGstSampleHandleTraits>;
@@ -255,6 +257,7 @@ using QGstBufferHandle = QGstImpl::QGstMiniObjectHandleHelper<GstBuffer>::Shared
using QGstContextHandle = QGstImpl::QGstMiniObjectHandleHelper<GstContext>::UniqueHandle;
using QGstGstDateTimeHandle = QGstImpl::QGstMiniObjectHandleHelper<GstDateTime>::SharedHandle;
using QGstPluginFeatureHandle = QGstImpl::QGstHandleHelper<GstPluginFeature>::SharedHandle;
+using QGstQueryHandle = QGstImpl::QGstMiniObjectHandleHelper<GstQuery>::SharedHandle;
#if QT_CONFIG(gstreamer_gl)
using QGstGLContextHandle = QGstImpl::QGstHandleHelper<GstGLContext>::UniqueHandle;
diff --git a/src/plugins/multimedia/gstreamer/common/qgst_p.h b/src/plugins/multimedia/gstreamer/common/qgst_p.h
index 285a4ec47..68412258e 100644
--- a/src/plugins/multimedia/gstreamer/common/qgst_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgst_p.h
@@ -23,6 +23,7 @@
#include <QtMultimedia/qvideoframe.h>
#include <QtMultimedia/private/qtmultimediaglobal_p.h>
#include <QtMultimedia/private/qmultimediautils_p.h>
+#include <QtMultimedia/private/qplatformmediaplayer_p.h>
#include <gst/gst.h>
#include <gst/video/video-info.h>
@@ -170,7 +171,7 @@ DestinationType *qGstCheckedCast(SourceType *arg)
}
class QSize;
-class QGstStructure;
+class QGstStructureView;
class QGstCaps;
class QGstPipelinePrivate;
class QCameraFormat;
@@ -211,7 +212,7 @@ public:
std::optional<QGRange<float>> getFractionRange() const;
std::optional<QGRange<int>> toIntRange() const;
- QGstStructure toStructure() const;
+ QGstStructureView toStructure() const;
QGstCaps toCaps() const;
bool isList() const;
@@ -309,18 +310,21 @@ protected:
class QGstreamerMessage;
-class QGstStructure
+class QGstStructureView
{
public:
const GstStructure *structure = nullptr;
- QGstStructure() = default;
- QGstStructure(const GstStructure *s);
- void free();
+ explicit QGstStructureView(const GstStructure *);
+ explicit QGstStructureView(const QUniqueGstStructureHandle &);
- bool isNull() const;
+ QUniqueGstStructureHandle clone() const;
+ bool isNull() const;
QByteArrayView name() const;
- QGValue operator[](const char *name) const;
+ QGValue operator[](const char *fieldname) const;
+
+ QGstCaps caps() const;
+ QGstTagListHandle tags() const;
QSize resolution() const;
QVideoFrameFormat::PixelFormat pixelFormat() const;
@@ -328,8 +332,6 @@ public:
QGstreamerMessage getMessage();
std::optional<Fraction> pixelAspectRatio() const;
QSize nativeSize() const;
-
- QGstStructure copy() const;
};
template <>
@@ -353,7 +355,7 @@ public:
enum MemoryFormat { CpuMemory, GLTexture, DMABuf };
int size() const;
- QGstStructure at(int index) const;
+ QGstStructureView at(int index) const;
GstCaps *caps() const;
MemoryFormat memoryFormat() const;
@@ -401,7 +403,7 @@ public:
void set(const char *property, const QGstCaps &c);
QGString getString(const char *property) const;
- QGstStructure getStructure(const char *property) const;
+ QGstStructureView getStructure(const char *property) const;
bool getBool(const char *property) const;
uint getUInt(const char *property) const;
int getInt(const char *property) const;
@@ -415,9 +417,9 @@ public:
void disconnect(gulong handlerId);
GType type() const;
- const char *typeName() const;
+ QLatin1StringView typeName() const;
GstObject *object() const;
- const char *name() const;
+ QLatin1StringView name() const;
};
class QGObjectHandlerConnection
@@ -478,6 +480,11 @@ public:
QGstCaps currentCaps() const;
QGstCaps queryCaps() const;
+ QGstTagListHandle tags() const;
+
+ std::optional<QPlatformMediaPlayer::TrackType>
+ inferTrackTypeFromName() const; // for decodebin3 etc
+
bool isLinked() const;
bool link(const QGstPad &sink) const;
bool unlink(const QGstPad &sink) const;
@@ -569,6 +576,9 @@ public:
static QGstElement createFromPipelineDescription(const char *);
static QGstElement createFromPipelineDescription(const QByteArray &);
+ static QGstElementFactoryHandle findFactory(const char *);
+ static QGstElementFactoryHandle findFactory(const QByteArray &name);
+
QGstPad staticPad(const char *name) const;
QGstPad src() const;
QGstPad sink() const;
@@ -636,6 +646,7 @@ public:
QGstElement getParent() const;
QGstPipeline getPipeline() const;
+ void dumpPipelineGraph(const char *filename) const;
};
template <typename... Ts>
@@ -737,6 +748,8 @@ public:
QGstBaseSink &operator=(const QGstBaseSink &) = default;
QGstBaseSink &operator=(QGstBaseSink &&) noexcept = default;
+ void setSync(bool);
+
GstBaseSink *baseSink() const;
};
@@ -772,6 +785,11 @@ public:
GstAppSink *appSink() const;
+ void setMaxBuffers(int);
+# if GST_CHECK_VERSION(1, 24, 0)
+ void setMaxBufferTime(std::chrono::nanoseconds);
+# endif
+
void setCaps(const QGstCaps &caps);
void setCallbacks(GstAppSinkCallbacks &callbacks, gpointer user_data, GDestroyNotify notify);
@@ -801,10 +819,24 @@ public:
#endif
-inline QString errorMessageCannotFindElement(std::string_view element)
+inline GstClockTime qGstClockTimeFromChrono(std::chrono::nanoseconds ns)
{
- return QStringLiteral("Could not find the %1 GStreamer element")
- .arg(QLatin1StringView(element));
+ return ns.count();
+}
+
+QString qGstErrorMessageCannotFindElement(std::string_view element);
+
+template <typename Arg, typename... Args>
+std::optional<QString> qGstErrorMessageIfElementsNotAvailable(const Arg &arg, Args... args)
+{
+ QGstElementFactoryHandle factory = QGstElement::findFactory(arg);
+ if (!factory)
+ return qGstErrorMessageCannotFindElement(arg);
+
+ if constexpr (sizeof...(args) != 0)
+ return qGstErrorMessageIfElementsNotAvailable(args...);
+ else
+ return std::nullopt;
}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/common/qgstappsource.cpp b/src/plugins/multimedia/gstreamer/common/qgstappsource.cpp
index 99af8443c..3c345de82 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstappsource.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstappsource.cpp
@@ -16,7 +16,7 @@ QMaybe<QGstAppSource *> QGstAppSource::create(QObject *parent)
{
QGstAppSrc appsrc = QGstAppSrc::create("appsrc");
if (!appsrc)
- return errorMessageCannotFindElement("appsrc");
+ return qGstErrorMessageCannotFindElement("appsrc");
return new QGstAppSource(appsrc, parent);
}
diff --git a/src/plugins/multimedia/gstreamer/common/qgstpipeline.cpp b/src/plugins/multimedia/gstreamer/common/qgstpipeline.cpp
index ae57f21d4..16b0e28a9 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstpipeline.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstpipeline.cpp
@@ -14,6 +14,13 @@
QT_BEGIN_NAMESPACE
+static constexpr GstSeekFlags rateChangeSeekFlags =
+#if GST_CHECK_VERSION(1, 18, 0)
+ GST_SEEK_FLAG_INSTANT_RATE_CHANGE;
+#else
+ GST_SEEK_FLAG_FLUSH;
+#endif
+
class QGstPipelinePrivate : public QObject
{
public:
@@ -25,7 +32,7 @@ public:
QList<QGstreamerSyncMessageFilter*> syncFilters;
QList<QGstreamerBusMessageFilter*> busFilters;
bool inStoppedState = true;
- mutable qint64 m_position = 0;
+ mutable std::chrono::nanoseconds m_position{};
double m_rate = 1.;
bool m_flushOnConfigChanges = false;
bool m_pendingFlush = false;
@@ -44,8 +51,17 @@ public:
void installMessageFilter(QGstreamerBusMessageFilter *filter);
void removeMessageFilter(QGstreamerBusMessageFilter *filter);
+ void processMessage(const QGstreamerMessage &msg)
+ {
+ for (QGstreamerBusMessageFilter *filter : std::as_const(busFilters)) {
+ if (filter->processBusMessage(msg))
+ break;
+ }
+ }
+
private:
- static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstPipelinePrivate *d)
+ static GstBusSyncReply syncGstBusFilter(GstBus *bus, GstMessage *message,
+ QGstPipelinePrivate *d)
{
if (!message)
return GST_BUS_PASS;
@@ -74,10 +90,7 @@ private:
QGstreamerMessage::NeedsRef,
};
- for (QGstreamerBusMessageFilter *filter : std::as_const(busFilters)) {
- if (filter->processBusMessage(msg))
- break;
- }
+ processMessage(msg);
}
static gboolean busCallback(GstBus *, GstMessage *message, gpointer data)
@@ -232,6 +245,16 @@ GstStateChangeReturn QGstPipeline::setState(GstState state)
return retval;
}
+void QGstPipeline::processMessages(GstMessageType types)
+{
+ QGstPipelinePrivate *d = getPrivate();
+ QGstreamerMessage message{
+ gst_bus_pop_filtered(d->m_bus, types),
+ QGstreamerMessage::HasRef,
+ };
+ d->processMessage(message);
+}
+
void QGstPipeline::dumpGraph(const char *fileName)
{
if (isNull())
@@ -298,53 +321,45 @@ void QGstPipeline::endConfig()
void QGstPipeline::flush()
{
- QGstPipelinePrivate *d = getPrivate();
- seek(position(), d->m_rate);
+ seek(position());
}
-bool QGstPipeline::seek(qint64 pos, double rate)
+void QGstPipeline::seek(std::chrono::nanoseconds pos, double rate)
{
+ using namespace std::chrono_literals;
+
QGstPipelinePrivate *d = getPrivate();
- // always adjust the rate, so it can be set before playback starts
+ // always adjust the rate, so it can be set before playback starts
// setting position needs a loaded media file that's seekable
- d->m_rate = rate;
- qint64 from = rate > 0 ? pos : 0;
- qint64 to = rate > 0 ? duration() : pos;
- bool success = gst_element_seek(element(), rate, GST_FORMAT_TIME,
- GstSeekFlags(GST_SEEK_FLAG_FLUSH),
- GST_SEEK_TYPE_SET, from,
- GST_SEEK_TYPE_SET, to);
- if (!success)
- return false;
+
+ bool success = (rate > 0)
+ ? gst_element_seek(element(), d->m_rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, pos.count(), GST_SEEK_TYPE_END, 0)
+ : gst_element_seek(element(), d->m_rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, pos.count());
+
+ if (!success) {
+ qDebug() << "seek: gst_element_seek failed" << pos;
+ return;
+ }
d->m_position = pos;
- return true;
}
-bool QGstPipeline::setPlaybackRate(double rate, bool applyToPipeline)
+void QGstPipeline::seek(std::chrono::nanoseconds pos)
+{
+ seek(pos, getPrivate()->m_rate);
+}
+
+void QGstPipeline::setPlaybackRate(double rate)
{
QGstPipelinePrivate *d = getPrivate();
if (rate == d->m_rate)
- return false;
-
- if (!applyToPipeline) {
- d->m_rate = rate;
- return true;
- }
-
- constexpr GstSeekFlags seekFlags =
-#if GST_CHECK_VERSION(1, 18, 0)
- GST_SEEK_FLAG_INSTANT_RATE_CHANGE;
-#else
- GST_SEEK_FLAG_FLUSH;
-#endif
+ return;
- bool success = gst_element_seek(element(), rate, GST_FORMAT_TIME, seekFlags, GST_SEEK_TYPE_NONE,
- GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
- if (success)
- d->m_rate = rate;
+ d->m_rate = rate;
- return success;
+ applyPlaybackRate(/*instantRateChange =*/true);
}
double QGstPipeline::playbackRate() const
@@ -353,27 +368,50 @@ double QGstPipeline::playbackRate() const
return d->m_rate;
}
-bool QGstPipeline::setPosition(qint64 pos)
+void QGstPipeline::applyPlaybackRate(bool instantRateChange)
{
QGstPipelinePrivate *d = getPrivate();
- return seek(pos, d->m_rate);
+
+ bool success = gst_element_seek(element(), d->m_rate, GST_FORMAT_UNDEFINED,
+ instantRateChange ? rateChangeSeekFlags : GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE,
+ GST_CLOCK_TIME_NONE);
+ if (!success)
+ qDebug() << "setPlaybackRate: gst_element_seek failed";
+}
+
+void QGstPipeline::setPosition(std::chrono::nanoseconds pos)
+{
+ seek(pos);
}
-qint64 QGstPipeline::position() const
+std::chrono::nanoseconds QGstPipeline::position() const
{
gint64 pos;
QGstPipelinePrivate *d = getPrivate();
if (gst_element_query_position(element(), GST_FORMAT_TIME, &pos))
- d->m_position = pos;
+ d->m_position = std::chrono::nanoseconds{ pos };
return d->m_position;
}
-qint64 QGstPipeline::duration() const
+std::chrono::milliseconds QGstPipeline::positionInMs() const
+{
+ using namespace std::chrono;
+ return round<milliseconds>(position());
+}
+
+std::chrono::nanoseconds QGstPipeline::duration() const
{
gint64 d;
if (!gst_element_query_duration(element(), GST_FORMAT_TIME, &d))
- return 0.;
- return d;
+ return {};
+ return std::chrono::nanoseconds{ d };
+}
+
+std::chrono::milliseconds QGstPipeline::durationInMs() const
+{
+ using namespace std::chrono;
+ return round<milliseconds>(duration());
}
QGstPipelinePrivate *QGstPipeline::getPrivate() const
diff --git a/src/plugins/multimedia/gstreamer/common/qgstpipeline_p.h b/src/plugins/multimedia/gstreamer/common/qgstpipeline_p.h
index 6914993de..41275587e 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstpipeline_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstpipeline_p.h
@@ -73,6 +73,8 @@ public:
GstPipeline *pipeline() const { return GST_PIPELINE_CAST(get()); }
+ void processMessages(GstMessageType = GST_MESSAGE_ANY);
+
void dumpGraph(const char *fileName);
template <typename Functor>
@@ -94,16 +96,21 @@ public:
void flush();
- bool seek(qint64 pos, double rate);
- bool setPlaybackRate(double rate, bool applyToPipeline = true);
+ void setPlaybackRate(double rate);
double playbackRate() const;
+ void applyPlaybackRate(bool instantRateChange);
- bool setPosition(qint64 pos);
- qint64 position() const;
+ void setPosition(std::chrono::nanoseconds pos);
+ std::chrono::nanoseconds position() const;
+ std::chrono::milliseconds positionInMs() const;
- qint64 duration() const;
+ std::chrono::nanoseconds duration() const;
+ std::chrono::milliseconds durationInMs() const;
private:
+ void seek(std::chrono::nanoseconds pos, double rate);
+ void seek(std::chrono::nanoseconds pos);
+
QGstPipelinePrivate *getPrivate() const;
void beginConfig();
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput.cpp b/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput.cpp
index ca56c4572..7c620da39 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput.cpp
@@ -21,24 +21,23 @@ QT_BEGIN_NAMESPACE
QMaybe<QPlatformAudioInput *> QGstreamerAudioInput::create(QAudioInput *parent)
{
- QGstElement autoaudiosrc = QGstElement::createFromFactory("autoaudiosrc", "autoaudiosrc");
- if (!autoaudiosrc)
- return errorMessageCannotFindElement("autoaudiosrc");
+ static const auto error = qGstErrorMessageIfElementsNotAvailable("autoaudiosrc", "volume");
+ if (error)
+ return *error;
- QGstElement volume = QGstElement::createFromFactory("volume", "volume");
- if (!volume)
- return errorMessageCannotFindElement("volume");
-
- return new QGstreamerAudioInput(autoaudiosrc, volume, parent);
+ return new QGstreamerAudioInput(parent);
}
-QGstreamerAudioInput::QGstreamerAudioInput(QGstElement autoaudiosrc, QGstElement volume,
- QAudioInput *parent)
+QGstreamerAudioInput::QGstreamerAudioInput(QAudioInput *parent)
: QObject(parent),
QPlatformAudioInput(parent),
gstAudioInput(QGstBin::create("audioInput")),
- audioSrc(std::move(autoaudiosrc)),
- audioVolume(std::move(volume))
+ audioSrc{
+ QGstElement::createFromFactory("autoaudiosrc", "autoaudiosrc"),
+ },
+ audioVolume{
+ QGstElement::createFromFactory("volume", "volume"),
+ }
{
gstAudioInput.add(audioSrc, audioVolume);
qLinkGstElements(audioSrc, audioVolume);
@@ -46,6 +45,56 @@ QGstreamerAudioInput::QGstreamerAudioInput(QGstElement autoaudiosrc, QGstElement
gstAudioInput.addGhostPad(audioVolume, "src");
}
+QGstElement QGstreamerAudioInput::createGstElement()
+{
+ const auto *customDeviceInfo =
+ dynamic_cast<const QGStreamerCustomAudioDeviceInfo *>(m_audioDevice.handle());
+
+ if (customDeviceInfo) {
+ qCDebug(qLcMediaAudioInput)
+ << "requesting custom audio src element: " << customDeviceInfo->id;
+
+ QGstElement element = QGstBin::createFromPipelineDescription(customDeviceInfo->id,
+ /*name=*/nullptr,
+ /*ghostUnlinkedPads=*/true);
+ if (element)
+ return element;
+
+ qCWarning(qLcMediaAudioInput)
+ << "Cannot create audio source element:" << customDeviceInfo->id;
+ }
+
+ const QByteArray &id = m_audioDevice.id();
+ if constexpr (QT_CONFIG(pulseaudio)) {
+ QGstElement newSrc = QGstElement::createFromFactory("pulsesrc", "audiosrc");
+ if (newSrc) {
+ newSrc.set("device", id.constData());
+ return newSrc;
+ } else {
+ qWarning() << "Cannot create pulsesrc";
+ }
+ } else if constexpr (QT_CONFIG(alsa)) {
+ QGstElement newSrc = QGstElement::createFromFactory("alsasrc", "audiosrc");
+ if (newSrc) {
+ newSrc.set("device", id.constData());
+ return newSrc;
+ } else {
+ qWarning() << "Cannot create alsasrc";
+ }
+ } else {
+ auto *deviceInfo = dynamic_cast<const QGStreamerAudioDeviceInfo *>(m_audioDevice.handle());
+ if (deviceInfo && deviceInfo->gstDevice) {
+ QGstElement element = QGstElement::createFromDevice(deviceInfo->gstDevice, "audiosrc");
+ if (element)
+ return element;
+ }
+ }
+ qCWarning(qLcMediaAudioInput) << "Invalid audio device";
+ qCWarning(qLcMediaAudioInput)
+ << "Failed to create a gst element for the audio device, using a default audio source";
+ return QGstElement::createFromFactory("autoaudiosrc", "audiosrc");
+}
+
QGstreamerAudioInput::~QGstreamerAudioInput()
{
gstAudioInput.setStateSync(GST_STATE_NULL);
@@ -67,36 +116,8 @@ void QGstreamerAudioInput::setAudioDevice(const QAudioDevice &device)
return;
qCDebug(qLcMediaAudioInput) << "setAudioInput" << device.description() << device.isNull();
m_audioDevice = device;
- const QByteArray &id = m_audioDevice.id();
-
- QGstElement newSrc;
- if constexpr (QT_CONFIG(pulseaudio)) {
- newSrc = QGstElement::createFromFactory("pulsesrc", "audiosrc");
- if (newSrc)
- newSrc.set("device", id.constData());
- else
- qWarning() << "Cannot create pulsesrc";
- } else if constexpr (QT_CONFIG(alsa)) {
- newSrc = QGstElement::createFromFactory("alsasrc", "audiosrc");
- if (newSrc)
- newSrc.set("device", id.constData());
- else
- qWarning() << "Cannot create alsasrc";
- } else {
- auto *gstDeviceInfo =
- dynamic_cast<const QGStreamerAudioDeviceInfo *>(m_audioDevice.handle());
- if (gstDeviceInfo && gstDeviceInfo->gstDevice) {
- newSrc = QGstElement::createFromDevice(gstDeviceInfo->gstDevice, "audiosrc");
- } else {
- qWarning() << "Invalid audio device";
- }
- }
- if (newSrc.isNull()) {
- qWarning() << "Failed to create a gst element for the audio device, using a default audio "
- "source";
- newSrc = QGstElement::createFromFactory("autoaudiosrc", "audiosrc");
- }
+ QGstElement newSrc = createGstElement();
QGstPipeline::modifyPipelineWhileNotRunning(gstAudioInput.getPipeline(), [&] {
qUnlinkGstElements(audioSrc, audioVolume);
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput_p.h b/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput_p.h
index 69500ecab..5ca0e1a49 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstreameraudioinput_p.h
@@ -44,7 +44,9 @@ public:
QGstElement gstElement() const { return gstAudioInput; }
private:
- QGstreamerAudioInput(QGstElement autoaudiosrc, QGstElement volume, QAudioInput *parent);
+ explicit QGstreamerAudioInput(QAudioInput *parent);
+
+ QGstElement createGstElement();
QAudioDevice m_audioDevice;
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput.cpp b/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput.cpp
index 6156c97be..9cea7fb62 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput.cpp
@@ -16,43 +16,90 @@ QT_BEGIN_NAMESPACE
QMaybe<QPlatformAudioOutput *> QGstreamerAudioOutput::create(QAudioOutput *parent)
{
- QGstElement audioconvert = QGstElement::createFromFactory("audioconvert", "audioConvert");
- if (!audioconvert)
- return errorMessageCannotFindElement("audioconvert");
+ static const auto error = qGstErrorMessageIfElementsNotAvailable(
+ "audioconvert", "audioresample", "volume", "autoaudiosink");
+ if (error)
+ return *error;
- QGstElement audioresample = QGstElement::createFromFactory("audioresample", "audioResample");
- if (!audioresample)
- return errorMessageCannotFindElement("audioresample");
-
- QGstElement volume = QGstElement::createFromFactory("volume", "volume");
- if (!volume)
- return errorMessageCannotFindElement("volume");
-
- QGstElement autoaudiosink = QGstElement::createFromFactory("autoaudiosink", "autoAudioSink");
- if (!autoaudiosink)
- return errorMessageCannotFindElement("autoaudiosink");
-
- return new QGstreamerAudioOutput(audioconvert, audioresample, volume, autoaudiosink, parent);
+ return new QGstreamerAudioOutput(parent);
}
-QGstreamerAudioOutput::QGstreamerAudioOutput(QGstElement audioconvert, QGstElement audioresample,
- QGstElement volume, QGstElement autoaudiosink,
- QAudioOutput *parent)
+QGstreamerAudioOutput::QGstreamerAudioOutput(QAudioOutput *parent)
: QObject(parent),
QPlatformAudioOutput(parent),
gstAudioOutput(QGstBin::create("audioOutput")),
- audioConvert(std::move(audioconvert)),
- audioResample(std::move(audioresample)),
- audioVolume(std::move(volume)),
- audioSink(std::move(autoaudiosink))
+ audioQueue{
+ QGstElement::createFromFactory("queue", "audioQueue"),
+ },
+ audioConvert{
+ QGstElement::createFromFactory("audioconvert", "audioConvert"),
+ },
+ audioResample{
+ QGstElement::createFromFactory("audioresample", "audioResample"),
+ },
+ audioVolume{
+ QGstElement::createFromFactory("volume", "volume"),
+ },
+ audioSink{
+ QGstElement::createFromFactory("autoaudiosink", "autoAudioSink"),
+ }
{
- audioQueue = QGstElement::createFromFactory("queue", "audioQueue");
gstAudioOutput.add(audioQueue, audioConvert, audioResample, audioVolume, audioSink);
qLinkGstElements(audioQueue, audioConvert, audioResample, audioVolume, audioSink);
gstAudioOutput.addGhostPad(audioQueue, "sink");
}
+QGstElement QGstreamerAudioOutput::createGstElement()
+{
+ const auto *customDeviceInfo =
+ dynamic_cast<const QGStreamerCustomAudioDeviceInfo *>(m_audioOutput.handle());
+
+ if (customDeviceInfo) {
+ qCDebug(qLcMediaAudioOutput)
+ << "requesting custom audio sink element: " << customDeviceInfo->id;
+
+ QGstElement element =
+ QGstBin::createFromPipelineDescription(customDeviceInfo->id, /*name=*/nullptr,
+ /*ghostUnlinkedPads=*/true);
+ if (element)
+ return element;
+
+ qCWarning(qLcMediaAudioOutput)
+ << "Cannot create audio sink element:" << customDeviceInfo->id;
+ }
+
+ const QByteArray &id = m_audioOutput.id();
+ if constexpr (QT_CONFIG(pulseaudio)) {
+ QGstElement newSink = QGstElement::createFromFactory("pulsesink", "audiosink");
+ if (newSink) {
+ newSink.set("device", id.constData());
+ return newSink;
+ } else {
+ qWarning() << "Cannot create pulsesink";
+ }
+ } else if constexpr (QT_CONFIG(alsa)) {
+ QGstElement newSink = QGstElement::createFromFactory("alsasink", "audiosink");
+ if (newSink) {
+ newSink.set("device", id.constData());
+ return newSink;
+ } else {
+ qWarning() << "Cannot create alsasink";
+ }
+ } else {
+ auto *deviceInfo = dynamic_cast<const QGStreamerAudioDeviceInfo *>(m_audioOutput.handle());
+ if (deviceInfo && deviceInfo->gstDevice) {
+ QGstElement element = QGstElement::createFromDevice(deviceInfo->gstDevice, "audiosink");
+ if (element)
+ return element;
+ }
+ }
+ qCWarning(qLcMediaAudioOutput) << "Invalid audio device:" << m_audioOutput.id();
+ qCWarning(qLcMediaAudioOutput)
+ << "Failed to create a gst element for the audio device, using a default audio sink";
+ return QGstElement::createFromFactory("autoaudiosink", "audiosink");
+}
+
QGstreamerAudioOutput::~QGstreamerAudioOutput()
{
gstAudioOutput.setStateSync(GST_STATE_NULL);
@@ -75,34 +122,8 @@ void QGstreamerAudioOutput::setAudioDevice(const QAudioDevice &info)
qCDebug(qLcMediaAudioOutput) << "setAudioOutput" << info.description() << info.isNull();
m_audioOutput = info;
- const QByteArray &id = m_audioOutput.id();
-
- QGstElement newSink;
- if constexpr (QT_CONFIG(pulseaudio)) {
- newSink = QGstElement::createFromFactory("pulsesink", "audiosink");
- if (newSink)
- newSink.set("device", id.constData());
- else
- qWarning() << "Cannot create pulsesink";
- } else if constexpr (QT_CONFIG(alsa)) {
- newSink = QGstElement::createFromFactory("alsasink", "audiosink");
- if (newSink)
- newSink.set("device", id.constData());
- else
- qWarning() << "Cannot create alsasink";
- } else {
- auto *deviceInfo = dynamic_cast<const QGStreamerAudioDeviceInfo *>(m_audioOutput.handle());
- if (deviceInfo && deviceInfo->gstDevice)
- newSink = QGstElement::createFromDevice(deviceInfo->gstDevice, "audiosink");
- else
- qWarning() << "Invalid audio device";
- }
- if (newSink.isNull()) {
- qWarning() << "Failed to create a gst element for the audio "
- "device using a default audio sink";
- newSink = QGstElement::createFromFactory("autoaudiosink", "audiosink");
- }
+ QGstElement newSink = createGstElement();
QGstPipeline::modifyPipelineWhileNotRunning(gstAudioOutput.getPipeline(), [&] {
qUnlinkGstElements(audioVolume, audioSink);
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput_p.h b/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput_p.h
index 4b528d9ee..dea53e5c4 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstreameraudiooutput_p.h
@@ -41,8 +41,9 @@ public:
QGstElement gstElement() const { return gstAudioOutput; }
private:
- QGstreamerAudioOutput(QGstElement audioconvert, QGstElement audioresample, QGstElement volume,
- QGstElement autoaudiosink, QAudioOutput *parent);
+ explicit QGstreamerAudioOutput(QAudioOutput *parent);
+
+ QGstElement createGstElement();
QAudioDevice m_audioOutput;
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer.cpp b/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer.cpp
index 6e3636441..687bcaba6 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer.cpp
@@ -26,6 +26,10 @@
#include <sys/stat.h>
#include <fcntl.h>
+#if QT_CONFIG(gstreamer_gl)
+# include <gst/gl/gl.h>
+#endif
+
static Q_LOGGING_CATEGORY(qLcMediaPlayer, "qt.multimedia.player")
QT_BEGIN_NAMESPACE
@@ -92,35 +96,26 @@ QMaybe<QPlatformMediaPlayer *> QGstreamerMediaPlayer::create(QMediaPlayer *paren
if (!videoOutput)
return videoOutput.error();
- QGstElement videoInputSelector =
- QGstElement::createFromFactory("input-selector", "videoInputSelector");
- if (!videoInputSelector)
- return errorMessageCannotFindElement("input-selector");
-
- QGstElement audioInputSelector =
- QGstElement::createFromFactory("input-selector", "audioInputSelector");
- if (!audioInputSelector)
- return errorMessageCannotFindElement("input-selector");
+ static const auto error =
+ qGstErrorMessageIfElementsNotAvailable("input-selector", "decodebin", "uridecodebin");
+ if (error)
+ return *error;
- QGstElement subTitleInputSelector =
- QGstElement::createFromFactory("input-selector", "subTitleInputSelector");
- if (!subTitleInputSelector)
- return errorMessageCannotFindElement("input-selector");
-
- return new QGstreamerMediaPlayer(videoOutput.value(), videoInputSelector, audioInputSelector,
- subTitleInputSelector, parent);
+ return new QGstreamerMediaPlayer(videoOutput.value(), parent);
}
QGstreamerMediaPlayer::QGstreamerMediaPlayer(QGstreamerVideoOutput *videoOutput,
- QGstElement videoInputSelector,
- QGstElement audioInputSelector,
- QGstElement subTitleInputSelector,
QMediaPlayer *parent)
: QObject(parent),
QPlatformMediaPlayer(parent),
- trackSelectors{ { { VideoStream, videoInputSelector },
- { AudioStream, audioInputSelector },
- { SubtitleStream, subTitleInputSelector } } },
+ trackSelectors{ {
+ { VideoStream,
+ QGstElement::createFromFactory("input-selector", "videoInputSelector") },
+ { AudioStream,
+ QGstElement::createFromFactory("input-selector", "audioInputSelector") },
+ { SubtitleStream,
+ QGstElement::createFromFactory("input-selector", "subTitleInputSelector") },
+ } },
playerPipeline(QGstPipeline::create("playerPipeline")),
gstVideoOutput(videoOutput)
{
@@ -132,7 +127,6 @@ QGstreamerMediaPlayer::QGstreamerMediaPlayer(QGstreamerVideoOutput *videoOutput,
for (auto &ts : trackSelectors)
playerPipeline.add(ts.selector);
- playerPipeline.setState(GST_STATE_NULL);
playerPipeline.installMessageFilter(static_cast<QGstreamerBusMessageFilter *>(this));
playerPipeline.installMessageFilter(static_cast<QGstreamerSyncMessageFilter *>(this));
@@ -143,7 +137,7 @@ QGstreamerMediaPlayer::QGstreamerMediaPlayer(QGstreamerVideoOutput *videoOutput,
gst_pipeline_use_clock(playerPipeline.pipeline(), systemClock.get());
connect(&positionUpdateTimer, &QTimer::timeout, this, [this] {
- updatePosition();
+ updatePositionFromPipeline();
});
}
@@ -152,20 +146,27 @@ QGstreamerMediaPlayer::~QGstreamerMediaPlayer()
playerPipeline.removeMessageFilter(static_cast<QGstreamerBusMessageFilter *>(this));
playerPipeline.removeMessageFilter(static_cast<QGstreamerSyncMessageFilter *>(this));
playerPipeline.setStateSync(GST_STATE_NULL);
- topology.free();
}
-qint64 QGstreamerMediaPlayer::position() const
+std::chrono::nanoseconds QGstreamerMediaPlayer::pipelinePosition() const
+{
+ if (m_url.isEmpty())
+ return {};
+
+ Q_ASSERT(playerPipeline);
+ return playerPipeline.position();
+}
+
+void QGstreamerMediaPlayer::updatePositionFromPipeline()
{
- if (playerPipeline.isNull() || m_url.isEmpty())
- return 0;
+ using namespace std::chrono;
- return playerPipeline.position()/1e6;
+ positionChanged(round<milliseconds>(pipelinePosition()));
}
qint64 QGstreamerMediaPlayer::duration() const
{
- return m_duration;
+ return m_duration.count();
}
float QGstreamerMediaPlayer::bufferProgress() const
@@ -185,19 +186,28 @@ qreal QGstreamerMediaPlayer::playbackRate() const
void QGstreamerMediaPlayer::setPlaybackRate(qreal rate)
{
- bool applyRateToPipeline = state() != QMediaPlayer::StoppedState;
- if (playerPipeline.setPlaybackRate(rate, applyRateToPipeline))
- playbackRateChanged(rate);
+ if (rate == m_rate)
+ return;
+
+ m_rate = rate;
+
+ playerPipeline.setPlaybackRate(rate);
+ playbackRateChanged(rate);
}
void QGstreamerMediaPlayer::setPosition(qint64 pos)
{
- qint64 currentPos = playerPipeline.position()/1e6;
- if (pos == currentPos)
+ std::chrono::milliseconds posInMs{ pos };
+ setPosition(posInMs);
+}
+
+void QGstreamerMediaPlayer::setPosition(std::chrono::milliseconds pos)
+{
+ if (pos == playerPipeline.position())
return;
playerPipeline.finishStateChange();
- playerPipeline.setPosition(pos*1e6);
- qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << pos << playerPipeline.position()/1e6;
+ playerPipeline.setPosition(pos);
+ qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << pos << playerPipeline.positionInMs();
if (mediaStatus() == QMediaPlayer::EndOfMedia)
mediaStatusChanged(QMediaPlayer::LoadedMedia);
positionChanged(pos);
@@ -207,12 +217,14 @@ void QGstreamerMediaPlayer::play()
{
if (state() == QMediaPlayer::PlayingState || m_url.isEmpty())
return;
- resetCurrentLoop();
+
+ if (state() != QMediaPlayer::PausedState)
+ resetCurrentLoop();
playerPipeline.setInStoppedState(false);
if (mediaStatus() == QMediaPlayer::EndOfMedia) {
- playerPipeline.setPosition(0);
- updatePosition();
+ playerPipeline.setPosition({});
+ positionChanged(0);
}
qCDebug(qLcMediaPlayer) << "play().";
@@ -222,6 +234,11 @@ void QGstreamerMediaPlayer::play()
// immediately, when they happen while paused.
playerPipeline.flush();
m_requiresSeekOnPlay = false;
+ } else {
+ // we get an assertion failure during instant playback rate changes
+ // https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3545
+ constexpr bool performInstantRateChange = false;
+ playerPipeline.applyPlaybackRate(/*instantRateChange=*/performInstantRateChange);
}
if (ret == GST_STATE_CHANGE_FAILURE)
qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the playing state.";
@@ -241,13 +258,15 @@ void QGstreamerMediaPlayer::pause()
playerPipeline.setInStoppedState(false);
playerPipeline.flush();
}
- int ret = playerPipeline.setState(GST_STATE_PAUSED);
+ int ret = playerPipeline.setStateSync(GST_STATE_PAUSED);
if (ret == GST_STATE_CHANGE_FAILURE)
qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the paused state.";
if (mediaStatus() == QMediaPlayer::EndOfMedia) {
- playerPipeline.setPosition(0);
+ playerPipeline.setPosition({});
+ positionChanged(0);
+ } else {
+ updatePositionFromPipeline();
}
- updatePosition();
emit stateChanged(QMediaPlayer::PausedState);
if (m_bufferProgress > 0 || !canTrackProgress())
@@ -260,10 +279,11 @@ void QGstreamerMediaPlayer::pause()
void QGstreamerMediaPlayer::stop()
{
+ using namespace std::chrono_literals;
if (state() == QMediaPlayer::StoppedState) {
if (position() != 0) {
- playerPipeline.setPosition(0);
- positionChanged(0);
+ playerPipeline.setPosition({});
+ positionChanged(0ms);
mediaStatusChanged(QMediaPlayer::LoadedMedia);
}
return;
@@ -271,21 +291,24 @@ void QGstreamerMediaPlayer::stop()
stopOrEOS(false);
}
-void *QGstreamerMediaPlayer::nativePipeline()
+const QGstPipeline &QGstreamerMediaPlayer::pipeline() const
{
- return playerPipeline.pipeline();
+ return playerPipeline;
}
void QGstreamerMediaPlayer::stopOrEOS(bool eos)
{
+ using namespace std::chrono_literals;
+
positionUpdateTimer.stop();
playerPipeline.setInStoppedState(true);
bool ret = playerPipeline.setStateSync(GST_STATE_PAUSED);
if (!ret)
qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the stopped state.";
- if (!eos)
- playerPipeline.setPosition(0);
- updatePosition();
+ if (!eos) {
+ playerPipeline.setPosition(0ms);
+ positionChanged(0ms);
+ }
emit stateChanged(QMediaPlayer::StoppedState);
if (eos)
mediaStatusChanged(QMediaPlayer::EndOfMedia);
@@ -294,6 +317,23 @@ void QGstreamerMediaPlayer::stopOrEOS(bool eos)
m_initialBufferProgressSent = false;
}
+void QGstreamerMediaPlayer::detectPipelineIsSeekable()
+{
+ qCDebug(qLcMediaPlayer) << "detectPipelineIsSeekable";
+ QGstQueryHandle query{
+ gst_query_new_seeking(GST_FORMAT_TIME),
+ QGstQueryHandle::HasRef,
+ };
+ gboolean canSeek = false;
+ if (gst_element_query(playerPipeline.element(), query.get())) {
+ gst_query_parse_seeking(query.get(), nullptr, &canSeek, nullptr, nullptr);
+ qCDebug(qLcMediaPlayer) << " pipeline is seekable:" << canSeek;
+ } else {
+ qCWarning(qLcMediaPlayer) << " query for seekable failed.";
+ }
+ seekableChanged(canSeek);
+}
+
bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message)
{
qCDebug(qLcMediaPlayer) << "received bus message:" << message;
@@ -320,21 +360,23 @@ bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message)
break;
}
case GST_MESSAGE_DURATION_CHANGED: {
- qint64 d = playerPipeline.duration()/1e6;
+ std::chrono::milliseconds d = playerPipeline.durationInMs();
qCDebug(qLcMediaPlayer) << " duration changed message" << d;
if (d != m_duration) {
m_duration = d;
- emit durationChanged(duration());
+ emit durationChanged(m_duration);
}
return false;
}
- case GST_MESSAGE_EOS:
+ case GST_MESSAGE_EOS: {
+ positionChanged(playerPipeline.durationInMs());
if (doLoop()) {
setPosition(0);
break;
}
stopOrEOS(true);
break;
+ }
case GST_MESSAGE_BUFFERING: {
int progress = 0;
gst_message_parse_buffering(gm, &progress);
@@ -385,11 +427,11 @@ bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message)
GST_DEBUG_BIN_TO_DOT_FILE(playerPipeline.bin(), GST_DEBUG_GRAPH_SHOW_ALL,
"playerPipeline");
- qint64 d = playerPipeline.duration() / 1e6;
+ std::chrono::milliseconds d = playerPipeline.durationInMs();
if (d != m_duration) {
m_duration = d;
qCDebug(qLcMediaPlayer) << " duration changed" << d;
- emit durationChanged(duration());
+ emit durationChanged(d);
}
parseStreamsAndMetadata();
@@ -397,17 +439,6 @@ bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message)
emit tracksChanged();
mediaStatusChanged(QMediaPlayer::LoadedMedia);
- GstQuery *query = gst_query_new_seeking(GST_FORMAT_TIME);
- gboolean canSeek = false;
- if (gst_element_query(playerPipeline.element(), query)) {
- gst_query_parse_seeking(query, nullptr, &canSeek, nullptr, nullptr);
- qCDebug(qLcMediaPlayer) << " pipeline is seekable:" << canSeek;
- } else {
- qCDebug(qLcMediaPlayer) << " query for seekable failed.";
- }
- gst_query_unref(query);
- seekableChanged(canSeek);
-
if (!playerPipeline.inStoppedState()) {
Q_ASSERT(!m_initialBufferProgressSent);
@@ -479,21 +510,27 @@ bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message)
case GST_MESSAGE_SEGMENT_START: {
qCDebug(qLcMediaPlayer) << " segment start message, updating position";
- QGstStructure structure(gst_message_get_structure(gm));
+ QGstStructureView structure(gst_message_get_structure(gm));
auto p = structure["position"].toInt64();
if (p) {
- qint64 position = (*p)/1000000;
+ std::chrono::milliseconds position{
+ (*p) / 1000000,
+ };
emit positionChanged(position);
}
break;
}
case GST_MESSAGE_ELEMENT: {
- QGstStructure structure(gst_message_get_structure(gm));
+ QGstStructureView structure(gst_message_get_structure(gm));
auto type = structure.name();
- if (type == "stream-topology") {
- topology.free();
- topology = structure.copy();
- }
+ if (type == "stream-topology")
+ topology = structure.clone();
+
+ break;
+ }
+
+ case GST_MESSAGE_ASYNC_DONE: {
+ detectPipelineIsSeekable();
break;
}
@@ -585,7 +622,7 @@ void QGstreamerMediaPlayer::decoderPadAdded(const QGstElement &src, const QGstPa
if (!prerolling)
emit tracksChanged();
- decoderOutputMap.insert(pad.name(), sinkPad);
+ decoderOutputMap.emplace(pad, sinkPad);
}
void QGstreamerMediaPlayer::decoderPadRemoved(const QGstElement &src, const QGstPad &pad)
@@ -594,9 +631,11 @@ void QGstreamerMediaPlayer::decoderPadRemoved(const QGstElement &src, const QGst
return;
qCDebug(qLcMediaPlayer) << "Removed pad" << pad.name() << "from" << src.name();
- auto track = decoderOutputMap.value(pad.name());
- if (track.isNull())
+
+ auto it = decoderOutputMap.find(pad);
+ if (it == decoderOutputMap.end())
return;
+ QGstPad track = it->second;
auto ts = std::find_if(std::begin(trackSelectors), std::end(trackSelectors),
[&](TrackSelector &ts){ return ts.selector == track.parent(); });
@@ -653,7 +692,7 @@ void QGstreamerMediaPlayer::connectOutput(TrackSelector &ts)
qCDebug(qLcMediaPlayer) << "connecting output for track type" << ts.type;
playerPipeline.add(e);
qLinkGstElements(ts.selector, e);
- e.setState(GST_STATE_PAUSED);
+ e.syncStateWithParent();
}
ts.isConnected = true;
@@ -688,6 +727,18 @@ void QGstreamerMediaPlayer::removeOutput(TrackSelector &ts)
ts.isConnected = false;
}
+void QGstreamerMediaPlayer::removeDynamicPipelineElements()
+{
+ for (QGstElement *element : { &src, &decoder }) {
+ if (element->isNull())
+ continue;
+
+ element->setStateSync(GstState::GST_STATE_NULL);
+ playerPipeline.remove(*element);
+ *element = QGstElement{};
+ }
+}
+
void QGstreamerMediaPlayer::uridecodebinElementAddedCallback(GstElement * /*uridecodebin*/,
GstElement *child,
QGstreamerMediaPlayer *)
@@ -696,9 +747,7 @@ void QGstreamerMediaPlayer::uridecodebinElementAddedCallback(GstElement * /*urid
qCDebug(qLcMediaPlayer) << "New element added to uridecodebin:" << c.name();
static const GType decodeBinType = [] {
- QGstElementFactoryHandle factory = QGstElementFactoryHandle{
- gst_element_factory_find("decodebin"),
- };
+ QGstElementFactoryHandle factory = QGstElement::findFactory("decodebin");
return gst_element_factory_get_element_type(factory.get());
}();
@@ -757,16 +806,12 @@ void QGstreamerMediaPlayer::unknownTypeCallback(GstElement *decodebin, GstPad *p
static bool isQueue(const QGstElement &element)
{
static const GType queueType = [] {
- QGstElementFactoryHandle factory = QGstElementFactoryHandle{
- gst_element_factory_find("queue"),
- };
+ QGstElementFactoryHandle factory = QGstElement::findFactory("queue");
return gst_element_factory_get_element_type(factory.get());
}();
static const GType multiQueueType = [] {
- QGstElementFactoryHandle factory = QGstElementFactoryHandle{
- gst_element_factory_find("multiqueue"),
- };
+ QGstElementFactoryHandle factory = QGstElement::findFactory("multiqueue");
return gst_element_factory_get_element_type(factory.get());
}();
@@ -793,6 +838,8 @@ void QGstreamerMediaPlayer::decodebinElementRemovedCallback(GstBin * /*decodebin
void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
{
+ using namespace std::chrono_literals;
+
qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << "setting location to" << content;
prerolling = true;
@@ -805,24 +852,19 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
m_url = content;
m_stream = stream;
- if (!src.isNull())
- playerPipeline.remove(src);
- if (!decoder.isNull())
- playerPipeline.remove(decoder);
- src = QGstElement();
+ removeDynamicPipelineElements();
disconnectDecoderHandlers();
- decoder = QGstElement();
removeAllOutputs();
seekableChanged(false);
Q_ASSERT(playerPipeline.inStoppedState());
- if (m_duration != 0) {
- m_duration = 0;
- durationChanged(0);
+ if (m_duration != 0ms) {
+ m_duration = 0ms;
+ durationChanged(0ms);
}
stateChanged(QMediaPlayer::StoppedState);
if (position() != 0)
- positionChanged(0);
+ positionChanged(0ms);
if (!m_metaData.isEmpty()) {
m_metaData.clear();
metaDataChanged();
@@ -847,7 +889,7 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
src = m_appSrc->element();
decoder = QGstElement::createFromFactory("decodebin", "decoder");
if (!decoder) {
- error(QMediaPlayer::ResourceError, errorMessageCannotFindElement("decodebin"));
+ error(QMediaPlayer::ResourceError, qGstErrorMessageCannotFindElement("decodebin"));
return;
}
decoder.set("post-stream-topology", true);
@@ -867,7 +909,7 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
// use uridecodebin
decoder = QGstElement::createFromFactory("uridecodebin", "decoder");
if (!decoder) {
- error(QMediaPlayer::ResourceError, errorMessageCannotFindElement("uridecodebin"));
+ error(QMediaPlayer::ResourceError, qGstErrorMessageCannotFindElement("uridecodebin"));
return;
}
playerPipeline.add(decoder);
@@ -905,14 +947,14 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
padRemoved = decoder.onPadRemoved<&QGstreamerMediaPlayer::decoderPadRemoved>(this);
mediaStatusChanged(QMediaPlayer::LoadingMedia);
- if (!playerPipeline.setState(GST_STATE_PAUSED)) {
+ if (!playerPipeline.setStateSync(GST_STATE_PAUSED)) {
qCWarning(qLcMediaPlayer) << "Unable to set the pipeline to the paused state.";
// Note: no further error handling: errors will be delivered via a GstMessage
return;
}
- playerPipeline.setPosition(0);
- positionChanged(0);
+ playerPipeline.setPosition(0ms);
+ positionChanged(0ms);
}
void QGstreamerMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
@@ -942,9 +984,9 @@ void QGstreamerMediaPlayer::setVideoSink(QVideoSink *sink)
gstVideoOutput->setVideoSink(sink);
}
-static QGstStructure endOfChain(const QGstStructure &s)
+static QGstStructureView endOfChain(const QGstStructureView &s)
{
- QGstStructure e = s;
+ QGstStructureView e = s;
while (1) {
auto next = e["next"].toStructure();
if (!next.isNull())
@@ -958,29 +1000,30 @@ static QGstStructure endOfChain(const QGstStructure &s)
void QGstreamerMediaPlayer::parseStreamsAndMetadata()
{
qCDebug(qLcMediaPlayer) << "============== parse topology ============";
- if (topology.isNull()) {
+
+ if (!topology) {
qCDebug(qLcMediaPlayer) << " null topology";
return;
}
- auto caps = topology["caps"].toCaps();
- auto structure = caps.at(0);
+
+ QGstStructureView topologyView{ topology };
+
+ QGstCaps caps = topologyView.caps();
+ QGstStructureView structure = caps.at(0);
auto fileFormat = QGstreamerFormatInfo::fileFormatForCaps(structure);
qCDebug(qLcMediaPlayer) << caps << fileFormat;
m_metaData.insert(QMediaMetaData::FileFormat, QVariant::fromValue(fileFormat));
m_metaData.insert(QMediaMetaData::Duration, duration());
m_metaData.insert(QMediaMetaData::Url, m_url);
- QGValue tags = topology["tags"];
- if (!tags.isNull()) {
- QGstTagListHandle tagList;
- gst_structure_get(topology.structure, "tags", GST_TYPE_TAG_LIST, &tagList, nullptr);
-
+ QGstTagListHandle tagList = QGstStructureView{ topology }.tags();
+ if (tagList) {
const auto metaData = taglistToMetaData(tagList);
for (auto k : metaData.keys())
m_metaData.insert(k, metaData.value(k));
}
- auto demux = endOfChain(topology);
- auto next = demux["next"];
+ QGstStructureView demux = endOfChain(topologyView);
+ QGValue next = demux["next"];
if (!next.isList()) {
qCDebug(qLcMediaPlayer) << " no additional streams";
emit metaDataChanged();
@@ -991,7 +1034,7 @@ void QGstreamerMediaPlayer::parseStreamsAndMetadata()
int size = next.listSize();
for (int i = 0; i < size; ++i) {
auto val = next.at(i);
- caps = val.toStructure()["caps"].toCaps();
+ caps = val.toStructure().caps();
structure = caps.at(0);
if (structure.name().startsWith("audio/")) {
auto codec = QGstreamerFormatInfo::audioCodecForCaps(structure);
@@ -1015,17 +1058,14 @@ void QGstreamerMediaPlayer::parseStreamsAndMetadata()
}
auto sinkPad = trackSelector(VideoStream).activeInputPad();
- if (!sinkPad.isNull()) {
- QGstTagListHandle tagList;
-
- g_object_get(sinkPad.object(), "tags", &tagList, nullptr);
+ if (sinkPad) {
+ QGstTagListHandle tagList = sinkPad.tags();
if (tagList)
qCDebug(qLcMediaPlayer) << " tags=" << tagList.get();
else
qCDebug(qLcMediaPlayer) << " tags=(null)";
}
-
qCDebug(qLcMediaPlayer) << "============== end parse topology ============";
emit metaDataChanged();
playerPipeline.dumpGraph("playback");
@@ -1039,12 +1079,10 @@ int QGstreamerMediaPlayer::trackCount(QPlatformMediaPlayer::TrackType type)
QMediaMetaData QGstreamerMediaPlayer::trackMetaData(QPlatformMediaPlayer::TrackType type, int index)
{
auto track = trackSelector(type).inputPad(index);
- if (track.isNull())
+ if (!track)
return {};
- QGstTagListHandle tagList;
- g_object_get(track.object(), "tags", &tagList, nullptr);
-
+ QGstTagListHandle tagList = track.tags();
return taglistToMetaData(tagList);
}
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer_p.h b/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer_p.h
index 5c33d531f..cf337f32c 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamermediaplayer_p.h
@@ -44,7 +44,6 @@ public:
static QMaybe<QPlatformMediaPlayer *> create(QMediaPlayer *parent = nullptr);
~QGstreamerMediaPlayer();
- qint64 position() const override;
qint64 duration() const override;
float bufferProgress() const override;
@@ -72,22 +71,19 @@ public:
void setActiveTrack(TrackType, int /*streamNumber*/) override;
void setPosition(qint64 pos) override;
+ void setPosition(std::chrono::milliseconds pos);
void play() override;
void pause() override;
void stop() override;
- void *nativePipeline() override;
+ const QGstPipeline &pipeline() const;
bool processBusMessage(const QGstreamerMessage& message) override;
bool processSyncMessage(const QGstreamerMessage& message) override;
- void updatePosition() { positionChanged(position()); }
-
private:
- QGstreamerMediaPlayer(QGstreamerVideoOutput *videoOutput, QGstElement videoInputSelector,
- QGstElement audioInputSelector, QGstElement subTitleInputSelector,
- QMediaPlayer *parent);
+ QGstreamerMediaPlayer(QGstreamerVideoOutput *videoOutput, QMediaPlayer *parent);
struct TrackSelector
{
@@ -128,9 +124,14 @@ private:
void parseStreamsAndMetadata();
void connectOutput(TrackSelector &ts);
void removeOutput(TrackSelector &ts);
+ void removeDynamicPipelineElements();
void removeAllOutputs();
void stopOrEOS(bool eos);
bool canTrackProgress() const { return decodeBinQueues > 0; }
+ void detectPipelineIsSeekable();
+
+ std::chrono::nanoseconds pipelinePosition() const;
+ void updatePositionFromPipeline();
std::array<TrackSelector, NTrackTypes> trackSelectors;
TrackSelector &trackSelector(TrackType type);
@@ -151,12 +152,13 @@ private:
bool m_requiresSeekOnPlay = false;
bool m_initialBufferProgressSent = false;
ResourceErrorState m_resourceErrorState = ResourceErrorState::NoError;
- qint64 m_duration = 0;
+ float m_rate = 1.f;
+ std::chrono::milliseconds m_duration{};
QTimer positionUpdateTimer;
QGstAppSource *m_appSrc = nullptr;
- QGstStructure topology;
+ QUniqueGstStructureHandle topology;
// Gst elements
QGstPipeline playerPipeline;
@@ -168,7 +170,15 @@ private:
// QGstElement streamSynchronizer;
- QHash<QByteArray, QGstPad> decoderOutputMap;
+ struct QGstPadLess
+ {
+ bool operator()(const QGstPad &lhs, const QGstPad &rhs) const
+ {
+ return lhs.pad() < rhs.pad();
+ }
+ };
+
+ std::map<QGstPad, QGstPad, QGstPadLess> decoderOutputMap;
// decoder connections
QGObjectHandlerScopedConnection padAdded;
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamermessage_p.h b/src/plugins/multimedia/gstreamer/common/qgstreamermessage_p.h
index 01fe68acb..9836bd0cb 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamermessage_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamermessage_p.h
@@ -43,7 +43,7 @@ public:
GstMessageType type() const { return GST_MESSAGE_TYPE(get()); }
QGstObject source() const { return QGstObject(GST_MESSAGE_SRC(get()), QGstObject::NeedsRef); }
- QGstStructure structure() const { return QGstStructure(gst_message_get_structure(get())); }
+ QGstStructureView structure() const { return QGstStructureView(gst_message_get_structure(get())); }
GstMessage *message() const { return get(); }
};
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput.cpp b/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput.cpp
index 6bc65693a..2f3197e92 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput.cpp
@@ -19,40 +19,39 @@ QMaybe<QGstreamerVideoOutput *> QGstreamerVideoOutput::create(QObject *parent)
QGstElement videoConvert;
QGstElement videoScale;
- QGstElementFactoryHandle factory = QGstElementFactoryHandle{
- gst_element_factory_find("videoconvertscale"),
- };
+ QGstElementFactoryHandle factory = QGstElement::findFactory("videoconvertscale");
if (factory) { // videoconvertscale is only available in gstreamer 1.20
videoConvert = QGstElement::createFromFactory(factory, "videoConvertScale");
} else {
videoConvert = QGstElement::createFromFactory("videoconvert", "videoConvert");
if (!videoConvert)
- return errorMessageCannotFindElement("videoconvert");
+ return qGstErrorMessageCannotFindElement("videoconvert");
videoScale = QGstElement::createFromFactory("videoscale", "videoScale");
if (!videoScale)
- return errorMessageCannotFindElement("videoscale");
+ return qGstErrorMessageCannotFindElement("videoscale");
}
- QGstElement videoSink = QGstElement::createFromFactory("fakesink", "fakeVideoSink");
- if (!videoSink)
- return errorMessageCannotFindElement("fakesink");
- videoSink.set("sync", true);
+ if (!QGstElement::findFactory("fakesink"))
+ return qGstErrorMessageCannotFindElement("fakesink");
- return new QGstreamerVideoOutput(videoConvert, videoScale, videoSink, parent);
+ return new QGstreamerVideoOutput(videoConvert, videoScale, parent);
}
QGstreamerVideoOutput::QGstreamerVideoOutput(QGstElement convert, QGstElement scale,
- QGstElement sink, QObject *parent)
+ QObject *parent)
: QObject(parent),
gstVideoOutput(QGstBin::create("videoOutput")),
+ videoQueue{
+ QGstElement::createFromFactory("queue", "videoQueue"),
+ },
videoConvert(std::move(convert)),
videoScale(std::move(scale)),
- videoSink(std::move(sink))
+ videoSink{
+ QGstElement::createFromFactory("fakesink", "fakeVideoSink"),
+ }
{
- videoQueue = QGstElement::createFromFactory("queue", "videoQueue");
-
videoSink.set("sync", true);
videoSink.set("async", false); // no asynchronous state changes
@@ -121,11 +120,7 @@ void QGstreamerVideoOutput::setVideoSink(QVideoSink *sink)
qCDebug(qLcMediaVideoOutput) << "sinkChanged" << gstSink.name();
- GST_DEBUG_BIN_TO_DOT_FILE(gstPipeline.bin(),
- GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL |*/ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE |
- GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES),
- videoSink.name());
-
+ gstPipeline.dumpGraph(videoSink.name().constData());
}
void QGstreamerVideoOutput::setPipeline(const QGstPipeline &pipeline)
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput_p.h b/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput_p.h
index 42acb18cc..883946dda 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamervideooutput_p.h
@@ -53,8 +53,7 @@ public:
void setRotation(QtVideo::Rotation);
private:
- QGstreamerVideoOutput(QGstElement videoConvert, QGstElement videoScale, QGstElement videoSink,
- QObject *parent);
+ QGstreamerVideoOutput(QGstElement videoConvert, QGstElement videoScale, QObject *parent);
void doLinkSubtitleStream();
void updateNativeSize();
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamervideosink.cpp b/src/plugins/multimedia/gstreamer/common/qgstreamervideosink.cpp
index 2ed2acb36..6467673d7 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamervideosink.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamervideosink.cpp
@@ -37,10 +37,13 @@ QT_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(qLcGstVideoSink, "qt.multimedia.gstvideosink");
QGstreamerVideoSink::QGstreamerVideoSink(QVideoSink *parent)
- : QPlatformVideoSink(parent)
+ : QPlatformVideoSink{
+ parent,
+ },
+ sinkBin{
+ QGstBin::create("videoSinkBin"),
+ }
{
- sinkBin = QGstBin::create("videoSinkBin");
-
// This is a hack for some iMX and NVidia platforms. These require the use of a special video
// conversion element in the pipeline before the video sink, as they unfortunately
// output some proprietary format from the decoder even though it's sometimes marked as
@@ -48,8 +51,6 @@ QGstreamerVideoSink::QGstreamerVideoSink(QVideoSink *parent)
//
// To fix this, simply insert the element into the pipeline if it's available. Otherwise
// we simply use an identity element.
- gstQueue = QGstElement::createFromFactory("queue", "videoSinkQueue");
-
QGstElementFactoryHandle factory;
// QT_MULTIMEDIA_GSTREAMER_OVERRIDE_VIDEO_CONVERSION_ELEMENT allows users to override the
@@ -59,20 +60,14 @@ QGstreamerVideoSink::QGstreamerVideoSink(QVideoSink *parent)
if (!preprocessOverride.isEmpty()) {
qCDebug(qLcGstVideoSink) << "requesting conversion element from environment: "
<< preprocessOverride;
- factory = QGstElementFactoryHandle{
- gst_element_factory_find(preprocessOverride.constData()),
- };
+ factory = QGstElement::findFactory(preprocessOverride);
}
if (!factory)
- factory = QGstElementFactoryHandle{
- gst_element_factory_find("imxvideoconvert_g2d"),
- };
+ factory = QGstElement::findFactory("imxvideoconvert_g2d");
if (!factory)
- factory = QGstElementFactoryHandle{
- gst_element_factory_find("nvvidconv"),
- };
+ factory = QGstElement::findFactory("nvvidconv");
if (factory) {
qCDebug(qLcGstVideoSink) << "instantiating conversion element: "
@@ -103,13 +98,13 @@ QGstreamerVideoSink::QGstreamerVideoSink(QVideoSink *parent)
}
if (gstPreprocess) {
- sinkBin.add(gstQueue, gstPreprocess, gstCapsFilter);
- qLinkGstElements(gstQueue, gstPreprocess, gstCapsFilter);
+ sinkBin.add(gstPreprocess, gstCapsFilter);
+ qLinkGstElements(gstPreprocess, gstCapsFilter);
+ sinkBin.addGhostPad(gstPreprocess, "sink");
} else {
- sinkBin.add(gstQueue, gstCapsFilter);
- qLinkGstElements(gstQueue, gstCapsFilter);
+ sinkBin.add(gstCapsFilter);
+ sinkBin.addGhostPad(gstCapsFilter, "sink");
}
- sinkBin.addGhostPad(gstQueue, "sink");
gstSubtitleSink =
QGstElement(GST_ELEMENT(QGstSubtitleSink::createSink(this)), QGstElement::NeedsRef);
@@ -117,6 +112,8 @@ QGstreamerVideoSink::QGstreamerVideoSink(QVideoSink *parent)
QGstreamerVideoSink::~QGstreamerVideoSink()
{
+ emit aboutToBeDestroyed();
+
unrefGstContexts();
setPipeline(QGstPipeline());
@@ -200,6 +197,8 @@ void QGstreamerVideoSink::unrefGstContexts()
void QGstreamerVideoSink::updateGstContexts()
{
+ using namespace Qt::Literals;
+
unrefGstContexts();
#if QT_CONFIG(gstreamer_gl)
@@ -212,12 +211,12 @@ void QGstreamerVideoSink::updateGstContexts()
const QString platform = QGuiApplication::platformName();
QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface();
- m_eglDisplay = pni->nativeResourceForIntegration("egldisplay");
+ m_eglDisplay = pni->nativeResourceForIntegration("egldisplay"_ba);
// qDebug() << "platform is" << platform << m_eglDisplay;
QGstGLDisplayHandle gstGlDisplay;
- const char *contextName = "eglcontext";
+ QByteArray contextName = "eglcontext"_ba;
GstGLPlatform glPlatform = GST_GL_PLATFORM_EGL;
// use the egl display if we have one
if (m_eglDisplay) {
@@ -227,12 +226,12 @@ void QGstreamerVideoSink::updateGstContexts()
m_eglImageTargetTexture2D = eglGetProcAddress("glEGLImageTargetTexture2DOES");
#endif
} else {
- auto display = pni->nativeResourceForIntegration("display");
+ auto display = pni->nativeResourceForIntegration("display"_ba);
if (display) {
#if GST_GL_HAVE_WINDOW_X11 && __has_include("X11/Xlib-xcb.h")
if (platform == QLatin1String("xcb")) {
- contextName = "glxcontext";
+ contextName = "glxcontext"_ba;
glPlatform = GST_GL_PLATFORM_GLX;
gstGlDisplay.reset(GST_GL_DISPLAY_CAST(
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamervideosink_p.h b/src/plugins/multimedia/gstreamer/common/qgstreamervideosink_p.h
index 132eab557..da00903fb 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamervideosink_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamervideosink_p.h
@@ -15,25 +15,17 @@
// We mean it.
//
-#include <private/qtmultimediaglobal_p.h>
-#include <private/qplatformvideosink_p.h>
+#include <QtMultimedia/qvideosink.h>
+#include <QtMultimedia/private/qplatformvideosink_p.h>
#include <common/qgstpipeline_p.h>
-#include <common/qgstreamervideooverlay_p.h>
-#include <QtGui/qcolor.h>
-#include <qvideosink.h>
-
-#if QT_CONFIG(gstreamer_gl)
-#include <gst/gl/gl.h>
-#endif
QT_BEGIN_NAMESPACE
-class QGstreamerVideoRenderer;
-class QVideoWindow;
class QGstreamerVideoSink : public QPlatformVideoSink
{
Q_OBJECT
+
public:
explicit QGstreamerVideoSink(QVideoSink *parent = nullptr);
~QGstreamerVideoSink();
@@ -52,6 +44,9 @@ public:
Qt::HANDLE eglDisplay() const { return m_eglDisplay; }
QFunctionPointer eglImageTargetTexture2D() const { return m_eglImageTargetTexture2D; }
+Q_SIGNALS:
+ void aboutToBeDestroyed();
+
private:
void createQtSink();
void updateSinkElement();
@@ -61,7 +56,6 @@ private:
QGstPipeline gstPipeline;
QGstBin sinkBin;
- QGstElement gstQueue;
QGstElement gstPreprocess;
QGstElement gstCapsFilter;
QGstElement gstVideoSink;
diff --git a/src/plugins/multimedia/gstreamer/common/qgstutils.cpp b/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
index 40fb4b6f7..8ec2bde3c 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
@@ -56,7 +56,7 @@ QAudioFormat QGstUtils::audioFormatForSample(GstSample *sample)
QAudioFormat QGstUtils::audioFormatForCaps(const QGstCaps &caps)
{
QAudioFormat format;
- QGstStructure s = caps.at(0);
+ QGstStructureView s = caps.at(0);
if (s.name() != "audio/x-raw")
return format;
diff --git a/src/plugins/multimedia/gstreamer/common/qgstvideobuffer.cpp b/src/plugins/multimedia/gstreamer/common/qgstvideobuffer.cpp
index 6552786bb..5d5c67ee0 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstvideobuffer.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstvideobuffer.cpp
@@ -79,12 +79,6 @@ QGstVideoBuffer::~QGstVideoBuffer()
unmap();
}
-
-QVideoFrame::MapMode QGstVideoBuffer::mapMode() const
-{
- return m_mode;
-}
-
QAbstractVideoBuffer::MapData QGstVideoBuffer::map(QVideoFrame::MapMode mode)
{
const GstMapFlags flags = GstMapFlags(((mode & QVideoFrame::ReadOnly) ? GST_MAP_READ : 0)
diff --git a/src/plugins/multimedia/gstreamer/common/qgstvideobuffer_p.h b/src/plugins/multimedia/gstreamer/common/qgstvideobuffer_p.h
index 151927d3d..148f7cb5f 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstvideobuffer_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstvideobuffer_p.h
@@ -34,8 +34,6 @@ public:
const QVideoFrameFormat &frameFormat, QGstCaps::MemoryFormat format);
~QGstVideoBuffer();
- QVideoFrame::MapMode mapMode() const override;
-
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override;
diff --git a/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp b/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp
index 4e9619b11..814915e96 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp
@@ -41,6 +41,13 @@ QT_BEGIN_NAMESPACE
QGstVideoRenderer::QGstVideoRenderer(QGstreamerVideoSink *sink)
: m_sink(sink), m_surfaceCaps(createSurfaceCaps(sink))
{
+ QObject::connect(
+ sink, &QGstreamerVideoSink::aboutToBeDestroyed, this,
+ [this] {
+ QMutexLocker locker(&m_sinkMutex);
+ m_sink = nullptr;
+ },
+ Qt::DirectConnection);
}
QGstVideoRenderer::~QGstVideoRenderer() = default;
@@ -111,94 +118,105 @@ const QGstCaps &QGstVideoRenderer::caps()
bool QGstVideoRenderer::start(const QGstCaps& caps)
{
qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::start" << caps;
- QMutexLocker locker(&m_mutex);
- m_frameMirrored = false;
- m_frameRotationAngle = QtVideo::Rotation::None;
-
- if (m_active) {
- m_flush = true;
- m_stop = true;
- }
-
- m_startCaps = caps;
-
- /*
- Waiting for start() to be invoked in the main thread may block
- if gstreamer blocks the main thread until this call is finished.
- This situation is rare and usually caused by setState(Null)
- while pipeline is being prerolled.
-
- The proper solution to this involves controlling gstreamer pipeline from
- other thread than video surface.
-
- Currently start() fails if wait() timed out.
- */
- if (!waitForAsyncEvent(&locker, &m_setupCondition, 1000) && !m_startCaps.isNull()) {
- qWarning() << "Failed to start video surface due to main thread blocked.";
- m_startCaps = {};
+ {
+ m_frameRotationAngle = QtVideo::Rotation::None;
+ auto optionalFormatAndVideoInfo = caps.formatAndVideoInfo();
+ if (optionalFormatAndVideoInfo) {
+ std::tie(m_format, m_videoInfo) = std::move(*optionalFormatAndVideoInfo);
+ } else {
+ m_format = {};
+ m_videoInfo = {};
+ }
+ m_memoryFormat = caps.memoryFormat();
}
- return m_active;
+ return true;
}
void QGstVideoRenderer::stop()
{
- QMutexLocker locker(&m_mutex);
+ qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::stop";
- if (!m_active)
+ QMetaObject::invokeMethod(this, [this] {
+ m_currentState.buffer = {};
+ m_sink->setVideoFrame(QVideoFrame{});
return;
-
- m_flush = true;
- m_stop = true;
-
- m_startCaps = {};
-
- waitForAsyncEvent(&locker, &m_setupCondition, 500);
+ });
}
void QGstVideoRenderer::unlock()
{
- QMutexLocker locker(&m_mutex);
-
- m_setupCondition.wakeAll();
- m_renderCondition.wakeAll();
-}
-
-bool QGstVideoRenderer::proposeAllocation(GstQuery *query)
-{
- Q_UNUSED(query);
- QMutexLocker locker(&m_mutex);
- return m_active;
+ qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::unlock";
}
-void QGstVideoRenderer::flush()
+bool QGstVideoRenderer::proposeAllocation(GstQuery *)
{
- QMutexLocker locker(&m_mutex);
-
- m_flush = true;
- m_renderBuffer = {};
- m_renderCondition.wakeAll();
-
- notify();
+ qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::proposeAllocation";
+ return true;
}
GstFlowReturn QGstVideoRenderer::render(GstBuffer *buffer)
{
- QMutexLocker locker(&m_mutex);
qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::render";
- m_renderReturn = GST_FLOW_OK;
- m_renderBuffer = QGstBufferHandle{
- buffer,
- QGstBufferHandle::NeedsRef,
+ GstVideoCropMeta *meta = gst_buffer_get_video_crop_meta(buffer);
+ if (meta) {
+ QRect vp(meta->x, meta->y, meta->width, meta->height);
+ if (m_format.viewport() != vp) {
+ qCDebug(qLcGstVideoRenderer)
+ << Q_FUNC_INFO << " Update viewport on Metadata: [" << meta->height << "x"
+ << meta->width << " | " << meta->x << "x" << meta->y << "]";
+ // Update viewport if data is not the same
+ m_format.setViewport(vp);
+ }
+ }
+
+ RenderBufferState state{
+ .buffer = QGstBufferHandle{ buffer, QGstBufferHandle::NeedsRef },
+ .format = m_format,
+ .memoryFormat = m_memoryFormat,
+ .mirrored = m_frameMirrored,
+ .rotationAngle = m_frameRotationAngle,
};
- waitForAsyncEvent(&locker, &m_renderCondition, 300);
+ qCDebug(qLcGstVideoRenderer) << " sending video frame";
+
+ QMetaObject::invokeMethod(this, [this, state = std::move(state)]() mutable {
+ if (state == m_currentState) {
+ // same buffer received twice
+ if (!m_sink || !m_sink->inStoppedState())
+ return;
- m_renderBuffer = {};
+ qCDebug(qLcGstVideoRenderer) << " showing empty video frame";
+ m_currentVideoFrame = {};
+ m_sink->setVideoFrame(m_currentVideoFrame);
+ m_currentState = {};
+ return;
+ }
+
+ QGstVideoBuffer *videoBuffer = new QGstVideoBuffer{
+ state.buffer, m_videoInfo, m_sink, state.format, state.memoryFormat,
+ };
+ QVideoFrame frame(videoBuffer, state.format);
+ QGstUtils::setFrameTimeStampsFromBuffer(&frame, state.buffer.get());
+ frame.setMirrored(state.mirrored);
+ frame.setRotation(state.rotationAngle);
+ m_currentVideoFrame = std::move(frame);
+ m_currentState = std::move(state);
+
+ if (!m_sink)
+ return;
+
+ if (m_sink->inStoppedState()) {
+ qCDebug(qLcGstVideoRenderer) << " showing empty video frame";
+ m_currentVideoFrame = {};
+ }
- return m_renderReturn;
+ m_sink->setVideoFrame(m_currentVideoFrame);
+ });
+
+ return GST_FLOW_OK;
}
bool QGstVideoRenderer::query(GstQuery *query)
@@ -211,6 +229,10 @@ bool QGstVideoRenderer::query(GstQuery *query)
if (strcmp(type, "gst.gl.local_context") != 0)
return false;
+ QMutexLocker locker(&m_sinkMutex);
+ if (!m_sink)
+ return false;
+
auto *gstGlContext = m_sink->gstGlLocalContext();
if (!gstGlContext)
return false;
@@ -269,7 +291,6 @@ void QGstVideoRenderer::gstEventHandleTag(GstEvent *event)
rotationAngle = (180 + atoi(value.get() + flipRotateLen)) % 360;
}
- QMutexLocker locker(&m_mutex);
m_frameMirrored = mirrored;
switch (rotationAngle) {
case 0:
@@ -294,139 +315,6 @@ void QGstVideoRenderer::gstEventHandleEOS(GstEvent *)
stop();
}
-bool QGstVideoRenderer::event(QEvent *event)
-{
- if (event->type() == QEvent::UpdateRequest) {
- QMutexLocker locker(&m_mutex);
-
- if (m_notified) {
- while (handleEvent(&locker)) {}
- m_notified = false;
- }
- return true;
- }
-
- return QObject::event(event);
-}
-
-bool QGstVideoRenderer::handleEvent(QMutexLocker<QMutex> *locker)
-{
- if (m_flush) {
- m_flush = false;
- if (m_active) {
- locker->unlock();
-
- if (m_sink && !m_flushed)
- m_sink->setVideoFrame(QVideoFrame());
- m_flushed = true;
- locker->relock();
- }
- } else if (m_stop) {
- m_stop = false;
-
- if (m_active) {
- m_active = false;
- m_flushed = true;
- }
- } else if (!m_startCaps.isNull()) {
- Q_ASSERT(!m_active);
-
- auto startCaps = m_startCaps;
- m_startCaps = {};
-
- if (m_sink) {
- locker->unlock();
-
- m_flushed = true;
- auto optionalFormatAndVideoInfo = startCaps.formatAndVideoInfo();
- if (optionalFormatAndVideoInfo) {
- std::tie(m_format, m_videoInfo) = std::move(*optionalFormatAndVideoInfo);
- } else {
- m_format = {};
- m_videoInfo = {};
- }
-
- memoryFormat = startCaps.memoryFormat();
-
- locker->relock();
- m_active = m_format.isValid();
- } else if (m_active) {
- m_active = false;
- m_flushed = true;
- }
-
- } else if (m_renderBuffer) {
- QGstBufferHandle buffer = std::move(m_renderBuffer);
- m_renderReturn = GST_FLOW_ERROR;
-
- qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::handleEvent(renderBuffer)" << m_active << m_sink;
- if (m_active && m_sink) {
-
- locker->unlock();
-
- m_flushed = false;
-
- GstVideoCropMeta *meta = gst_buffer_get_video_crop_meta(buffer.get());
- if (meta) {
- QRect vp(meta->x, meta->y, meta->width, meta->height);
- if (m_format.viewport() != vp) {
- qCDebug(qLcGstVideoRenderer) << Q_FUNC_INFO << " Update viewport on Metadata: [" << meta->height << "x" << meta->width << " | " << meta->x << "x" << meta->y << "]";
- // Update viewport if data is not the same
- m_format.setViewport(vp);
- }
- }
-
- if (m_sink->inStoppedState()) {
- qCDebug(qLcGstVideoRenderer) << " sending empty video frame";
- m_sink->setVideoFrame(QVideoFrame());
- } else {
- QGstVideoBuffer *videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo, m_sink, m_format, memoryFormat);
- QVideoFrame frame(videoBuffer, m_format);
- QGstUtils::setFrameTimeStampsFromBuffer(&frame, buffer.get());
- frame.setMirrored(m_frameMirrored);
- frame.setRotation(m_frameRotationAngle);
-
- qCDebug(qLcGstVideoRenderer) << " sending video frame";
- m_sink->setVideoFrame(frame);
- }
-
- locker->relock();
-
- m_renderReturn = GST_FLOW_OK;
- }
-
- m_renderCondition.wakeAll();
- } else {
- m_setupCondition.wakeAll();
-
- return false;
- }
- return true;
-}
-
-void QGstVideoRenderer::notify()
-{
- if (!m_notified) {
- m_notified = true;
- QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
- }
-}
-
-bool QGstVideoRenderer::waitForAsyncEvent(
- QMutexLocker<QMutex> *locker, QWaitCondition *condition, unsigned long time)
-{
- if (QThread::currentThread() == thread()) {
- while (handleEvent(locker)) {}
- m_notified = false;
-
- return true;
- }
-
- notify();
-
- return condition->wait(&m_mutex, time);
-}
-
static GstVideoSinkClass *gvrs_sink_parent_class;
static thread_local QGstreamerVideoSink *gvrs_current_sink;
@@ -438,8 +326,6 @@ QGstVideoRendererSink *QGstVideoRendererSink::createSink(QGstreamerVideoSink *si
QGstVideoRendererSink *gstSink = reinterpret_cast<QGstVideoRendererSink *>(
g_object_new(QGstVideoRendererSink::get_type(), nullptr));
- g_signal_connect(G_OBJECT(gstSink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), gstSink);
-
return gstSink;
}
@@ -535,41 +421,9 @@ void QGstVideoRendererSink::finalize(GObject *object)
G_OBJECT_CLASS(gvrs_sink_parent_class)->finalize(object);
}
-void QGstVideoRendererSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d)
-{
- Q_UNUSED(o);
- Q_UNUSED(p);
- QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(d);
-
- gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
- g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr);
-
- if (!showPrerollFrame) {
- GstState state = GST_STATE_VOID_PENDING;
- GstClockTime timeout = 10000000; // 10 ms
- gst_element_get_state(GST_ELEMENT(sink), &state, nullptr, timeout);
- // show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means
- // the QMediaPlayer was stopped from the paused state.
- // We need to flush the current frame.
- if (state == GST_STATE_PAUSED)
- sink->renderer->flush();
- }
-}
-
GstStateChangeReturn QGstVideoRendererSink::change_state(
GstElement *element, GstStateChange transition)
{
- QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(element);
-
- gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default
- g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, nullptr);
-
- // If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to
- // GST_STATE_PAUSED, it means the QMediaPlayer was stopped.
- // We need to flush the current frame.
- if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame)
- sink->renderer->flush();
-
return GST_ELEMENT_CLASS(gvrs_sink_parent_class)->change_state(element, transition);
}
diff --git a/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink_p.h b/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink_p.h
index 99d1b0ac8..d9e3db462 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink_p.h
@@ -15,7 +15,11 @@
// We mean it.
//
+#include <QtMultimedia/qvideoframeformat.h>
+#include <QtMultimedia/qvideoframe.h>
#include <QtMultimedia/private/qtmultimediaglobal_p.h>
+#include <QtCore/qmutex.h>
+
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
@@ -30,66 +34,61 @@
#include <common/qgst_p.h>
QT_BEGIN_NAMESPACE
-class QVideoSink;
class QGstVideoRenderer : public QObject
{
public:
- explicit QGstVideoRenderer(QGstreamerVideoSink *sink);
+ explicit QGstVideoRenderer(QGstreamerVideoSink *);
~QGstVideoRenderer();
const QGstCaps &caps();
- bool start(const QGstCaps& caps);
+ bool start(const QGstCaps &);
void stop();
void unlock();
- bool proposeAllocation(GstQuery *query);
-
- void flush();
-
- GstFlowReturn render(GstBuffer *buffer);
-
- bool event(QEvent *event) override;
- bool query(GstQuery *query);
- void gstEvent(GstEvent *event);
-
-private slots:
- bool handleEvent(QMutexLocker<QMutex> *locker);
+ bool proposeAllocation(GstQuery *);
+ GstFlowReturn render(GstBuffer *);
+ bool query(GstQuery *);
+ void gstEvent(GstEvent *);
private:
void notify();
- bool waitForAsyncEvent(QMutexLocker<QMutex> *locker, QWaitCondition *condition, unsigned long time);
static QGstCaps createSurfaceCaps(QGstreamerVideoSink *);
void gstEventHandleTag(GstEvent *);
void gstEventHandleEOS(GstEvent *);
- QPointer<QGstreamerVideoSink> m_sink;
-
- QMutex m_mutex;
- QWaitCondition m_setupCondition;
- QWaitCondition m_renderCondition;
-
- // --- accessed from multiple threads, need to hold mutex to access
- GstFlowReturn m_renderReturn = GST_FLOW_OK;
- bool m_active = false;
+ QMutex m_sinkMutex;
+ QGstreamerVideoSink *m_sink = nullptr; // written only from qt thread. so only readers on
+ // worker threads need to acquire the lock
+ // --- only accessed from gstreamer thread
const QGstCaps m_surfaceCaps;
-
- QGstCaps m_startCaps;
- QGstBufferHandle m_renderBuffer;
-
- bool m_notified = false;
- bool m_stop = false;
- bool m_flush = false;
+ QVideoFrameFormat m_format;
+ GstVideoInfo m_videoInfo{};
+ QGstCaps::MemoryFormat m_memoryFormat = QGstCaps::CpuMemory;
bool m_frameMirrored = false;
QtVideo::Rotation m_frameRotationAngle = QtVideo::Rotation::None;
- // --- only accessed from one thread
- QVideoFrameFormat m_format;
- GstVideoInfo m_videoInfo{};
- bool m_flushed = true;
- QGstCaps::MemoryFormat memoryFormat = QGstCaps::CpuMemory;
+ // --- only accessed from qt thread
+ QVideoFrame m_currentVideoFrame;
+
+ struct RenderBufferState
+ {
+ QGstBufferHandle buffer;
+ QVideoFrameFormat format;
+ QGstCaps::MemoryFormat memoryFormat;
+ bool mirrored;
+ QtVideo::Rotation rotationAngle;
+
+ bool operator==(const RenderBufferState &rhs) const
+ {
+ return std::tie(buffer, format, memoryFormat, mirrored, rotationAngle)
+ == std::tie(rhs.buffer, rhs.format, rhs.memoryFormat, rhs.mirrored,
+ rhs.rotationAngle);
+ }
+ };
+ RenderBufferState m_currentState;
};
class QGstVideoRendererSink
@@ -108,8 +107,6 @@ private:
static void finalize(GObject *object);
- static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d);
-
static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
static GstCaps *get_caps(GstBaseSink *sink, GstCaps *filter);
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera.cpp b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera.cpp
index 887f74b12..9ff00711e 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera.cpp
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera.cpp
@@ -5,6 +5,7 @@
#include <QtMultimedia/qcameradevice.h>
#include <QtMultimedia/qmediacapturesession.h>
+#include <QtMultimedia/private/qcameradevice_p.h>
#include <QtCore/qdebug.h>
#include <common/qgst_debug_p.h>
@@ -21,36 +22,35 @@ QT_BEGIN_NAMESPACE
QMaybe<QPlatformCamera *> QGstreamerCamera::create(QCamera *camera)
{
- QGstElement videotestsrc = QGstElement::createFromFactory("videotestsrc");
- if (!videotestsrc)
- return errorMessageCannotFindElement("videotestsrc");
+ static const auto error = qGstErrorMessageIfElementsNotAvailable(
+ "videotestsrc", "capsfilter", "videoconvert", "videoscale", "identity");
+ if (error)
+ return *error;
- QGstElement capsFilter = QGstElement::createFromFactory("capsfilter", "videoCapsFilter");
- if (!capsFilter)
- return errorMessageCannotFindElement("capsfilter");
-
- QGstElement videoconvert = QGstElement::createFromFactory("videoconvert", "videoConvert");
- if (!videoconvert)
- return errorMessageCannotFindElement("videoconvert");
-
- QGstElement videoscale = QGstElement::createFromFactory("videoscale", "videoScale");
- if (!videoscale)
- return errorMessageCannotFindElement("videoscale");
-
- return new QGstreamerCamera(videotestsrc, capsFilter, videoconvert, videoscale, camera);
+ return new QGstreamerCamera(camera);
}
-QGstreamerCamera::QGstreamerCamera(QGstElement videotestsrc, QGstElement capsFilter,
- QGstElement videoconvert, QGstElement videoscale,
- QCamera *camera)
- : QPlatformCamera(camera),
- gstCamera(std::move(videotestsrc)),
- gstCapsFilter(std::move(capsFilter)),
- gstVideoConvert(std::move(videoconvert)),
- gstVideoScale(std::move(videoscale))
+QGstreamerCamera::QGstreamerCamera(QCamera *camera)
+ : QGstreamerCameraBase(camera),
+ gstCameraBin{
+ QGstBin::create("camerabin"),
+ },
+ gstCamera{
+ QGstElement::createFromFactory("videotestsrc"),
+ },
+ gstCapsFilter{
+ QGstElement::createFromFactory("capsfilter", "videoCapsFilter"),
+ },
+ gstDecode{
+ QGstElement::createFromFactory("identity"),
+ },
+ gstVideoConvert{
+ QGstElement::createFromFactory("videoconvert", "videoConvert"),
+ },
+ gstVideoScale{
+ QGstElement::createFromFactory("videoscale", "videoScale"),
+ }
{
- gstDecode = QGstElement::createFromFactory("identity");
- gstCameraBin = QGstBin::create("camerabin");
gstCameraBin.add(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
qLinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
gstCameraBin.addGhostPad(gstVideoScale, "src");
@@ -95,17 +95,21 @@ void QGstreamerCamera::setCamera(const QCameraDevice &camera)
GstDevice *device = integration->videoDevice(camera.id());
if (!device) {
- emit error(QCamera::Error::CameraError,
- u"Failed to create GstDevice for camera: "_s
- + QString::fromUtf8(camera.id()));
+ updateError(QCamera::Error::CameraError,
+ u"Failed to create GstDevice for camera: "_s
+ + QString::fromUtf8(camera.id()));
return;
}
gstNewCamera = QGstElement::createFromDevice(device, "camerasrc");
- if (QGstStructure properties = gst_device_get_properties(device); !properties.isNull()) {
- if (properties.name() == "v4l2deviceprovider")
- m_v4l2DevicePath = QString::fromUtf8(properties["device.path"].toString());
- properties.free();
+ QUniqueGstStructureHandle properties{
+ gst_device_get_properties(device),
+ };
+
+ if (properties) {
+ QGstStructureView propertiesView{ properties };
+ if (propertiesView.name() == "v4l2deviceprovider")
+ m_v4l2DevicePath = QString::fromUtf8(propertiesView["device.path"].toString());
}
}
@@ -115,6 +119,8 @@ void QGstreamerCamera::setCamera(const QCameraDevice &camera)
f.pixelFormat() == QVideoFrameFormat::Format_Jpeg ? "jpegdec" : "identity");
QGstPipeline::modifyPipelineWhileNotRunning(gstCamera.getPipeline(), [&] {
+ gstCamera.setStateSync(GST_STATE_READY); // stop camera, as it may have active tasks
+
qUnlinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
gstCameraBin.stopAndRemoveElements(gstCamera, gstDecode);
@@ -147,7 +153,7 @@ bool QGstreamerCamera::setCameraFormat(const QCameraFormat &format)
f.pixelFormat() == QVideoFrameFormat::Format_Jpeg ? "jpegdec" : "identity");
QGstPipeline::modifyPipelineWhileNotRunning(gstCamera.getPipeline(), [&] {
- newGstDecode.syncStateWithParent();
+ gstCamera.setStateSync(GST_STATE_READY); // stop camera, as it may have active tasks
qUnlinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
gstCameraBin.stopAndRemoveElements(gstDecode);
@@ -713,8 +719,34 @@ int QGstreamerCamera::getV4L2Parameter(quint32 id) const
});
}
+QGstreamerCustomCamera::QGstreamerCustomCamera(QCamera *camera)
+ : QGstreamerCameraBase{
+ camera,
+ }
+{
+}
+
+void QGstreamerCustomCamera::setCamera(const QCameraDevice &device)
+{
+ gstCamera = QGstBin::createFromPipelineDescription(device.id(), /*name=*/nullptr,
+ /* ghostUnlinkedPads=*/true);
+}
+
+bool QGstreamerCustomCamera::isActive() const
+{
+ return m_active;
+}
+
+void QGstreamerCustomCamera::setActive(bool active)
+{
+ if (m_active == active)
+ return;
+
+ m_active = active;
+
+ emit activeChanged(active);
+}
+
#endif
QT_END_NAMESPACE
-
-#include "moc_qgstreamercamera_p.cpp"
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera_p.h b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera_p.h
index 74f12f918..3193a9090 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera_p.h
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamercamera_p.h
@@ -24,9 +24,16 @@
QT_BEGIN_NAMESPACE
-class QGstreamerCamera : public QPlatformCamera
+class QGstreamerCameraBase : public QPlatformCamera
+{
+public:
+ using QPlatformCamera::QPlatformCamera;
+
+ virtual QGstElement gstElement() const = 0;
+};
+
+class QGstreamerCamera : public QGstreamerCameraBase
{
- Q_OBJECT
public:
static QMaybe<QPlatformCamera *> create(QCamera *camera);
@@ -38,7 +45,7 @@ public:
void setCamera(const QCameraDevice &camera) override;
bool setCameraFormat(const QCameraFormat &format) override;
- QGstElement gstElement() const { return gstCameraBin; }
+ QGstElement gstElement() const override { return gstCameraBin; }
#if QT_CONFIG(gstreamer_photography)
GstPhotography *photography() const;
#endif
@@ -63,8 +70,7 @@ public:
void setColorTemperature(int temperature) override;
private:
- QGstreamerCamera(QGstElement videotestsrc, QGstElement capsFilter, QGstElement videoconvert,
- QGstElement videoscale, QCamera *camera);
+ QGstreamerCamera(QCamera *camera);
void updateCameraProperties();
@@ -118,12 +124,27 @@ private:
QGstElement gstDecode;
QGstElement gstVideoConvert;
QGstElement gstVideoScale;
- QGstPipeline gstPipeline;
bool m_active = false;
QString m_v4l2DevicePath;
};
+class QGstreamerCustomCamera : public QGstreamerCameraBase
+{
+public:
+ explicit QGstreamerCustomCamera(QCamera *);
+
+ QGstElement gstElement() const override { return gstCamera; }
+ void setCamera(const QCameraDevice &) override;
+
+ bool isActive() const override;
+ void setActive(bool) override;
+
+private:
+ QGstBin gstCamera;
+ bool m_active{};
+};
+
QT_END_NAMESPACE
#endif // QGSTREAMERCAMERACONTROL_H
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture.cpp b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture.cpp
index 2f8a1d776..1b76a7eec 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture.cpp
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture.cpp
@@ -10,6 +10,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
#include <QtCore/qstandardpaths.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qloggingcategory.h>
#include <common/qgstreamermetadata_p.h>
@@ -20,37 +21,96 @@
QT_BEGIN_NAMESPACE
-static Q_LOGGING_CATEGORY(qLcImageCaptureGst, "qt.multimedia.imageCapture")
+namespace {
+Q_LOGGING_CATEGORY(qLcImageCaptureGst, "qt.multimedia.imageCapture")
-QMaybe<QPlatformImageCapture *> QGstreamerImageCapture::create(QImageCapture *parent)
+struct ThreadPoolSingleton
{
- QGstElement videoconvert =
- QGstElement::createFromFactory("videoconvert", "imageCaptureConvert");
- if (!videoconvert)
- return errorMessageCannotFindElement("videoconvert");
+ QObject m_context;
+ QMutex m_poolMutex;
+ QThreadPool *m_instance{};
+ bool m_appUnderDestruction = false;
+
+ QThreadPool *get(const QMutexLocker<QMutex> &)
+ {
+ if (m_instance)
+ return m_instance;
+ if (m_appUnderDestruction || !qApp)
+ return nullptr;
+
+ using namespace std::chrono;
+
+ m_instance = new QThreadPool(qApp);
+ m_instance->setMaxThreadCount(1); // 1 thread;
+ static constexpr auto expiryTimeout = minutes(5);
+ m_instance->setExpiryTimeout(round<milliseconds>(expiryTimeout).count());
+
+ QObject::connect(qApp, &QCoreApplication::aboutToQuit, &m_context, [&] {
+ // we need to make sure that thread-local QRhi is destroyed before the application to
+ // prevent QTBUG-124189
+ QMutexLocker guard(&m_poolMutex);
+ delete m_instance;
+ m_instance = {};
+ m_appUnderDestruction = true;
+ });
- QGstElement jpegenc = QGstElement::createFromFactory("jpegenc", "jpegEncoder");
- if (!jpegenc)
- return errorMessageCannotFindElement("jpegenc");
+ QObject::connect(qApp, &QCoreApplication::destroyed, &m_context, [&] {
+ m_appUnderDestruction = false;
+ });
+ return m_instance;
+ }
- QGstElement jifmux = QGstElement::createFromFactory("jifmux", "jpegMuxer");
- if (!jifmux)
- return errorMessageCannotFindElement("jifmux");
+ template <typename Functor>
+ QFuture<void> run(Functor &&f)
+ {
+ QMutexLocker guard(&m_poolMutex);
+ QThreadPool *pool = get(guard);
+ if (!pool)
+ return QFuture<void>{};
- return new QGstreamerImageCapture(videoconvert, jpegenc, jifmux, parent);
+ return QtConcurrent::run(pool, std::forward<Functor>(f));
+ }
+};
+
+ThreadPoolSingleton s_threadPoolSingleton;
+
+}; // namespace
+
+QMaybe<QPlatformImageCapture *> QGstreamerImageCapture::create(QImageCapture *parent)
+{
+ static const auto error = qGstErrorMessageIfElementsNotAvailable(
+ "queue", "capsfilter", "videoconvert", "jpegenc", "jifmux", "fakesink");
+ if (error)
+ return *error;
+
+ return new QGstreamerImageCapture(parent);
}
-QGstreamerImageCapture::QGstreamerImageCapture(QGstElement videoconvert, QGstElement jpegenc,
- QGstElement jifmux, QImageCapture *parent)
+QGstreamerImageCapture::QGstreamerImageCapture(QImageCapture *parent)
: QPlatformImageCapture(parent),
QGstreamerBufferProbe(ProbeBuffers),
- videoConvert(std::move(videoconvert)),
- encoder(std::move(jpegenc)),
- muxer(std::move(jifmux))
+ bin{
+ QGstBin::create("imageCaptureBin"),
+ },
+ queue{
+ QGstElement::createFromFactory("queue", "imageCaptureQueue"),
+ },
+ filter{
+ QGstElement::createFromFactory("capsfilter", "filter"),
+ },
+ videoConvert{
+ QGstElement::createFromFactory("videoconvert", "imageCaptureConvert"),
+ },
+ encoder{
+ QGstElement::createFromFactory("jpegenc", "jpegEncoder"),
+ },
+ muxer{
+ QGstElement::createFromFactory("jifmux", "jpegMuxer"),
+ },
+ sink{
+ QGstElement::createFromFactory("fakesink", "imageCaptureSink"),
+ }
{
- bin = QGstBin::create("imageCaptureBin");
-
- queue = QGstElement::createFromFactory("queue", "imageCaptureQueue");
// configures the queue to be fast, lightweight and non blocking
queue.set("leaky", 2 /*downstream*/);
queue.set("silent", true);
@@ -58,8 +118,6 @@ QGstreamerImageCapture::QGstreamerImageCapture(QGstElement videoconvert, QGstEle
queue.set("max-size-bytes", uint(0));
queue.set("max-size-time", quint64(0));
- sink = QGstElement::createFromFactory("fakesink", "imageCaptureSink");
- filter = QGstElement::createFromFactory("capsfilter", "filter");
// imageCaptureSink do not wait for a preroll buffer when going READY -> PAUSED
// as no buffer will arrive until capture() is called
sink.set("async", false);
@@ -77,6 +135,15 @@ QGstreamerImageCapture::QGstreamerImageCapture(QGstElement videoconvert, QGstEle
QGstreamerImageCapture::~QGstreamerImageCapture()
{
bin.setStateSync(GST_STATE_NULL);
+
+ // wait for pending futures
+ auto pendingFutures = [&] {
+ QMutexLocker guard(&m_mutex);
+ return std::move(m_pendingFutures);
+ }();
+
+ for (QFuture<void> &pendingImage : pendingFutures)
+ pendingImage.waitForFinished();
}
bool QGstreamerImageCapture::isReadyForCapture() const
@@ -102,44 +169,40 @@ int QGstreamerImageCapture::doCapture(const QString &fileName)
{
qCDebug(qLcImageCaptureGst) << "do capture";
- // emit error in the next event loop,
- // so application can associate it with returned request id.
- auto invokeDeferred = [&](auto &&fn) {
- QMetaObject::invokeMethod(this, std::forward<decltype(fn)>(fn), Qt::QueuedConnection);
- };
-
- QMutexLocker guard(&m_mutex);
- if (!m_session) {
- invokeDeferred([this] {
- emit error(-1, QImageCapture::ResourceError,
- QPlatformImageCapture::msgImageCaptureNotSet());
- });
-
- qCDebug(qLcImageCaptureGst) << "error 1";
- return -1;
- }
- if (!m_session->camera()) {
- invokeDeferred([this] {
- emit error(-1, QImageCapture::ResourceError, tr("No camera available."));
- });
-
- qCDebug(qLcImageCaptureGst) << "error 2";
- return -1;
- }
- if (passImage) {
- invokeDeferred([this] {
- emit error(-1, QImageCapture::NotReadyError,
- QPlatformImageCapture::msgCameraNotReady());
- });
-
- qCDebug(qLcImageCaptureGst) << "error 3";
- return -1;
+ {
+ QMutexLocker guard(&m_mutex);
+ if (!m_session) {
+ invokeDeferred([this] {
+ emit error(-1, QImageCapture::ResourceError,
+ QPlatformImageCapture::msgImageCaptureNotSet());
+ });
+
+ qCDebug(qLcImageCaptureGst) << "error 1";
+ return -1;
+ }
+ if (!m_session->camera()) {
+ invokeDeferred([this] {
+ emit error(-1, QImageCapture::ResourceError, tr("No camera available."));
+ });
+
+ qCDebug(qLcImageCaptureGst) << "error 2";
+ return -1;
+ }
+ if (passImage) {
+ invokeDeferred([this] {
+ emit error(-1, QImageCapture::NotReadyError,
+ QPlatformImageCapture::msgCameraNotReady());
+ });
+
+ qCDebug(qLcImageCaptureGst) << "error 3";
+ return -1;
+ }
+ m_lastId++;
+
+ pendingImages.enqueue({ m_lastId, fileName, QMediaMetaData{} });
+ // let one image pass the pipeline
+ passImage = true;
}
- m_lastId++;
-
- pendingImages.enqueue({m_lastId, fileName, QMediaMetaData{}});
- // let one image pass the pipeline
- passImage = true;
emit readyForCaptureChanged(false);
return m_lastId;
@@ -161,6 +224,13 @@ void QGstreamerImageCapture::setResolution(const QSize &resolution)
filter.set("caps", caps);
}
+// HACK: gcc-10 and earlier reject [=,this] when building with c++17
+#if __cplusplus >= 202002L
+# define EQ_THIS_CAPTURE =, this
+#else
+# define EQ_THIS_CAPTURE =
+#endif
+
bool QGstreamerImageCapture::probeBuffer(GstBuffer *buffer)
{
QMutexLocker guard(&m_mutex);
@@ -176,7 +246,10 @@ bool QGstreamerImageCapture::probeBuffer(GstBuffer *buffer)
passImage = false;
- emit readyForCaptureChanged(isReadyForCapture());
+ bool ready = isReadyForCapture();
+ invokeDeferred([this, ready] {
+ emit readyForCaptureChanged(ready);
+ });
QGstCaps caps = bin.staticPad("sink").currentCaps();
auto memoryFormat = caps.memoryFormat();
@@ -187,35 +260,58 @@ bool QGstreamerImageCapture::probeBuffer(GstBuffer *buffer)
if (optionalFormatAndVideoInfo)
std::tie(fmt, previewInfo) = std::move(*optionalFormatAndVideoInfo);
- auto *sink = m_session->gstreamerVideoSink();
- auto *gstBuffer = new QGstVideoBuffer{
- std::move(bufferHandle), previewInfo, sink, fmt, memoryFormat,
- };
- QVideoFrame frame(gstBuffer, fmt);
- QImage img = frame.toImage();
- if (img.isNull()) {
- qDebug() << "received a null image";
- return true;
- }
-
- auto &imageData = pendingImages.head();
+ int futureId = futureIDAllocator += 1;
- emit imageExposed(imageData.id);
-
- qCDebug(qLcImageCaptureGst) << "Image available!";
- emit imageAvailable(imageData.id, frame);
+ // ensure QVideoFrame::toImage is executed on a worker thread that is joined before the
+ // qApplication is destroyed
+ QFuture<void> future = s_threadPoolSingleton.run([EQ_THIS_CAPTURE]() mutable {
+ QMutexLocker guard(&m_mutex);
+ auto scopeExit = qScopeGuard([&] {
+ m_pendingFutures.remove(futureId);
+ });
- emit imageCaptured(imageData.id, img);
+ if (!m_session) {
+ qDebug() << "QGstreamerImageCapture::probeBuffer: no session";
+ return;
+ }
+
+ auto *sink = m_session->gstreamerVideoSink();
+ auto *gstBuffer = new QGstVideoBuffer{
+ std::move(bufferHandle), previewInfo, sink, fmt, memoryFormat,
+ };
+ QVideoFrame frame(gstBuffer, fmt);
+
+ QImage img = frame.toImage();
+ if (img.isNull()) {
+ qDebug() << "received a null image";
+ return;
+ }
+
+ QMediaMetaData imageMetaData = metaData();
+ imageMetaData.insert(QMediaMetaData::Resolution, frame.size());
+ pendingImages.head().metaData = std::move(imageMetaData);
+ PendingImage pendingImage = pendingImages.head();
+
+ invokeDeferred([this, pendingImage = std::move(pendingImage), frame = std::move(frame),
+ img = std::move(img)]() mutable {
+ emit imageExposed(pendingImage.id);
+ qCDebug(qLcImageCaptureGst) << "Image available!";
+ emit imageAvailable(pendingImage.id, frame);
+ emit imageCaptured(pendingImage.id, img);
+ emit imageMetadataAvailable(pendingImage.id, pendingImage.metaData);
+ });
+ });
- QMediaMetaData metaData = this->metaData();
- metaData.insert(QMediaMetaData::Resolution, frame.size());
- imageData.metaData = metaData;
+ if (!future.isValid()) // during qApplication shutdown the threadpool becomes unusable
+ return true;
- emit imageMetadataAvailable(imageData.id, metaData);
+ m_pendingFutures.insert(futureId, future);
return true;
}
+#undef EQ_THIS_CAPTURE
+
void QGstreamerImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session)
{
QMutexLocker guard(&m_mutex);
@@ -292,28 +388,45 @@ void QGstreamerImageCapture::saveBufferToImage(GstBuffer *buffer)
if (pendingImages.isEmpty())
return;
- auto imageData = pendingImages.dequeue();
+ PendingImage imageData = pendingImages.dequeue();
if (imageData.filename.isEmpty())
return;
- qCDebug(qLcImageCaptureGst) << "saving image as" << imageData.filename;
+ int id = futureIDAllocator++;
+ QGstBufferHandle bufferHandle{
+ buffer,
+ QGstBufferHandle::NeedsRef,
+ };
- QFile f(imageData.filename);
- if (!f.open(QFile::WriteOnly)) {
- qCDebug(qLcImageCaptureGst) << " could not open image file for writing";
- return;
- }
+ QFuture<void> saveImageFuture = QtConcurrent::run([this, imageData, bufferHandle,
+ id]() mutable {
+ auto cleanup = qScopeGuard([&] {
+ QMutexLocker guard(&m_mutex);
+ m_pendingFutures.remove(id);
+ });
- GstMapInfo info;
- if (gst_buffer_map(buffer, &info, GST_MAP_READ)) {
- f.write(reinterpret_cast<const char *>(info.data), info.size);
- gst_buffer_unmap(buffer, &info);
- }
- f.close();
+ qCDebug(qLcImageCaptureGst) << "saving image as" << imageData.filename;
+
+ QFile f(imageData.filename);
+ if (!f.open(QFile::WriteOnly)) {
+ qCDebug(qLcImageCaptureGst) << " could not open image file for writing";
+ return;
+ }
- QMetaObject::invokeMethod(this, [this, imageData = std::move(imageData)]() mutable {
- imageSaved(imageData.id, imageData.filename);
+ GstMapInfo info;
+ GstBuffer *buffer = bufferHandle.get();
+ if (gst_buffer_map(buffer, &info, GST_MAP_READ)) {
+ f.write(reinterpret_cast<const char *>(info.data), info.size);
+ gst_buffer_unmap(buffer, &info);
+ }
+ f.close();
+
+ QMetaObject::invokeMethod(this, [this, imageData = std::move(imageData)]() mutable {
+ imageSaved(imageData.id, imageData.filename);
+ });
});
+
+ m_pendingFutures.insert(id, saveImageFuture);
}
QImageEncoderSettings QGstreamerImageCapture::imageSettings() const
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture_p.h b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture_p.h
index 4b2220d12..04a7c00b4 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture_p.h
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamerimagecapture_p.h
@@ -20,6 +20,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/qqueue.h>
+#include <QtConcurrent/QtConcurrentRun>
#include <common/qgst_p.h>
#include <common/qgstreamerbufferprobe_p.h>
@@ -29,9 +30,9 @@
QT_BEGIN_NAMESPACE
class QGstreamerImageCapture : public QPlatformImageCapture, private QGstreamerBufferProbe
-
{
Q_OBJECT
+
public:
static QMaybe<QPlatformImageCapture *> create(QImageCapture *parent);
virtual ~QGstreamerImageCapture();
@@ -56,8 +57,7 @@ public Q_SLOTS:
void onCameraChanged();
private:
- QGstreamerImageCapture(QGstElement videoconvert, QGstElement jpegenc, QGstElement jifmux,
- QImageCapture *parent);
+ QGstreamerImageCapture(QImageCapture *parent);
void setResolution(const QSize &resolution);
int doCapture(const QString &fileName);
@@ -93,6 +93,15 @@ private:
bool cameraActive = false;
QGObjectHandlerScopedConnection m_handoffConnection;
+
+ QMap<int, QFuture<void>> m_pendingFutures;
+ int futureIDAllocator = 0;
+
+ template <typename Functor>
+ void invokeDeferred(Functor &&fn)
+ {
+ QMetaObject::invokeMethod(this, std::forward<decltype(fn)>(fn), Qt::QueuedConnection);
+ };
};
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture.cpp b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture.cpp
index 720ff5603..7ecbb07d7 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture.cpp
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture.cpp
@@ -24,32 +24,25 @@ static void linkTeeToPad(QGstElement tee, QGstPad sink)
source.link(sink);
}
-static void unlinkTeeFromPad(QGstElement tee, QGstPad sink)
-{
- if (tee.isNull() || sink.isNull())
- return;
-
- auto source = sink.peer();
- source.unlink(sink);
-
- tee.releaseRequestPad(source);
-}
-
QMaybe<QPlatformMediaCaptureSession *> QGstreamerMediaCapture::create()
{
auto videoOutput = QGstreamerVideoOutput::create();
if (!videoOutput)
return videoOutput.error();
+ static const auto error = qGstErrorMessageIfElementsNotAvailable("tee", "capsfilter");
+ if (error)
+ return *error;
+
return new QGstreamerMediaCapture(videoOutput.value());
}
QGstreamerMediaCapture::QGstreamerMediaCapture(QGstreamerVideoOutput *videoOutput)
- : gstPipeline(QGstPipeline::create("mediaCapturePipeline")), gstVideoOutput(videoOutput)
+ : capturePipeline(QGstPipeline::create("mediaCapturePipeline")), gstVideoOutput(videoOutput)
{
gstVideoOutput->setParent(this);
gstVideoOutput->setIsPreview();
- gstVideoOutput->setPipeline(gstPipeline);
+ gstVideoOutput->setPipeline(capturePipeline);
// Use system clock to drive all elements in the pipeline. Otherwise,
// the clock is sourced from the elements (e.g. from an audio source).
@@ -59,14 +52,14 @@ QGstreamerMediaCapture::QGstreamerMediaCapture(QGstreamerVideoOutput *videoOutpu
QGstClockHandle systemClock{
gst_system_clock_obtain(),
};
- gst_pipeline_use_clock(gstPipeline.pipeline(), systemClock.get());
+ gst_pipeline_use_clock(capturePipeline.pipeline(), systemClock.get());
// This is the recording pipeline with only live sources, thus the pipeline
// will be always in the playing state.
- gstPipeline.setState(GST_STATE_PLAYING);
- gstPipeline.setInStoppedState(false);
+ capturePipeline.setState(GST_STATE_PLAYING);
+ capturePipeline.setInStoppedState(false);
- gstPipeline.dumpGraph("initial");
+ capturePipeline.dumpGraph("initial");
}
QGstreamerMediaCapture::~QGstreamerMediaCapture()
@@ -74,7 +67,7 @@ QGstreamerMediaCapture::~QGstreamerMediaCapture()
setMediaRecorder(nullptr);
setImageCapture(nullptr);
setCamera(nullptr);
- gstPipeline.setStateSync(GST_STATE_NULL);
+ capturePipeline.setStateSync(GST_STATE_NULL);
}
QPlatformCamera *QGstreamerMediaCapture::camera()
@@ -84,7 +77,7 @@ QPlatformCamera *QGstreamerMediaCapture::camera()
void QGstreamerMediaCapture::setCamera(QPlatformCamera *platformCamera)
{
- QGstreamerCamera *camera = static_cast<QGstreamerCamera *>(platformCamera);
+ auto *camera = static_cast<QGstreamerCameraBase *>(platformCamera);
if (gstCamera == camera)
return;
@@ -97,7 +90,7 @@ void QGstreamerMediaCapture::setCamera(QPlatformCamera *platformCamera)
gstCamera = camera;
if (gstCamera) {
- gstCameraActiveConnection = QObject::connect(camera, &QGstreamerCamera::activeChanged, this,
+ gstCameraActiveConnection = QObject::connect(camera, &QPlatformCamera::activeChanged, this,
&QGstreamerMediaCapture::setCameraActive);
if (gstCamera->isActive())
setCameraActive(true);
@@ -108,13 +101,13 @@ void QGstreamerMediaCapture::setCamera(QPlatformCamera *platformCamera)
void QGstreamerMediaCapture::setCameraActive(bool activate)
{
- gstPipeline.modifyPipelineWhileNotRunning([&] {
+ capturePipeline.modifyPipelineWhileNotRunning([&] {
if (activate) {
QGstElement cameraElement = gstCamera->gstElement();
gstVideoTee = QGstElement::createFromFactory("tee", "videotee");
gstVideoTee.set("allow-not-linked", true);
- gstPipeline.add(gstVideoOutput->gstElement(), cameraElement, gstVideoTee);
+ capturePipeline.add(gstVideoOutput->gstElement(), cameraElement, gstVideoTee);
linkTeeToPad(gstVideoTee, encoderVideoSink);
linkTeeToPad(gstVideoTee, gstVideoOutput->gstElement().staticPad("sink"));
@@ -122,21 +115,24 @@ void QGstreamerMediaCapture::setCameraActive(bool activate)
qLinkGstElements(cameraElement, gstVideoTee);
- gstPipeline.syncChildrenState();
+ capturePipeline.syncChildrenState();
} else {
- unlinkTeeFromPad(gstVideoTee, encoderVideoSink);
- unlinkTeeFromPad(gstVideoTee, imageCaptureSink);
+ if (encoderVideoCapsFilter)
+ qUnlinkGstElements(gstVideoTee, encoderVideoCapsFilter);
+ if (m_imageCapture)
+ qUnlinkGstElements(gstVideoTee, m_imageCapture->gstElement());
auto camera = gstCamera->gstElement();
- gstPipeline.stopAndRemoveElements(camera, gstVideoTee, gstVideoOutput->gstElement());
+ capturePipeline.stopAndRemoveElements(camera, gstVideoTee,
+ gstVideoOutput->gstElement());
gstVideoTee = {};
gstCamera->setCaptureSession(nullptr);
}
});
- gstPipeline.dumpGraph("camera");
+ capturePipeline.dumpGraph("camera");
}
QPlatformImageCapture *QGstreamerMediaCapture::imageCapture()
@@ -150,10 +146,10 @@ void QGstreamerMediaCapture::setImageCapture(QPlatformImageCapture *imageCapture
if (m_imageCapture == control)
return;
- gstPipeline.modifyPipelineWhileNotRunning([&] {
+ capturePipeline.modifyPipelineWhileNotRunning([&] {
if (m_imageCapture) {
- unlinkTeeFromPad(gstVideoTee, imageCaptureSink);
- gstPipeline.stopAndRemoveElements(m_imageCapture->gstElement());
+ qUnlinkGstElements(gstVideoTee, m_imageCapture->gstElement());
+ capturePipeline.stopAndRemoveElements(m_imageCapture->gstElement());
imageCaptureSink = {};
m_imageCapture->setCaptureSession(nullptr);
}
@@ -161,14 +157,14 @@ void QGstreamerMediaCapture::setImageCapture(QPlatformImageCapture *imageCapture
m_imageCapture = control;
if (m_imageCapture) {
imageCaptureSink = m_imageCapture->gstElement().staticPad("sink");
- gstPipeline.add(m_imageCapture->gstElement());
+ capturePipeline.add(m_imageCapture->gstElement());
m_imageCapture->gstElement().syncStateWithParent();
linkTeeToPad(gstVideoTee, imageCaptureSink);
m_imageCapture->setCaptureSession(this);
}
});
- gstPipeline.dumpGraph("imageCapture");
+ capturePipeline.dumpGraph("imageCapture");
emit imageCaptureChanged();
}
@@ -186,7 +182,7 @@ void QGstreamerMediaCapture::setMediaRecorder(QPlatformMediaRecorder *recorder)
m_mediaEncoder->setCaptureSession(this);
emit encoderChanged();
- gstPipeline.dumpGraph("encoder");
+ capturePipeline.dumpGraph("encoder");
}
QPlatformMediaRecorder *QGstreamerMediaCapture::mediaRecorder()
@@ -196,7 +192,7 @@ QPlatformMediaRecorder *QGstreamerMediaCapture::mediaRecorder()
void QGstreamerMediaCapture::linkEncoder(QGstPad audioSink, QGstPad videoSink)
{
- gstPipeline.modifyPipelineWhileNotRunning([&] {
+ capturePipeline.modifyPipelineWhileNotRunning([&] {
if (!gstVideoTee.isNull() && !videoSink.isNull()) {
QGstCaps caps = gstVideoTee.sink().currentCaps();
@@ -205,7 +201,7 @@ void QGstreamerMediaCapture::linkEncoder(QGstPad audioSink, QGstPad videoSink)
Q_ASSERT(encoderVideoCapsFilter);
encoderVideoCapsFilter.set("caps", caps);
- gstPipeline.add(encoderVideoCapsFilter);
+ capturePipeline.add(encoderVideoCapsFilter);
encoderVideoCapsFilter.src().link(videoSink);
linkTeeToPad(gstVideoTee, encoderVideoCapsFilter.sink());
@@ -220,7 +216,7 @@ void QGstreamerMediaCapture::linkEncoder(QGstPad audioSink, QGstPad videoSink)
Q_ASSERT(encoderAudioCapsFilter);
encoderAudioCapsFilter.set("caps", caps);
- gstPipeline.add(encoderAudioCapsFilter);
+ capturePipeline.add(encoderAudioCapsFilter);
encoderAudioCapsFilter.src().link(audioSink);
linkTeeToPad(gstAudioTee, encoderAudioCapsFilter.sink());
@@ -231,18 +227,16 @@ void QGstreamerMediaCapture::linkEncoder(QGstPad audioSink, QGstPad videoSink)
void QGstreamerMediaCapture::unlinkEncoder()
{
- gstPipeline.modifyPipelineWhileNotRunning([&] {
- if (!encoderVideoCapsFilter.isNull()) {
- encoderVideoCapsFilter.src().unlinkPeer();
- unlinkTeeFromPad(gstVideoTee, encoderVideoCapsFilter.sink());
- gstPipeline.stopAndRemoveElements(encoderVideoCapsFilter);
+ capturePipeline.modifyPipelineWhileNotRunning([&] {
+ if (encoderVideoCapsFilter) {
+ qUnlinkGstElements(gstVideoTee, encoderVideoCapsFilter);
+ capturePipeline.stopAndRemoveElements(encoderVideoCapsFilter);
encoderVideoCapsFilter = {};
}
- if (!encoderAudioCapsFilter.isNull()) {
- encoderAudioCapsFilter.src().unlinkPeer();
- unlinkTeeFromPad(gstAudioTee, encoderAudioCapsFilter.sink());
- gstPipeline.stopAndRemoveElements(encoderAudioCapsFilter);
+ if (encoderAudioCapsFilter) {
+ qUnlinkGstElements(gstAudioTee, encoderAudioCapsFilter);
+ capturePipeline.stopAndRemoveElements(encoderAudioCapsFilter);
encoderAudioCapsFilter = {};
}
@@ -251,22 +245,27 @@ void QGstreamerMediaCapture::unlinkEncoder()
});
}
+const QGstPipeline &QGstreamerMediaCapture::pipeline() const
+{
+ return capturePipeline;
+}
+
void QGstreamerMediaCapture::setAudioInput(QPlatformAudioInput *input)
{
if (gstAudioInput == input)
return;
- gstPipeline.modifyPipelineWhileNotRunning([&] {
+ capturePipeline.modifyPipelineWhileNotRunning([&] {
if (gstAudioInput) {
- unlinkTeeFromPad(gstAudioTee, encoderAudioSink);
+ if (encoderAudioCapsFilter)
+ qUnlinkGstElements(gstAudioTee, encoderAudioCapsFilter);
if (gstAudioOutput) {
- unlinkTeeFromPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
- gstPipeline.remove(gstAudioOutput->gstElement());
- gstAudioOutput->gstElement().setStateSync(GST_STATE_NULL);
+ qUnlinkGstElements(gstAudioTee, gstAudioOutput->gstElement());
+ capturePipeline.stopAndRemoveElements(gstAudioOutput->gstElement());
}
- gstPipeline.stopAndRemoveElements(gstAudioInput->gstElement(), gstAudioTee);
+ capturePipeline.stopAndRemoveElements(gstAudioInput->gstElement(), gstAudioTee);
gstAudioTee = {};
}
@@ -275,16 +274,16 @@ void QGstreamerMediaCapture::setAudioInput(QPlatformAudioInput *input)
Q_ASSERT(gstAudioTee.isNull());
gstAudioTee = QGstElement::createFromFactory("tee", "audiotee");
gstAudioTee.set("allow-not-linked", true);
- gstPipeline.add(gstAudioInput->gstElement(), gstAudioTee);
+ capturePipeline.add(gstAudioInput->gstElement(), gstAudioTee);
qLinkGstElements(gstAudioInput->gstElement(), gstAudioTee);
if (gstAudioOutput) {
- gstPipeline.add(gstAudioOutput->gstElement());
+ capturePipeline.add(gstAudioOutput->gstElement());
gstAudioOutput->gstElement().setState(GST_STATE_PLAYING);
linkTeeToPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
}
- gstPipeline.syncChildrenState();
+ capturePipeline.syncChildrenState();
linkTeeToPad(gstAudioTee, encoderAudioSink);
}
@@ -301,17 +300,17 @@ void QGstreamerMediaCapture::setAudioOutput(QPlatformAudioOutput *output)
if (gstAudioOutput == output)
return;
- gstPipeline.modifyPipelineWhileNotRunning([&] {
+ capturePipeline.modifyPipelineWhileNotRunning([&] {
if (gstAudioOutput && gstAudioInput) {
// If audio input is set, the output is in the pipeline
- unlinkTeeFromPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
- gstPipeline.stopAndRemoveElements(gstAudioOutput->gstElement());
+ qUnlinkGstElements(gstAudioTee, gstAudioOutput->gstElement());
+ capturePipeline.stopAndRemoveElements(gstAudioOutput->gstElement());
}
gstAudioOutput = static_cast<QGstreamerAudioOutput *>(output);
if (gstAudioOutput && gstAudioInput) {
- gstPipeline.add(gstAudioOutput->gstElement());
- gstPipeline.syncChildrenState();
+ capturePipeline.add(gstAudioOutput->gstElement());
+ capturePipeline.syncChildrenState();
linkTeeToPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
}
});
@@ -322,11 +321,6 @@ QGstreamerVideoSink *QGstreamerMediaCapture::gstreamerVideoSink() const
return gstVideoOutput ? gstVideoOutput->gstreamerVideoSink() : nullptr;
}
-void *QGstreamerMediaCapture::nativePipeline()
-{
- return gstPipeline.pipeline();
-}
-
QT_END_NAMESPACE
#include "moc_qgstreamermediacapture_p.cpp"
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture_p.h b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture_p.h
index 219773413..c44e31f0e 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture_p.h
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediacapture_p.h
@@ -25,7 +25,7 @@
QT_BEGIN_NAMESPACE
-class QGstreamerCamera;
+class QGstreamerCameraBase;
class QGstreamerImageCapture;
class QGstreamerMediaEncoder;
class QGstreamerAudioInput;
@@ -59,12 +59,10 @@ public:
void linkEncoder(QGstPad audioSink, QGstPad videoSink);
void unlinkEncoder();
- QGstPipeline pipeline() const { return gstPipeline; }
+ const QGstPipeline &pipeline() const;
QGstreamerVideoSink *gstreamerVideoSink() const;
- void *nativePipeline() override;
-
private:
void setCameraActive(bool activate);
@@ -72,10 +70,10 @@ private:
friend QGstreamerMediaEncoder;
// Gst elements
- QGstPipeline gstPipeline;
+ QGstPipeline capturePipeline;
QGstreamerAudioInput *gstAudioInput = nullptr;
- QGstreamerCamera *gstCamera = nullptr;
+ QGstreamerCameraBase *gstCamera = nullptr;
QMetaObject::Connection gstCameraActiveConnection;
QGstElement gstAudioTee;
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder.cpp b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder.cpp
index 4f9d3d364..4ec10ca84 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder.cpp
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder.cpp
@@ -40,10 +40,10 @@ QGstreamerMediaEncoder::QGstreamerMediaEncoder(QMediaRecorder *parent)
QGstreamerMediaEncoder::~QGstreamerMediaEncoder()
{
- if (!gstPipeline.isNull()) {
+ if (!capturePipeline.isNull()) {
finalize();
- gstPipeline.removeMessageFilter(this);
- gstPipeline.setStateSync(GST_STATE_NULL);
+ capturePipeline.removeMessageFilter(this);
+ capturePipeline.setStateSync(GST_STATE_NULL);
}
}
@@ -68,7 +68,7 @@ bool QGstreamerMediaEncoder::processBusMessage(const QGstreamerMessage &msg)
switch (msg.type()) {
case GST_MESSAGE_ELEMENT: {
- QGstStructure s = msg.structure();
+ QGstStructureView s = msg.structure();
if (s.name() == "GstBinForwarded")
return processBusMessage(s.getMessage());
@@ -310,8 +310,8 @@ void QGstreamerMediaEncoder::record(QMediaEncoderSettings &settings)
videoPauseControl.installOn(videoSink);
}
- gstPipeline.modifyPipelineWhileNotRunning([&] {
- gstPipeline.add(gstEncoder, gstFileSink);
+ capturePipeline.modifyPipelineWhileNotRunning([&] {
+ capturePipeline.add(gstEncoder, gstFileSink);
qLinkGstElements(gstEncoder, gstFileSink);
applyMetaDataToTagSetter(m_metaData, gstEncoder);
@@ -322,7 +322,7 @@ void QGstreamerMediaEncoder::record(QMediaEncoderSettings &settings)
});
signalDurationChangedTimer.start();
- gstPipeline.dumpGraph("recording");
+ capturePipeline.dumpGraph("recording");
durationChanged(0);
stateChanged(QMediaRecorder::RecordingState);
@@ -335,13 +335,13 @@ void QGstreamerMediaEncoder::pause()
return;
signalDurationChangedTimer.stop();
durationChanged(duration());
- gstPipeline.dumpGraph("before-pause");
+ capturePipeline.dumpGraph("before-pause");
stateChanged(QMediaRecorder::PausedState);
}
void QGstreamerMediaEncoder::resume()
{
- gstPipeline.dumpGraph("before-resume");
+ capturePipeline.dumpGraph("before-resume");
if (!m_session || m_finalizing || state() != QMediaRecorder::PausedState)
return;
signalDurationChangedTimer.start();
@@ -369,7 +369,7 @@ void QGstreamerMediaEncoder::finalize()
qCDebug(qLcMediaEncoderGst) << "finalize";
- gstPipeline.stopAndRemoveElements(gstEncoder, gstFileSink);
+ capturePipeline.stopAndRemoveElements(gstEncoder, gstFileSink);
gstFileSink = {};
gstEncoder = {};
m_finalizing = false;
@@ -403,17 +403,17 @@ void QGstreamerMediaEncoder::setCaptureSession(QPlatformMediaCaptureSession *ses
loop.exec();
}
- gstPipeline.removeMessageFilter(this);
- gstPipeline = {};
+ capturePipeline.removeMessageFilter(this);
+ capturePipeline = {};
}
m_session = captureSession;
if (!m_session)
return;
- gstPipeline = captureSession->gstPipeline;
- gstPipeline.set("message-forward", true);
- gstPipeline.installMessageFilter(this);
+ capturePipeline = captureSession->capturePipeline;
+ capturePipeline.set("message-forward", true);
+ capturePipeline.installMessageFilter(this);
}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder_p.h b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder_p.h
index 637fb7264..56e8c193b 100644
--- a/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder_p.h
+++ b/src/plugins/multimedia/gstreamer/mediacapture/qgstreamermediaencoder_p.h
@@ -79,7 +79,7 @@ private:
QMediaMetaData m_metaData;
QTimer signalDurationChangedTimer;
- QGstPipeline gstPipeline;
+ QGstPipeline capturePipeline;
QGstBin gstEncoder;
QGstElement gstFileSink;
diff --git a/src/plugins/multimedia/gstreamer/qgstreamerformatinfo.cpp b/src/plugins/multimedia/gstreamer/qgstreamerformatinfo.cpp
index 86d59a9a8..a91adedf1 100644
--- a/src/plugins/multimedia/gstreamer/qgstreamerformatinfo.cpp
+++ b/src/plugins/multimedia/gstreamer/qgstreamerformatinfo.cpp
@@ -8,7 +8,7 @@
QT_BEGIN_NAMESPACE
-QMediaFormat::AudioCodec QGstreamerFormatInfo::audioCodecForCaps(QGstStructure structure)
+QMediaFormat::AudioCodec QGstreamerFormatInfo::audioCodecForCaps(QGstStructureView structure)
{
const char *name = structure.name().data();
@@ -46,7 +46,7 @@ QMediaFormat::AudioCodec QGstreamerFormatInfo::audioCodecForCaps(QGstStructure s
return QMediaFormat::AudioCodec::Unspecified;
}
-QMediaFormat::VideoCodec QGstreamerFormatInfo::videoCodecForCaps(QGstStructure structure)
+QMediaFormat::VideoCodec QGstreamerFormatInfo::videoCodecForCaps(QGstStructureView structure)
{
const char *name = structure.name().data();
@@ -84,7 +84,7 @@ QMediaFormat::VideoCodec QGstreamerFormatInfo::videoCodecForCaps(QGstStructure s
return QMediaFormat::VideoCodec::Unspecified;
}
-QMediaFormat::FileFormat QGstreamerFormatInfo::fileFormatForCaps(QGstStructure structure)
+QMediaFormat::FileFormat QGstreamerFormatInfo::fileFormatForCaps(QGstStructureView structure)
{
const char *name = structure.name().data();
@@ -120,7 +120,7 @@ QMediaFormat::FileFormat QGstreamerFormatInfo::fileFormatForCaps(QGstStructure s
}
-QImageCapture::FileFormat QGstreamerFormatInfo::imageFormatForCaps(QGstStructure structure)
+QImageCapture::FileFormat QGstreamerFormatInfo::imageFormatForCaps(QGstStructureView structure)
{
const char *name = structure.name().data();
@@ -155,7 +155,7 @@ static QPair<QList<QMediaFormat::AudioCodec>, QList<QMediaFormat::VideoCodec>> g
auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
+ QGstStructureView structure = caps.at(i);
auto a = QGstreamerFormatInfo::audioCodecForCaps(structure);
if (a != QMediaFormat::AudioCodec::Unspecified && !audio.contains(a))
audio.append(a);
@@ -195,7 +195,7 @@ QList<QGstreamerFormatInfo::CodecMap> QGstreamerFormatInfo::getMuxerList(bool de
auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
+ QGstStructureView structure = caps.at(i);
auto fmt = fileFormatForCaps(structure);
if (fmt != QMediaFormat::UnspecifiedFormat)
fileFormats.append(fmt);
@@ -218,7 +218,7 @@ QList<QGstreamerFormatInfo::CodecMap> QGstreamerFormatInfo::getMuxerList(bool de
bool acceptsRawAudio = false;
for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
+ QGstStructureView structure = caps.at(i);
if (structure.name() == "audio/x-raw")
acceptsRawAudio = true;
auto audio = audioCodecForCaps(structure);
@@ -280,7 +280,7 @@ static QList<QImageCapture::FileFormat> getImageFormatList()
QGstCaps caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
+ QGstStructureView structure = caps.at(i);
auto f = QGstreamerFormatInfo::imageFormatForCaps(structure);
if (f != QImageCapture::UnspecifiedFormat) {
// qDebug() << structure.toString() << f;
diff --git a/src/plugins/multimedia/gstreamer/qgstreamerformatinfo_p.h b/src/plugins/multimedia/gstreamer/qgstreamerformatinfo_p.h
index def42b7ea..bba10edb9 100644
--- a/src/plugins/multimedia/gstreamer/qgstreamerformatinfo_p.h
+++ b/src/plugins/multimedia/gstreamer/qgstreamerformatinfo_p.h
@@ -31,10 +31,10 @@ public:
QGstCaps audioCaps(const QMediaFormat &f) const;
QGstCaps videoCaps(const QMediaFormat &f) const;
- static QMediaFormat::AudioCodec audioCodecForCaps(QGstStructure structure);
- static QMediaFormat::VideoCodec videoCodecForCaps(QGstStructure structure);
- static QMediaFormat::FileFormat fileFormatForCaps(QGstStructure structure);
- static QImageCapture::FileFormat imageFormatForCaps(QGstStructure structure);
+ static QMediaFormat::AudioCodec audioCodecForCaps(QGstStructureView structure);
+ static QMediaFormat::VideoCodec videoCodecForCaps(QGstStructureView structure);
+ static QMediaFormat::FileFormat fileFormatForCaps(QGstStructureView structure);
+ static QImageCapture::FileFormat imageFormatForCaps(QGstStructureView structure);
QList<CodecMap> getMuxerList(bool demuxer, QList<QMediaFormat::AudioCodec> audioCodecs, QList<QMediaFormat::VideoCodec> videoCodecs);
};
diff --git a/src/plugins/multimedia/gstreamer/qgstreamerintegration.cpp b/src/plugins/multimedia/gstreamer/qgstreamerintegration.cpp
index 4ee5b36e8..e79ff0f64 100644
--- a/src/plugins/multimedia/gstreamer/qgstreamerintegration.cpp
+++ b/src/plugins/multimedia/gstreamer/qgstreamerintegration.cpp
@@ -4,6 +4,7 @@
#include <qgstreamerintegration_p.h>
#include <qgstreamerformatinfo_p.h>
#include <qgstreamervideodevices_p.h>
+#include <audio/qgstreameraudiodevice_p.h>
#include <audio/qgstreameraudiodecoder_p.h>
#include <common/qgstreameraudioinput_p.h>
#include <common/qgstreameraudiooutput_p.h>
@@ -15,42 +16,126 @@
#include <mediacapture/qgstreamermediaencoder_p.h>
#include <QtCore/qloggingcategory.h>
+#include <QtMultimedia/private/qmediaplayer_p.h>
+#include <QtMultimedia/private/qmediacapturesession_p.h>
+#include <QtMultimedia/private/qcameradevice_p.h>
QT_BEGIN_NAMESPACE
+static thread_local bool inCustomCameraConstruction = false;
+
+QGStreamerPlatformSpecificInterfaceImplementation::
+ ~QGStreamerPlatformSpecificInterfaceImplementation() = default;
+
+QAudioDevice QGStreamerPlatformSpecificInterfaceImplementation::makeCustomGStreamerAudioInput(
+ const QByteArray &gstreamerPipeline)
+{
+ return qMakeCustomGStreamerAudioInput(gstreamerPipeline);
+}
+
+QAudioDevice QGStreamerPlatformSpecificInterfaceImplementation::makeCustomGStreamerAudioOutput(
+ const QByteArray &gstreamerPipeline)
+{
+ return qMakeCustomGStreamerAudioOutput(gstreamerPipeline);
+}
+
+QCamera *QGStreamerPlatformSpecificInterfaceImplementation::makeCustomGStreamerCamera(
+ const QByteArray &gstreamerPipeline, QObject *parent)
+{
+ QCameraDevicePrivate *info = new QCameraDevicePrivate;
+ info->id = gstreamerPipeline;
+ QCameraDevice device = info->create();
+
+ inCustomCameraConstruction = true;
+ auto guard = qScopeGuard([] {
+ inCustomCameraConstruction = false;
+ });
+
+ return new QCamera(device, parent);
+}
+
+GstPipeline *QGStreamerPlatformSpecificInterfaceImplementation::gstPipeline(QMediaPlayer *player)
+{
+ auto *priv = reinterpret_cast<QMediaPlayerPrivate *>(QMediaPlayerPrivate::get(player));
+ if (!priv)
+ return nullptr;
+
+ QGstreamerMediaPlayer *gstreamerPlayer = dynamic_cast<QGstreamerMediaPlayer *>(priv->control);
+ return gstreamerPlayer ? gstreamerPlayer->pipeline().pipeline() : nullptr;
+}
+
+GstPipeline *
+QGStreamerPlatformSpecificInterfaceImplementation::gstPipeline(QMediaCaptureSession *session)
+{
+ auto *priv = QMediaCaptureSessionPrivate::get(session);
+ if (!priv)
+ return nullptr;
+
+ QGstreamerMediaCapture *gstreamerCapture =
+ dynamic_cast<QGstreamerMediaCapture *>(priv->captureSession.get());
+ return gstreamerCapture ? gstreamerCapture->pipeline().pipeline() : nullptr;
+}
+
Q_LOGGING_CATEGORY(lcGstreamer, "qt.multimedia.gstreamer")
+namespace {
+
+void rankDownPlugin(GstRegistry *reg, const char *name)
+{
+ QGstPluginFeatureHandle pluginFeature{
+ gst_registry_lookup_feature(reg, name),
+ QGstPluginFeatureHandle::HasRef,
+ };
+ if (pluginFeature)
+ gst_plugin_feature_set_rank(pluginFeature.get(), GST_RANK_PRIMARY - 1);
+}
+
+// https://gstreamer.freedesktop.org/documentation/vaapi/index.html
+constexpr auto vaapiPluginNames = {
+ "vaapidecodebin", "vaapih264dec", "vaapih264enc", "vaapih265dec",
+ "vaapijpegdec", "vaapijpegenc", "vaapimpeg2dec", "vaapipostproc",
+ "vaapisink", "vaapivp8dec", "vaapivp9dec",
+};
+
+// https://gstreamer.freedesktop.org/documentation/va/index.html
+constexpr auto vaPluginNames = {
+ "vaav1dec", "vacompositor", "vadeinterlace", "vah264dec", "vah264enc", "vah265dec",
+ "vajpegdec", "vampeg2dec", "vapostproc", "vavp8dec", "vavp9dec",
+};
+
+// https://gstreamer.freedesktop.org/documentation/nvcodec/index.html
+constexpr auto nvcodecPluginNames = {
+ "cudaconvert", "cudaconvertscale", "cudadownload", "cudaipcsink", "cudaipcsrc",
+ "cudascale", "cudaupload", "nvautogpuh264enc", "nvautogpuh265enc", "nvav1dec",
+ "nvcudah264enc", "nvcudah265enc", "nvd3d11h264enc", "nvd3d11h265enc", "nvh264dec",
+ "nvh264enc", "nvh265dec", "nvh265enc", "nvjpegdec", "nvjpegenc",
+ "nvmpeg2videodec", "nvmpeg4videodec", "nvmpegvideodec", "nvvp8dec", "nvvp9dec",
+};
+
+} // namespace
+
QGstreamerIntegration::QGstreamerIntegration()
: QPlatformMediaIntegration(QLatin1String("gstreamer"))
{
gst_init(nullptr, nullptr);
qCDebug(lcGstreamer) << "Using gstreamer version: " << gst_version_string();
+ GstRegistry *reg = gst_registry_get();
+
if constexpr (!GST_CHECK_VERSION(1, 22, 0)) {
GstRegistry* reg = gst_registry_get();
- const auto pluginNames = {
- "vaapidecodebin",
- "vaapih264dec",
- "vaapih264enc",
- "vaapih265dec",
- "vaapijpegdec",
- "vaapijpegenc",
- "vaapimpeg2dec",
- "vaapipostproc",
- "vaapisink",
- "vaapivp8dec",
- "vaapivp9dec"
- };
-
- for (auto name : pluginNames) {
- QGstPluginFeatureHandle pluginFeature {
- gst_registry_lookup_feature(reg, name),
- QGstPluginFeatureHandle::HasRef,
- };
- if (pluginFeature) {
- gst_plugin_feature_set_rank(pluginFeature.get(), GST_RANK_PRIMARY - 1);
- }
- }
+ for (const char *name : vaapiPluginNames)
+ rankDownPlugin(reg, name);
+ }
+
+ if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_VA")) {
+ for (const char *name : vaPluginNames)
+ rankDownPlugin(reg, name);
+ }
+
+ if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_NVCODEC")) {
+ for (const char *name : nvcodecPluginNames)
+ rankDownPlugin(reg, name);
}
}
@@ -86,7 +171,10 @@ QMaybe<QPlatformMediaPlayer *> QGstreamerIntegration::createPlayer(QMediaPlayer
QMaybe<QPlatformCamera *> QGstreamerIntegration::createCamera(QCamera *camera)
{
- return QGstreamerCamera::create(camera);
+ if (inCustomCameraConstruction)
+ return new QGstreamerCustomCamera(camera);
+ else
+ return QGstreamerCamera::create(camera);
}
QMaybe<QPlatformMediaRecorder *> QGstreamerIntegration::createRecorder(QMediaRecorder *recorder)
@@ -120,4 +208,9 @@ GstDevice *QGstreamerIntegration::videoDevice(const QByteArray &id)
return devices ? static_cast<QGstreamerVideoDevices *>(devices)->videoDevice(id) : nullptr;
}
+QAbstractPlatformSpecificInterface *QGstreamerIntegration::platformSpecificInterface()
+{
+ return &m_platformSpecificImplementation;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/qgstreamerintegration_p.h b/src/plugins/multimedia/gstreamer/qgstreamerintegration_p.h
index 9cb84c57b..d8e8595d5 100644
--- a/src/plugins/multimedia/gstreamer/qgstreamerintegration_p.h
+++ b/src/plugins/multimedia/gstreamer/qgstreamerintegration_p.h
@@ -15,13 +15,29 @@
// We mean it.
//
-#include <private/qplatformmediaintegration_p.h>
+#include <QtMultimedia/private/qplatformmediaintegration_p.h>
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+
#include <gst/gst.h>
QT_BEGIN_NAMESPACE
class QGstreamerFormatInfo;
+class QGStreamerPlatformSpecificInterfaceImplementation : public QGStreamerPlatformSpecificInterface
+{
+public:
+ ~QGStreamerPlatformSpecificInterfaceImplementation() override;
+
+ QAudioDevice makeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline) override;
+ QAudioDevice makeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline) override;
+ QCamera *makeCustomGStreamerCamera(const QByteArray &gstreamerPipeline,
+ QObject *parent) override;
+
+ GstPipeline *gstPipeline(QMediaPlayer *) override;
+ GstPipeline *gstPipeline(QMediaCaptureSession *) override;
+};
+
class QGstreamerIntegration : public QPlatformMediaIntegration
{
public:
@@ -47,9 +63,13 @@ public:
const QGstreamerFormatInfo *gstFormatsInfo();
GstDevice *videoDevice(const QByteArray &id);
+ QAbstractPlatformSpecificInterface *platformSpecificInterface() override;
+
protected:
QPlatformMediaFormatInfo *createFormatInfo() override;
QPlatformVideoDevices *createVideoDevices() override;
+
+ QGStreamerPlatformSpecificInterfaceImplementation m_platformSpecificImplementation;
};
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/qgstreamervideodevices.cpp b/src/plugins/multimedia/gstreamer/qgstreamervideodevices.cpp
index cceaca621..78ac16eb4 100644
--- a/src/plugins/multimedia/gstreamer/qgstreamervideodevices.cpp
+++ b/src/plugins/multimedia/gstreamer/qgstreamervideodevices.cpp
@@ -76,11 +76,13 @@ QList<QCameraDevice> QGstreamerVideoDevices::videoDevices() const
info->description = desc.toQString();
info->id = device.id;
- if (QGstStructure properties = gst_device_get_properties(device.gstDevice.get());
- !properties.isNull()) {
- auto def = properties["is-default"].toBool();
+ QUniqueGstStructureHandle properties{
+ gst_device_get_properties(device.gstDevice.get()),
+ };
+ if (properties) {
+ QGstStructureView view{ properties };
+ auto def = view["is-default"].toBool();
info->isDefault = def && *def;
- properties.free();
}
if (info->isDefault)
diff --git a/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer.cpp b/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer.cpp
index 8ad0894f7..0a061eacb 100644
--- a/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer.cpp
+++ b/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer.cpp
@@ -277,11 +277,6 @@ QQnxCameraFrameBuffer::QQnxCameraFrameBuffer(const camera_buffer_t *buffer, QRhi
m_frameSize = ::frameSize(buffer);
}
-QVideoFrame::MapMode QQnxCameraFrameBuffer::mapMode() const
-{
- return QVideoFrame::ReadOnly;
-}
-
QAbstractVideoBuffer::MapData QQnxCameraFrameBuffer::map(QVideoFrame::MapMode)
{
return m_mapData;
diff --git a/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer_p.h b/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer_p.h
index 9fed113a6..222fd34ee 100644
--- a/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer_p.h
+++ b/src/plugins/multimedia/qnx/camera/qqnxcameraframebuffer_p.h
@@ -34,7 +34,6 @@ public:
QQnxCameraFrameBuffer(const QQnxCameraFrameBuffer&) = delete;
QQnxCameraFrameBuffer& operator=(const QQnxCameraFrameBuffer&) = delete;
- QVideoFrame::MapMode mapMode() const override;
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override;
diff --git a/src/plugins/multimedia/qnx/mediaplayer/qqnxmediaplayer.cpp b/src/plugins/multimedia/qnx/mediaplayer/qqnxmediaplayer.cpp
index 1c28c3b14..c8a4587c6 100644
--- a/src/plugins/multimedia/qnx/mediaplayer/qqnxmediaplayer.cpp
+++ b/src/plugins/multimedia/qnx/mediaplayer/qqnxmediaplayer.cpp
@@ -72,11 +72,6 @@ public:
m_handle = 0;
}
- QVideoFrame::MapMode mapMode() const override
- {
- return QVideoFrame::ReadWrite;
- }
-
void unmap() override {}
MapData map(QVideoFrame::MapMode /*mode*/) override
@@ -108,13 +103,11 @@ public:
m_windowGrabber = windowGrabber;
}
- QVideoFrame::MapMode mapMode() const override
+ MapData map(QVideoFrame::MapMode mode) override
{
- return QVideoFrame::ReadOnly;
- }
+ if (mode != QVideoFrame::ReadOnly)
+ return {};
- MapData map(QVideoFrame::MapMode /*mode*/) override
- {
if (buffer.data) {
qWarning("QnxRasterBuffer: need to unmap before mapping");
return {};
diff --git a/src/plugins/multimedia/wasm/mediacapture/qwasmcamera.cpp b/src/plugins/multimedia/wasm/mediacapture/qwasmcamera.cpp
index 9bd63b081..33d0789de 100644
--- a/src/plugins/multimedia/wasm/mediacapture/qwasmcamera.cpp
+++ b/src/plugins/multimedia/wasm/mediacapture/qwasmcamera.cpp
@@ -64,7 +64,7 @@ void QWasmCamera::setActive(bool active)
{
if (!m_CaptureSession) {
- emit error(QCamera::CameraError, QStringLiteral("video surface error"));
+ updateError(QCamera::CameraError, QStringLiteral("video surface error"));
m_shouldBeActive = true;
return;
}
@@ -120,7 +120,7 @@ void QWasmCamera::setCamera(const QCameraDevice &camera)
createCamera(m_cameraDev);
emit cameraIsReady();
} else {
- emit error(QCamera::CameraError, QStringLiteral("Failed to find a camera"));
+ updateError(QCamera::CameraError, QStringLiteral("Failed to find a camera"));
}
}
diff --git a/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp b/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp
index cc14cd419..cec6ea9ea 100644
--- a/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp
+++ b/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp
@@ -44,8 +44,6 @@ public:
m_memSurface->UnlockRect();
}
- QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
-
MapData map(QVideoFrame::MapMode mode) override
{
if (!m_sample || m_mapMode != QVideoFrame::NotMapped || mode != QVideoFrame::ReadOnly)
diff --git a/tests/auto/integration/CMakeLists.txt b/tests/auto/integration/CMakeLists.txt
index cbacf0c1a..47e53b6d4 100644
--- a/tests/auto/integration/CMakeLists.txt
+++ b/tests/auto/integration/CMakeLists.txt
@@ -9,6 +9,7 @@ add_subdirectory(qaudiodevice)
add_subdirectory(qaudiosource)
add_subdirectory(qaudiosink)
add_subdirectory(qmediaplayerbackend)
+add_subdirectory(qmediaplayerformatsupport)
add_subdirectory(qsoundeffect)
add_subdirectory(qvideoframebackend)
add_subdirectory(backends)
diff --git a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
index 5fb3a81a6..53a1445cd 100644
--- a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
+++ b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
@@ -14,6 +14,18 @@ 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;
+
+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
/*
@@ -152,7 +164,7 @@ void tst_QAudioDecoderBackend::directBruteForceReading()
checkNoMoreChanges(decoder);
- QCOMPARE(sampleCount, 44094);
+ QCOMPARE(sampleCount, testFileSampleCount);
}
void tst_QAudioDecoderBackend::indirectReadingByBufferReadySignal()
@@ -190,7 +202,7 @@ void tst_QAudioDecoderBackend::indirectReadingByBufferReadySignal()
checkNoMoreChanges(decoder);
- QCOMPARE(sampleCount, 44094);
+ QCOMPARE(sampleCount, testFileSampleCount);
QCOMPARE(finishSpy.size(), 1);
}
@@ -232,7 +244,7 @@ void tst_QAudioDecoderBackend::indirectReadingByBufferAvailableSignal() {
checkNoMoreChanges(decoder);
- QCOMPARE(sampleCount, 44094);
+ QCOMPARE(sampleCount, testFileSampleCount);
QCOMPARE(finishSpy.size(), 1);
}
@@ -300,7 +312,7 @@ void tst_QAudioDecoderBackend::restartOnBufferReady()
checkNoMoreChanges(decoder);
- QCOMPARE(sampleCount, 44094);
+ QCOMPARE(sampleCount, testFileSampleCount);
}
void tst_QAudioDecoderBackend::restartOnFinish()
@@ -341,7 +353,7 @@ void tst_QAudioDecoderBackend::restartOnFinish()
QVERIFY(!decoder.isDecoding());
checkNoMoreChanges(decoder);
- QCOMPARE(sampleCount, 44094);
+ QCOMPARE(sampleCount, testFileSampleCount);
}
void tst_QAudioDecoderBackend::fileTest()
@@ -395,7 +407,7 @@ void tst_QAudioDecoderBackend::fileTest()
// 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
@@ -408,7 +420,7 @@ void tst_QAudioDecoderBackend::fileTest()
byteCount += buffer.byteCount();
// Now drain the decoder
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
@@ -422,14 +434,14 @@ void tst_QAudioDecoderBackend::fileTest()
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.size(), 1);
@@ -495,12 +507,12 @@ 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());
@@ -510,19 +522,14 @@ void tst_QAudioDecoderBackend::fileTest()
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
QCOMPARE_LT(qAbs(sampleCount - 22047), 100);
QCOMPARE_LT(qAbs(byteCount - 22047), 100);
- QCOMPARE_LT(qAbs(qint64(duration) - 1000000), 20000);
+ QCOMPARE_LT(qAbs(qint64(duration) - testFileDurationUs), 20000);
QCOMPARE_LT(qAbs((d.position() + (buffer.duration() / 1000)) - 1000), 20);
- QTRY_COMPARE(finishedSpy.size(), 1);
QVERIFY(!d.bufferAvailable());
QVERIFY(!d.isDecoding());
@@ -781,6 +788,7 @@ void tst_QAudioDecoderBackend::invalidSource()
void tst_QAudioDecoderBackend::deviceTest()
{
+ using namespace std::chrono;
CHECK_SELECTED_URL(m_wavFile);
QAudioDecoder d;
@@ -829,7 +837,7 @@ void tst_QAudioDecoderBackend::deviceTest()
// 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());
@@ -838,7 +846,7 @@ void tst_QAudioDecoderBackend::deviceTest()
sampleCount += buffer.sampleCount();
// Now drain the decoder
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
@@ -846,18 +854,24 @@ 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.size(), 1);
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/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
index 7f1af8bde..d9c1a2c6a 100644
--- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
+++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
@@ -151,6 +151,8 @@ private slots:
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();
@@ -208,6 +210,7 @@ private:
MaybeUrl m_colorMatrix90degClockwiseVideo = QUnexpect{};
MaybeUrl m_colorMatrix180degClockwiseVideo = QUnexpect{};
MaybeUrl m_colorMatrix270degClockwiseVideo = QUnexpect{};
+ MaybeUrl m_hdrVideo = QUnexpect{};
MediaFileSelector m_mediaSelector;
@@ -339,6 +342,8 @@ void tst_QMediaPlayerBackend::initTestCase()
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");
+
detectVlcCommand();
}
@@ -378,7 +383,10 @@ void tst_QMediaPlayerBackend::destructor_emitsOnlyQObjectDestroyedSignal_whenPla
// Arrange
m_fixture->player.setSource(*m_localVideoFile3ColorsWithSound);
m_fixture->player.play();
- QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::BufferedMedia);
+
+ // Wait for started
+ QTRY_VERIFY(m_fixture->player.mediaStatus() == QMediaPlayer::BufferedMedia
+ || m_fixture->player.mediaStatus() == QMediaPlayer::EndOfMedia);
m_fixture->clearSpies();
@@ -691,7 +699,8 @@ void tst_QMediaPlayerBackend::setSource_loadsNewMedia_whenPreviousMediaWasFullyL
QCOMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadingMedia);
QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::LoadedMedia);
m_fixture->player.play();
- QTRY_COMPARE(m_fixture->player.mediaStatus(), QMediaPlayer::BufferedMedia);
+ 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);
@@ -805,8 +814,14 @@ void tst_QMediaPlayerBackend::
QTest::addRow("Horizontal expanding (par=3/2)")
<< m_192x108_PAR_3_2_Video << QSize(192 * 3 / 2, 108);
- QTest::addRow("Vertical expanding (par=2/3)")
- << m_192x108_PAR_2_3_Video << QSize(192, 108 * 3 / 2);
+
+ 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::
@@ -1088,6 +1103,8 @@ void tst_QMediaPlayerBackend::
if (!canCreateRtspStream())
QSKIP("Rtsp stream cannot be created");
+ QSKIP_GSTREAMER("GStreamer tests fail");
+
auto temporaryFile = copyResourceToTemporaryFile(":/testdata/colors.mp4", "colors.XXXXXX.mp4");
QVERIFY(temporaryFile);
@@ -1399,9 +1416,15 @@ void tst_QMediaPlayerBackend::setMuted_doesNotChangeVolume()
void tst_QMediaPlayerBackend::processEOS()
{
- CHECK_SELECTED_URL(m_localWavFile);
-
- m_fixture->player.setSource(*m_localWavFile);
+ 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);
@@ -1427,7 +1450,7 @@ void tst_QMediaPlayerBackend::processEOS()
m_fixture->player.play();
//position is reset to start
- QTRY_VERIFY(m_fixture->player.position() < 100);
+ QTRY_COMPARE_LT(m_fixture->player.position(), 500);
QTRY_VERIFY(m_fixture->positionChanged.size() > 0);
QCOMPARE(m_fixture->positionChanged.first()[0].value<qint64>(), 0);
@@ -1451,11 +1474,8 @@ void tst_QMediaPlayerBackend::processEOS()
QCOMPARE(m_fixture->playbackStateChanged.size(), 2);
QCOMPARE(m_fixture->playbackStateChanged.last()[0].value<QMediaPlayer::PlaybackState>(), QMediaPlayer::StoppedState);
- if (!isGStreamerPlatform()) {
- // QTBUG-124517: for some media types gstreamer does not emit buffer progress messages
- QCOMPARE_GT(m_fixture->bufferProgressChanged.size(), 1);
- QCOMPARE(m_fixture->bufferProgressChanged.back().front(), 0.f);
- }
+ 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());
@@ -1842,6 +1862,8 @@ void tst_QMediaPlayerBackend::seekInStoppedState()
void tst_QMediaPlayerBackend::subsequentPlayback()
{
+ QSKIP_GSTREAMER("QTBUG-124005: spurious seek failures with gstreamer");
+
CHECK_SELECTED_URL(m_localCompressedSoundFile);
QAudioOutput output;
@@ -1855,7 +1877,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);
@@ -1900,6 +1922,7 @@ 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(), *m_localVideoFile);
@@ -1995,6 +2018,8 @@ void tst_QMediaPlayerBackend::multiplePlaybackRateChangingStressTest()
void tst_QMediaPlayerBackend::multipleSeekStressTest()
{
+ QSKIP_GSTREAMER("QTBUG-124005: spurious test failures with gstreamer");
+
#ifdef Q_OS_ANDROID
QSKIP("frame.toImage will return null image because of QTBUG-108446");
#endif
@@ -2094,7 +2119,7 @@ void tst_QMediaPlayerBackend::setPlaybackRate_changesActualRateAndFramesRenderin
QTest::addColumn<bool>("withAudio");
QTest::addColumn<int>("positionDeviationMs");
- QTest::newRow("Without audio") << false << 150;
+ QTest::newRow("Without audio") << false << 170;
// set greater positionDeviationMs for case with audio due to possible synchronization.
QTest::newRow("With audio") << true << 200;
@@ -2102,6 +2127,8 @@ void tst_QMediaPlayerBackend::setPlaybackRate_changesActualRateAndFramesRenderin
void tst_QMediaPlayerBackend::setPlaybackRate_changesActualRateAndFramesRenderingTime()
{
+ QSKIP_GSTREAMER("QTBUG-124005: timing issues");
+
QFETCH(bool, withAudio);
QFETCH(int, positionDeviationMs);
@@ -2214,6 +2241,10 @@ void tst_QMediaPlayerBackend::surfaceTest()
void tst_QMediaPlayerBackend::metadata()
{
+ // QTBUG-124380: gstreamer reports CoverArtImage instead of ThumbnailImage
+ QMediaMetaData::Key thumbnailKey =
+ isGStreamerPlatform() ? QMediaMetaData::CoverArtImage : QMediaMetaData::ThumbnailImage;
+
CHECK_SELECTED_URL(m_localFileWithMetadata);
m_fixture->player.setSource(*m_localFileWithMetadata);
@@ -2225,7 +2256,7 @@ void tst_QMediaPlayerBackend::metadata()
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(QMediaMetaData::ThumbnailImage).value<QImage>().isNull());
+ QVERIFY(!metadata.value(thumbnailKey).value<QImage>().isNull());
m_fixture->clearSpies();
m_fixture->player.setSource(QUrl());
@@ -2282,6 +2313,31 @@ void tst_QMediaPlayerBackend::metadata_returnsMetadataWithThumbnail_whenMediaHas
}
}
+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);
+
+ QSKIP_IF_NOT_FFMPEG();
+
+ 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()
{
CHECK_SELECTED_URL(m_localWavFile);
@@ -2585,13 +2641,15 @@ void tst_QMediaPlayerBackend::finiteLoops()
QCOMPARE(iterations.size(), 3u);
QCOMPARE_GT(iterations[0].startPos, 0);
QCOMPARE(iterations[0].endPos, m_fixture->player.duration());
- QCOMPARE_GT(iterations[0].posCount, 10);
QCOMPARE(iterations[1].startPos, 0);
QCOMPARE(iterations[1].endPos, m_fixture->player.duration());
- QCOMPARE_GT(iterations[1].posCount, 10);
QCOMPARE(iterations[2].startPos, 0);
QCOMPARE(iterations[2].endPos, m_fixture->player.duration());
- QCOMPARE_GT(iterations[2].posCount, 10);
+ 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);
@@ -2649,6 +2707,8 @@ void tst_QMediaPlayerBackend::infiniteLoops()
m_fixture->player.stop(); // QMediaPlayer::stop stops whether or not looping is infinite
QCOMPARE(m_fixture->player.playbackState(), QMediaPlayer::StoppedState);
+ if (isGStreamerPlatform())
+ return; // QTBUG-124005: many StalledMedia/BufferingMedia/BufferedMedia signals are emitted
QCOMPARE(m_fixture->mediaStatusChanged,
SignalList({ { QMediaPlayer::LoadingMedia },
{ QMediaPlayer::LoadedMedia },
@@ -2781,6 +2841,8 @@ void tst_QMediaPlayerBackend::seekAfterLoopReset()
void tst_QMediaPlayerBackend::changeVideoOutputNoFramesLost()
{
+ QSKIP_GSTREAMER("QTBUG-124005: gstreamer will lose frames, possibly due to buffering");
+
CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
QVideoSink sinks[4];
@@ -2803,11 +2865,11 @@ void tst_QMediaPlayerBackend::changeVideoOutputNoFramesLost()
player.setVideoOutput(&sinks[1]);
player.play();
- QTRY_VERIFY(framesCount[1] >= framesCount[0] / 4);
+ QTRY_COMPARE_GE(framesCount[1], framesCount[0] / 4);
player.setVideoOutput(&sinks[2]);
const int savedFrameNumber1 = framesCount[1];
- QTRY_VERIFY(framesCount[2] >= (framesCount[0] - savedFrameNumber1) / 2);
+ QTRY_COMPARE_GE(framesCount[2], (framesCount[0] - savedFrameNumber1) / 2);
player.setVideoOutput(&sinks[3]);
const int savedFrameNumber2 = framesCount[2];
@@ -2823,6 +2885,9 @@ void tst_QMediaPlayerBackend::changeVideoOutputNoFramesLost()
void tst_QMediaPlayerBackend::cleanSinkAndNoMoreFramesAfterStop()
{
+ QSKIP_GSTREAMER(
+ "QTBUG-124005: spurious failures on gstreamer, probably due to asynchronous play()");
+
CHECK_SELECTED_URL(m_localVideoFile3ColorsWithSound);
QVideoSink sink;
@@ -2854,6 +2919,9 @@ void tst_QMediaPlayerBackend::cleanSinkAndNoMoreFramesAfterStop()
QTest::qWait(30);
+ if (isGStreamerPlatform())
+ continue; // QTBUG-124005: stop() is asynchronous in gstreamer
+
// check if nothing changed after short waiting
QCOMPARE(framesCount, 0);
}
@@ -3003,7 +3071,11 @@ std::unique_ptr<QProcess> tst_QMediaPlayerBackend::createRtspStreamProcess(QStri
// rtsp 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.
- QTest::qWait(500);
+ int timeout = 500;
+#ifdef Q_OS_MACOS
+ timeout = 2000;
+#endif
+ QTest::qWait(timeout);
return process;
}
@@ -3084,6 +3156,8 @@ void tst_QMediaPlayerBackend::play_playsRotatedVideoOutput_whenVideoFileHasOrien
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);
}
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/shared/mediabackendutils.h b/tests/auto/integration/shared/mediabackendutils.h
index 3279f7044..1455352b5 100644
--- a/tests/auto/integration/shared/mediabackendutils.h
+++ b/tests/auto/integration/shared/mediabackendutils.h
@@ -38,6 +38,12 @@ inline bool isWindowsPlatform()
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()) \
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/mockbackend/qmockcamera.cpp b/tests/auto/unit/mockbackend/qmockcamera.cpp
index 9347e8c84..23ecc36ae 100644
--- a/tests/auto/unit/mockbackend/qmockcamera.cpp
+++ b/tests/auto/unit/mockbackend/qmockcamera.cpp
@@ -34,12 +34,6 @@ void QMockCamera::setActive(bool active)
emit activeChanged(active);
}
-/* helper method to emit the signal error */
-void QMockCamera::setError(QCamera::Error err, QString errorString)
-{
- emit error(err, errorString);
-}
-
void QMockCamera::setCamera(const QCameraDevice &camera)
{
m_camera = camera;
diff --git a/tests/auto/unit/mockbackend/qmockcamera.h b/tests/auto/unit/mockbackend/qmockcamera.h
index df8a08874..3d8159e84 100644
--- a/tests/auto/unit/mockbackend/qmockcamera.h
+++ b/tests/auto/unit/mockbackend/qmockcamera.h
@@ -31,9 +31,6 @@ public:
void setActive(bool active) override;
- /* helper method to emit the signal error */
- void setError(QCamera::Error err, QString errorString);
-
void setCamera(const QCameraDevice &camera) override;
bool setCameraFormat(const QCameraFormat &format) override;
diff --git a/tests/auto/unit/mockbackend/qmockvideobuffer.h b/tests/auto/unit/mockbackend/qmockvideobuffer.h
index f82a09a59..d09f93391 100644
--- a/tests/auto/unit/mockbackend/qmockvideobuffer.h
+++ b/tests/auto/unit/mockbackend/qmockvideobuffer.h
@@ -12,8 +12,6 @@ class QMockVideoBuffer : public QAbstractVideoBuffer
public:
QMockVideoBuffer(QImage image) : QAbstractVideoBuffer(QVideoFrame::NoHandle), m_image(image) { }
- QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
-
MapData map(QVideoFrame::MapMode mode) override
{
MapData mapData;
diff --git a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp
index 2cecbe21b..a63d06b86 100644
--- a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp
+++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp
@@ -12,6 +12,8 @@
QT_USE_NAMESPACE
+// NOLINTBEGIN(readability-convert-member-functions-to-static)
+
using namespace Qt::Literals;
QGstTagListHandle tst_GStreamer::parseTagList(const char *str)
@@ -151,6 +153,25 @@ void tst_GStreamer::QGstElement_createFromPipelineDescription_multipleElementsCr
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);
+}
+
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
index 7b490c22b..203062c8f 100644
--- a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h
+++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h
@@ -32,6 +32,8 @@ private slots:
void QGstElement_createFromPipelineDescription();
void QGstElement_createFromPipelineDescription_multipleElementsCreatesBin();
+ void QGstPad_inferTypeFromName();
+
private:
QGstreamerIntegration integration;
};
diff --git a/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp b/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp
index 567b086f2..5539fe3c4 100644
--- a/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp
+++ b/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp
@@ -28,7 +28,6 @@ private slots:
void handleType_data();
void handleType();
void handle();
- void mapMode();
void mapModeDebug_data();
void mapModeDebug();
};
@@ -38,8 +37,6 @@ class QtTestVideoBuffer : public QAbstractVideoBuffer
public:
QtTestVideoBuffer(QVideoFrame::HandleType type) : QAbstractVideoBuffer(type) {}
- [[nodiscard]] QVideoFrame::MapMode mapMode() const override { return QVideoFrame::ReadWrite; }
-
MapData map(QVideoFrame::MapMode) override { return {}; }
void unmap() override {}
};
@@ -97,12 +94,6 @@ void tst_QAbstractVideoBuffer::handle()
QVERIFY(buffer.textureHandle(nullptr, 0) == 0);
}
-void tst_QAbstractVideoBuffer::mapMode()
-{
- QtTestVideoBuffer maptest(QVideoFrame::NoHandle);
- QVERIFY2(maptest.mapMode() == QVideoFrame::ReadWrite, "ReadWrite Failed");
-}
-
void tst_QAbstractVideoBuffer::mapModeDebug_data()
{
QTest::addColumn<QVideoFrame::MapMode>("mapMode");
diff --git a/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp b/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp
index 1ba624eec..bd1972550 100644
--- a/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp
+++ b/tests/auto/unit/multimedia/qcamera/tst_qcamera.cpp
@@ -607,7 +607,7 @@ void tst_QCamera::testErrorSignal()
QSignalSpy spyError(&camera, &QCamera::errorOccurred);
/* Set the QPlatformCamera error and verify if the signal is emitted correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QStringLiteral("Camera Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError, QStringLiteral("Camera Error"));
QVERIFY(spyError.size() == 1);
QCamera::Error err = qvariant_cast<QCamera::Error >(spyError.at(0).at(0));
@@ -616,7 +616,8 @@ void tst_QCamera::testErrorSignal()
spyError.clear();
/* Set the QPlatformCamera error and verify if the signal is emitted correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QStringLiteral("InvalidRequestError Error"));
+ 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);
@@ -624,7 +625,8 @@ void tst_QCamera::testErrorSignal()
spyError.clear();
/* Set the QPlatformCamera error and verify if the signal is emitted correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QStringLiteral("NotSupportedFeatureError Error"));
+ 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);
@@ -640,15 +642,17 @@ void tst_QCamera::testError()
auto *service = QMockIntegration::instance()->lastCaptureService();
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QStringLiteral("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,QStringLiteral("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,QStringLiteral("CameraError Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("CameraError Error"));
QVERIFY(camera.error() == QCamera::CameraError);
}
@@ -662,15 +666,17 @@ void tst_QCamera::testErrorString()
auto *service = QMockIntegration::instance()->lastCaptureService();
/* Set the QPlatformCamera error and verify if it is set correctly in QCamera */
- service->mockCameraControl->setError(QCamera::CameraError,QStringLiteral("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,QStringLiteral("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,QStringLiteral("CameraError Error"));
+ service->mockCameraControl->updateError(QCamera::CameraError,
+ QStringLiteral("CameraError Error"));
QVERIFY(camera.errorString() == QStringLiteral("CameraError Error"));
}
diff --git a/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp b/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp
index 7ca2b5980..455586243 100644
--- a/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp
+++ b/tests/auto/unit/multimedia/qcameradevice/tst_qcameradevice.cpp
@@ -9,40 +9,25 @@
#include <qmediadevices.h>
#include "qmockintegration.h"
-#include "qmockmediacapturesession.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();
+ void qDebug_operator();
};
-void tst_QCameraDevice::initTestCase()
-{
-}
-
-void tst_QCameraDevice::init()
-{
-}
-
-void tst_QCameraDevice::cleanup()
-{
-}
-
void tst_QCameraDevice::constructor()
{
{
@@ -50,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);
}
@@ -66,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);
}
@@ -82,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);
@@ -97,8 +82,8 @@ void tst_QCameraDevice::availableCameras()
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);
@@ -110,8 +95,8 @@ void tst_QCameraDevice::availableCameras()
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);
}
@@ -136,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/qmediacapture_gstreamer/CMakeLists.txt b/tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt
index 8a4734434..209be5883 100644
--- a/tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/qmediacapture_gstreamer/CMakeLists.txt
@@ -8,7 +8,11 @@
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
index 55bce42f5..d51314e79 100644
--- a/tests/auto/unit/multimedia/qmediacapture_gstreamer/tst_qmediacapture_gstreamer.cpp
+++ b/tests/auto/unit/multimedia/qmediacapture_gstreamer/tst_qmediacapture_gstreamer.cpp
@@ -2,14 +2,25 @@
// 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
@@ -22,15 +33,34 @@ public slots:
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();
private:
std::unique_ptr<QMediaCaptureSession> session;
+ QGStreamerPlatformSpecificInterface *gstInterface()
+ {
+ return QGStreamerPlatformSpecificInterface::instance();
+ }
+
GstPipeline *getGstPipeline()
{
- return reinterpret_cast<GstPipeline *>(
- QPlatformMediaCaptureSession::nativePipeline(session.get()));
+ auto *iface = QGStreamerPlatformSpecificInterface::instance();
+ return iface ? iface->gstPipeline(session.get()) : nullptr;
+ }
+
+ QGstPipeline getPipeline()
+ {
+ return QGstPipeline{
+ getGstPipeline(),
+ QGstPipeline::NeedsRef,
+ };
}
void dumpGraph(const char *fileNamePrefix)
@@ -56,6 +86,11 @@ void tst_QMediaCaptureGStreamer::cleanup()
session.reset();
}
+void tst_QMediaCaptureGStreamer::mediaIntegration_hasPlatformSpecificInterface()
+{
+ QVERIFY(QGStreamerPlatformSpecificInterface::instance());
+}
+
void tst_QMediaCaptureGStreamer::constructor_preparesGstPipeline()
{
auto *rawPipeline = getGstPipeline();
@@ -70,6 +105,84 @@ void tst_QMediaCaptureGStreamer::constructor_preparesGstPipeline()
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, 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, 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");
+}
+
QTEST_GUILESS_MAIN(tst_QMediaCaptureGStreamer)
#include "tst_qmediacapture_gstreamer.moc"
diff --git a/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp
index a11e25f29..d43296c40 100644
--- a/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp
+++ b/tests/auto/unit/multimedia/qmediaplayer_gstreamer/tst_qmediaplayer_gstreamer.cpp
@@ -4,6 +4,7 @@
#include <QtTest/QtTest>
#include <QtMultimedia/qmediaplayer.h>
#include <QtMultimedia/private/qmediaplayer_p.h>
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
#include <QtQGstreamerMediaPlugin/private/qgstpipeline_p.h>
#include <memory>
@@ -29,7 +30,8 @@ private:
GstPipeline *getGstPipeline()
{
- return reinterpret_cast<GstPipeline *>(QPlatformMediaPlayer::nativePipeline(player.get()));
+ auto *iface = QGStreamerPlatformSpecificInterface::instance();
+ return iface ? iface->gstPipeline(player.get()) : nullptr;
}
void dumpGraph(const char *fileNamePrefix)
diff --git a/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp b/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp
index 97f5e3b62..0494289cb 100644
--- a/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp
+++ b/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp
@@ -25,19 +25,11 @@ private slots:
void map_changesMappedStateAndReturnsProperMappings_whenBufferIsNotMapped_data();
void map_changesMappedStateAndReturnsProperMappings_whenBufferIsNotMapped();
- void mapWithNotMappedMode_doesNothing_data();
- void mapWithNotMappedMode_doesNothing();
-
void map_doesNothing_whenBufferIsMapped_data();
void map_doesNothing_whenBufferIsMapped();
void mapMemoryBufferWithReadOnly_doesntDetachArray();
- void mapMemoryBufferWithWriteModes_detachsArray_data();
- void mapMemoryBufferWithWriteModes_detachsArray();
-
- void underlyingByteArray_returnsCorrectValueForPlanes();
-
void unmap_resetsMappedState_whenBufferIsMapped_data();
void unmap_resetsMappedState_whenBufferIsMapped();
@@ -111,8 +103,6 @@ void tst_QVideoBuffers::map_changesMappedStateAndReturnsProperMappings_whenBuffe
auto mappedData = buffer->map(mapMode);
- QCOMPARE(buffer->mapMode(), mapMode);
-
QCOMPARE(mappedData.nPlanes, 1);
QVERIFY(mappedData.data[0]);
QCOMPARE(mappedData.size[0], 80);
@@ -122,23 +112,6 @@ void tst_QVideoBuffers::map_changesMappedStateAndReturnsProperMappings_whenBuffe
QCOMPARE(QByteArray(data, mappedData.size[0]), m_byteArray);
}
-void tst_QVideoBuffers::mapWithNotMappedMode_doesNothing_data()
-{
- generateImageAndMemoryBuffersWithAllModes();
-}
-
-void tst_QVideoBuffers::mapWithNotMappedMode_doesNothing()
-{
- QFETCH(BufferPtr, buffer);
- QFETCH(QVideoFrame::MapMode, mapMode);
-
- buffer->map(mapMode);
-
- buffer->map(QVideoFrame::NotMapped);
-
- QCOMPARE(buffer->mapMode(), mapMode);
-}
-
void tst_QVideoBuffers::map_doesNothing_whenBufferIsMapped_data()
{
generateImageAndMemoryBuffersWithAllModes();
@@ -152,51 +125,17 @@ void tst_QVideoBuffers::map_doesNothing_whenBufferIsMapped()
buffer->map(mapMode);
auto mappedData = buffer->map(QVideoFrame::ReadOnly);
QCOMPARE(mappedData.nPlanes, 0);
- QCOMPARE(buffer->mapMode(), mapMode);
}
void tst_QVideoBuffers::mapMemoryBufferWithReadOnly_doesntDetachArray()
{
auto buffer = createMemoryBuffer();
- auto underlyingArray = buffer->underlyingByteArray(0);
auto mappedData = buffer->map(QVideoFrame::ReadOnly);
QCOMPARE(mappedData.nPlanes, 1);
- QCOMPARE(mappedData.data[0], reinterpret_cast<const uchar *>(underlyingArray.constData()));
QCOMPARE(mappedData.data[0], reinterpret_cast<const uchar *>(m_byteArray.constData()));
}
-void tst_QVideoBuffers::mapMemoryBufferWithWriteModes_detachsArray_data()
-{
- QTest::addColumn<QVideoFrame::MapMode>("mapMode");
-
- QTest::newRow(mapModeToString(QVideoFrame::WriteOnly).toUtf8().constData()) << QVideoFrame::WriteOnly;
- QTest::newRow(mapModeToString(QVideoFrame::WriteOnly).toUtf8().constData()) << QVideoFrame::WriteOnly;
-}
-
-void tst_QVideoBuffers::mapMemoryBufferWithWriteModes_detachsArray()
-{
- QFETCH(QVideoFrame::MapMode, mapMode);
-
- auto buffer = createMemoryBuffer();
- auto underlyingArray = buffer->underlyingByteArray(0);
-
- auto mappedData = buffer->map(mapMode);
- QCOMPARE(mappedData.nPlanes, 1);
- QCOMPARE_NE(mappedData.data[0], reinterpret_cast<const uchar *>(underlyingArray.constData()));
-}
-
-void tst_QVideoBuffers::underlyingByteArray_returnsCorrectValueForPlanes()
-{
- auto buffer = createMemoryBuffer();
-
- QCOMPARE(buffer->underlyingByteArray(0).constData(), m_byteArray.constData());
-
- QVERIFY(buffer->underlyingByteArray(-1).isNull());
- QVERIFY(buffer->underlyingByteArray(1).isNull());
- QVERIFY(buffer->underlyingByteArray(2).isNull());
-}
-
void tst_QVideoBuffers::unmap_resetsMappedState_whenBufferIsMapped_data()
{
generateImageAndMemoryBuffersWithAllModes();
@@ -211,12 +150,9 @@ void tst_QVideoBuffers::unmap_resetsMappedState_whenBufferIsMapped()
buffer->unmap();
- QCOMPARE(buffer->mapMode(), QVideoFrame::NotMapped);
-
// Check buffer is valid and it's possible to map again
auto mappedData = buffer->map(QVideoFrame::ReadOnly);
QCOMPARE(mappedData.nPlanes, 1);
- QCOMPARE(buffer->mapMode(), QVideoFrame::ReadOnly);
const auto data = reinterpret_cast<const char*>(mappedData.data[0]);
QCOMPARE(QByteArray(data, mappedData.size[0]), m_byteArray);
diff --git a/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp b/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp
index 76d62dba3..a0cc96d02 100644
--- a/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp
+++ b/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp
@@ -10,6 +10,7 @@
#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) \
@@ -125,6 +126,53 @@ bool compareEq(QVideoFrame &frame, const QImage &image)
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
@@ -159,6 +207,9 @@ private slots:
void formatConversion_data();
void formatConversion();
+ void qImageFromVideoFrame_doesNotCrash_whenCalledWithEvenAndOddSizedFrames_data();
+ void qImageFromVideoFrame_doesNotCrash_whenCalledWithEvenAndOddSizedFrames();
+
void isMapped();
void isReadable();
void isWritable();
@@ -170,6 +221,7 @@ private slots:
void mirrored_takesValue_fromVideoFrameFormat();
void rotation_takesValue_fromVideoFrameFormat();
+ void streamFrameRate_takesValue_fromVideoFrameFormat();
void constructor_createsInvalidFrame_whenCalledWithNullImage();
void constructor_createsInvalidFrame_whenCalledWithEmptyImage();
@@ -189,8 +241,6 @@ public:
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 {}
};
@@ -205,8 +255,6 @@ public:
: QAbstractVideoBuffer(type)
{}
- [[nodiscard]] QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
-
MapData map(QVideoFrame::MapMode mode) override
{
m_mapMode = mode;
@@ -939,6 +987,69 @@ void tst_QVideoFrame::formatConversion()
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)); \
@@ -1139,6 +1250,20 @@ void tst_QVideoFrame::rotation_takesValue_fromVideoFrameFormat()
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{} };
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
index 682e999cc..682e999cc 100644
--- 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
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_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_AdobeRgb_Video.png
+++ 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_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT2020_Full.png
+++ 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_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_adobergb_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT2020_Video.png
+++ 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_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT601_Full.png
+++ 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_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT601_Video.png
+++ 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_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT709_Full.png
+++ 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_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt2020_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_BT709_Video.png
+++ 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_argb8888_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_AdobeRgb_Full.png
+++ 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_argb8888_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_AdobeRgb_Video.png
+++ 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_argb8888_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT2020_Full.png
+++ 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_argb8888_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt601_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT2020_Video.png
+++ 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_argb8888_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT601_Full.png
+++ 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_argb8888_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT601_Video.png
+++ 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_argb8888_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT709_Full.png
+++ 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_argb8888_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_abgr8888_bt709_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_BT709_Video.png
+++ 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_premultiplied_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_AdobeRgb_Full.png
+++ 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_premultiplied_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_AdobeRgb_Video.png
+++ 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_premultiplied_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT2020_Full.png
+++ 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_premultiplied_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_adobergb_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT2020_Video.png
+++ 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_premultiplied_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT601_Full.png
+++ 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_premultiplied_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT601_Video.png
+++ 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_premultiplied_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT709_Full.png
+++ 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_premultiplied_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt2020_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_BT709_Video.png
+++ 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_bgra8888_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_AdobeRgb_Full.png
+++ 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_bgra8888_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_AdobeRgb_Video.png
+++ 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_bgra8888_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT2020_Full.png
+++ 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_bgra8888_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt601_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT2020_Video.png
+++ 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_bgra8888_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT601_Full.png
+++ 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_bgra8888_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT601_Video.png
+++ 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_bgra8888_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT709_Full.png
+++ 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_bgra8888_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_bt709_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_BT709_Video.png
+++ 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_bgra8888_premultiplied_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_AdobeRgb_Full.png
+++ 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_bgra8888_premultiplied_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_AdobeRgb_Video.png
+++ 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_bgra8888_premultiplied_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT2020_Full.png
+++ 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_bgra8888_premultiplied_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_adobergb_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT2020_Video.png
+++ 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_bgra8888_premultiplied_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT601_Full.png
+++ 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_bgra8888_premultiplied_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT601_Video.png
+++ 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_bgra8888_premultiplied_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT709_Full.png
+++ 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_bgra8888_premultiplied_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt2020_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_BT709_Video.png
+++ 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_bgrx8888_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_AdobeRgb_Full.png
+++ 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_bgrx8888_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_AdobeRgb_Video.png
+++ 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_bgrx8888_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT2020_Full.png
+++ 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_bgrx8888_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt601_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT2020_Video.png
+++ 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_bgrx8888_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT601_Full.png
+++ 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_bgrx8888_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT601_Video.png
+++ 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_bgrx8888_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT709_Full.png
+++ 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_bgrx8888_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_argb8888_premultiplied_bt709_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgrx8888_BT709_Video.png
+++ 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_rgba8888_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_AdobeRgb_Full.png
+++ 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_rgba8888_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_AdobeRgb_Video.png
+++ 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_rgba8888_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT2020_Full.png
+++ 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_rgba8888_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_adobergb_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT2020_Video.png
+++ 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_rgba8888_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT601_Full.png
+++ 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_rgba8888_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT601_Video.png
+++ 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_rgba8888_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT709_Full.png
+++ 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_rgba8888_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt2020_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgba8888_BT709_Video.png
+++ 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_rgbx8888_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_AdobeRgb_Full.png
+++ 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_rgbx8888_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_AdobeRgb_Video.png
+++ 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_rgbx8888_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT2020_Full.png
+++ 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_rgbx8888_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt601_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT2020_Video.png
+++ 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_rgbx8888_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT601_Full.png
+++ 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_rgbx8888_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT601_Video.png
+++ 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_rgbx8888_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT709_Full.png
+++ 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_rgbx8888_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_bt709_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_rgbx8888_BT709_Video.png
+++ 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_xbgr8888_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_AdobeRgb_Full.png
+++ 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_xbgr8888_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_AdobeRgb_Video.png
+++ 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_xbgr8888_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT2020_Full.png
+++ 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_xbgr8888_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_adobergb_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT2020_Video.png
+++ 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_xbgr8888_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT601_Full.png
+++ 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_xbgr8888_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT601_Video.png
+++ 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_xbgr8888_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT709_Full.png
+++ 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_xbgr8888_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt2020_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xbgr8888_BT709_Video.png
+++ 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_xrgb8888_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_AdobeRgb_Full.png
+++ 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_xrgb8888_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_AdobeRgb_Video.png
+++ 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_xrgb8888_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT2020_Full.png
+++ 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_xrgb8888_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt601_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT2020_Video.png
+++ 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_xrgb8888_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT601_Full.png
+++ 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_xrgb8888_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_full_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT601_Video.png
+++ 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_xrgb8888_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT709_Full.png
+++ 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_xrgb8888_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_bgra8888_premultiplied_bt709_video_cpu.png
index 682e999cc..682e999cc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_xrgb8888_BT709_Video.png
+++ 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_420p_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_full.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_AdobeRgb_Full.png
+++ 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_420p_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_adobergb_video.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_AdobeRgb_Video.png
+++ 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_420p_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_full.png
index d6d461f5d..d6d461f5d 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT2020_Full.png
+++ 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_420p_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt2020_video.png
index 2a4f7d8a7..2a4f7d8a7 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT2020_Video.png
+++ 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_420p_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_full.png
index d291f62bb..d291f62bb 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT601_Full.png
+++ 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_420p_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt601_video.png
index 35296fc03..35296fc03 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT601_Video.png
+++ 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_420p_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_full.png
index 64e5eb6dc..64e5eb6dc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT709_Full.png
+++ 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_420p_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_bt709_video.png
index 9f6bdd1ea..9f6bdd1ea 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_420p_BT709_Video.png
+++ 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
index 90b2b3601..90b2b3601 100644
--- 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
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
index 90b2b3601..90b2b3601 100644
--- 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
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
index 2e78cfc31..2e78cfc31 100644
--- 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
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
index d673b7ce5..d673b7ce5 100644
--- 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
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
index 8be30a706..8be30a706 100644
--- 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
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
index 1f64ea0f1..1f64ea0f1 100644
--- 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
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
index 24fb9065e..24fb9065e 100644
--- 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
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
index f737d8602..f737d8602 100644
--- 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
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_imc1_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_full.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_AdobeRgb_Full.png
+++ 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_imc1_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_adobergb_video.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_AdobeRgb_Video.png
+++ 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_imc1_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_full.png
index d6d461f5d..d6d461f5d 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT2020_Full.png
+++ 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_imc1_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt2020_video.png
index 2a4f7d8a7..2a4f7d8a7 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT2020_Video.png
+++ 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_imc1_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_full.png
index d291f62bb..d291f62bb 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT601_Full.png
+++ 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_imc1_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt601_video.png
index 35296fc03..35296fc03 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT601_Video.png
+++ 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_imc1_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_full.png
index 64e5eb6dc..64e5eb6dc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT709_Full.png
+++ 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_imc1_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_bt709_video.png
index 9f6bdd1ea..9f6bdd1ea 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc1_BT709_Video.png
+++ 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
index 6efa73ea2..6efa73ea2 100644
--- 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
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
index 6efa73ea2..6efa73ea2 100644
--- 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
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
index 8d6a36a1c..8d6a36a1c 100644
--- 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
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
index dab23bf0d..dab23bf0d 100644
--- 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
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
index 36e787cef..36e787cef 100644
--- 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
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
index 01e6ab967..01e6ab967 100644
--- 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
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
index 22beff2e8..22beff2e8 100644
--- 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
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
index c2af074b8..c2af074b8 100644
--- 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
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_imc3_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_full.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_AdobeRgb_Full.png
+++ 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_imc3_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_adobergb_video.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_AdobeRgb_Video.png
+++ 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_imc3_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_full.png
index d6d461f5d..d6d461f5d 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT2020_Full.png
+++ 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_imc3_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt2020_video.png
index 2a4f7d8a7..2a4f7d8a7 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT2020_Video.png
+++ 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_imc3_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_full.png
index d291f62bb..d291f62bb 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT601_Full.png
+++ 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_imc3_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt601_video.png
index 35296fc03..35296fc03 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT601_Video.png
+++ 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_imc3_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_full.png
index 64e5eb6dc..64e5eb6dc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT709_Full.png
+++ 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_imc3_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_bt709_video.png
index 9f6bdd1ea..9f6bdd1ea 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_imc3_BT709_Video.png
+++ 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_nv12_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_full.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_AdobeRgb_Full.png
+++ 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_nv12_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_adobergb_video.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_AdobeRgb_Video.png
+++ 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_nv12_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_full.png
index d6d461f5d..d6d461f5d 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT2020_Full.png
+++ 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_nv12_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt2020_video.png
index 2a4f7d8a7..2a4f7d8a7 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT2020_Video.png
+++ 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_nv12_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_full.png
index d291f62bb..d291f62bb 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT601_Full.png
+++ 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_nv12_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt601_video.png
index 35296fc03..35296fc03 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT601_Video.png
+++ 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_nv12_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_full.png
index 64e5eb6dc..64e5eb6dc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT709_Full.png
+++ 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_nv12_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_bt709_video.png
index 9f6bdd1ea..9f6bdd1ea 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv12_BT709_Video.png
+++ 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
index 71e107b8a..71e107b8a 100644
--- 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
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
index 71e107b8a..71e107b8a 100644
--- 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
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
index 58a7ebc92..58a7ebc92 100644
--- 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
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
index d8756caac..d8756caac 100644
--- 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
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
index 905568bf9..905568bf9 100644
--- 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
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
index f374df207..f374df207 100644
--- 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
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
index d2ee0f8e2..d2ee0f8e2 100644
--- 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
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
index 740de7f79..740de7f79 100644
--- 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
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
index ad76d393a..ad76d393a 100644
--- 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
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
index ad76d393a..ad76d393a 100644
--- 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
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
index a6e47132c..a6e47132c 100644
--- 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
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
index d9760b9c9..d9760b9c9 100644
--- 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
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
index 04ae5e1cd..04ae5e1cd 100644
--- 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
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
index 9faa15fad..9faa15fad 100644
--- 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
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
index 84b04ff9e..84b04ff9e 100644
--- 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
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
index 505752c10..505752c10 100644
--- 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
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
index c5243c441..c5243c441 100644
--- 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
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
index c5243c441..c5243c441 100644
--- 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
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
index 0a9874943..0a9874943 100644
--- 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
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
index 7318c1e99..7318c1e99 100644
--- 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
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
index 68789bef5..68789bef5 100644
--- 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
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
index bfd6396ec..bfd6396ec 100644
--- 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
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
index 704c59cf9..704c59cf9 100644
--- 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
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
index d9ad9c239..d9ad9c239 100644
--- 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
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
index b1dc781f2..b1dc781f2 100644
--- 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
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
index b1dc781f2..b1dc781f2 100644
--- 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
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
index 619ee36a4..619ee36a4 100644
--- 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
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
index 881f6be33..881f6be33 100644
--- 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
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
index b1d3111df..b1d3111df 100644
--- 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
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
index e4d1ce940..e4d1ce940 100644
--- 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
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
index b1d3111df..b1d3111df 100644
--- 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
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
index df8df3edd..df8df3edd 100644
--- 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
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
index 130a3b541..130a3b541 100644
--- 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
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
index 130a3b541..130a3b541 100644
--- 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
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
index 21ed2218a..21ed2218a 100644
--- 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
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
index f60f53d02..f60f53d02 100644
--- 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
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
index df59b71e7..df59b71e7 100644
--- 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
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
index dbca71c70..dbca71c70 100644
--- 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
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
index df59b71e7..df59b71e7 100644
--- 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
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
index 3479bb890..3479bb890 100644
--- 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
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
index 20b24da65..20b24da65 100644
--- 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
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
index 20b24da65..20b24da65 100644
--- 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
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
index b96379a0b..b96379a0b 100644
--- 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
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
index c77645b59..c77645b59 100644
--- 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
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
index a1b8b62da..a1b8b62da 100644
--- 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
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
index 7a69f6afa..7a69f6afa 100644
--- 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
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
index 644b083fe..644b083fe 100644
--- 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
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
index d4e9debd7..d4e9debd7 100644
--- 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
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_yuv420p_adobergb_full.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_AdobeRgb_Full.png
+++ 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_nv21_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_adobergb_video.png
index 2af7cdaa4..2af7cdaa4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_AdobeRgb_Video.png
+++ 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_nv21_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_full.png
index d6d461f5d..d6d461f5d 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT2020_Full.png
+++ 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_nv21_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt2020_video.png
index 2a4f7d8a7..2a4f7d8a7 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT2020_Video.png
+++ 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_nv21_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_full.png
index d291f62bb..d291f62bb 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT601_Full.png
+++ 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_nv21_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt601_video.png
index 35296fc03..35296fc03 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT601_Video.png
+++ 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_nv21_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_full.png
index 64e5eb6dc..64e5eb6dc 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT709_Full.png
+++ 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_nv21_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv420p_bt709_video.png
index 9f6bdd1ea..9f6bdd1ea 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_nv21_BT709_Video.png
+++ 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_422p_AdobeRgb_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_full.png
index 3e255af2f..3e255af2f 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_AdobeRgb_Full.png
+++ 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_422p_AdobeRgb_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_adobergb_video.png
index 3e255af2f..3e255af2f 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_AdobeRgb_Video.png
+++ 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_422p_BT2020_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_full.png
index 74fd12726..74fd12726 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT2020_Full.png
+++ 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_422p_BT2020_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt2020_video.png
index e358d16d8..e358d16d8 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT2020_Video.png
+++ 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_422p_BT601_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_full.png
index cb1cbbd34..cb1cbbd34 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT601_Full.png
+++ 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_422p_BT601_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt601_video.png
index 6dd95a078..6dd95a078 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT601_Video.png
+++ 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_422p_BT709_Full.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_full.png
index 3e92f3695..3e92f3695 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT709_Full.png
+++ 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_422p_BT709_Video.png b/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_yuv422p_bt709_video.png
index e94891e1c..e94891e1c 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/testdata/umbrellas.jpg_422p_BT709_Video.png
+++ 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
index c5243c441..c5243c441 100644
--- 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
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
index c5243c441..c5243c441 100644
--- 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
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
index 0a9874943..0a9874943 100644
--- 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
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
index 7318c1e99..7318c1e99 100644
--- 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
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
index 68789bef5..68789bef5 100644
--- 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
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
index bfd6396ec..bfd6396ec 100644
--- 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
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
index 704c59cf9..704c59cf9 100644
--- 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
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
index d9ad9c239..d9ad9c239 100644
--- 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
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
index 2af7cdaa4..2af7cdaa4 100644
--- 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
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
index 2af7cdaa4..2af7cdaa4 100644
--- 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
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
index d6d461f5d..d6d461f5d 100644
--- 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
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
index 2a4f7d8a7..2a4f7d8a7 100644
--- 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
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
index d291f62bb..d291f62bb 100644
--- 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
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
index 35296fc03..35296fc03 100644
--- 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
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
index 64e5eb6dc..64e5eb6dc 100644
--- 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
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
index 9f6bdd1ea..9f6bdd1ea 100644
--- 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
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
index 22b7ddd36..d29078bd4 100644
--- a/tests/auto/unit/multimedia/qvideoframecolormanagement/tst_qvideoframecolormanagement.cpp
+++ b/tests/auto/unit/multimedia/qvideoframecolormanagement/tst_qvideoframecolormanagement.cpp
@@ -6,6 +6,7 @@
#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 <QtGui/QColorSpace>
@@ -22,6 +23,7 @@ struct TestParams
QVideoFrameFormat::PixelFormat pixelFormat;
QVideoFrameFormat::ColorSpace colorSpace;
QVideoFrameFormat::ColorRange colorRange;
+ bool forceCpu;
};
QString toString(QVideoFrameFormat::ColorRange r)
@@ -45,54 +47,54 @@ std::vector<QVideoFrameFormat::ColorRange> colorRanges()
};
}
-// clang-format off
-
-static const QHash<QVideoFrameFormat::PixelFormat, const char*> s_formats {
- { QVideoFrameFormat::Format_ARGB8888, "argb8888" },
- { QVideoFrameFormat::Format_ARGB8888_Premultiplied, "argb8888_premultiplied" },
- { QVideoFrameFormat::Format_XRGB8888, "xrgb8888" },
- { QVideoFrameFormat::Format_BGRA8888, "bgra8888" },
- { QVideoFrameFormat::Format_BGRA8888_Premultiplied, "bgra8888_premultiplied" },
- { QVideoFrameFormat::Format_BGRX8888, "bgrx8888" },
- { QVideoFrameFormat::Format_ABGR8888, "abgr8888" },
- { QVideoFrameFormat::Format_XBGR8888, "xbgr8888" },
- { QVideoFrameFormat::Format_RGBA8888, "rgba8888" },
- { QVideoFrameFormat::Format_RGBX8888, "rgbx8888" },
- { QVideoFrameFormat::Format_NV12, "nv12" },
- { QVideoFrameFormat::Format_NV21, "nv21" },
- { QVideoFrameFormat::Format_IMC1, "imc1" },
- { QVideoFrameFormat::Format_IMC2, "imc2" },
- { QVideoFrameFormat::Format_IMC3, "imc3" },
- { QVideoFrameFormat::Format_IMC4, "imc4" },
- //{ QVideoFrameFormat::Format_AYUV, "ayuv" }, // TODO: Fixme (No corresponding FFmpeg format available)
- //{ QVideoFrameFormat::Format_AYUV_Premultiplied, "ayuv_premultiplied" }, // TODO: Fixme (No corresponding FFmpeg format available)
- { QVideoFrameFormat::Format_YV12, "yv12" },
- { QVideoFrameFormat::Format_YUV420P, "420p" },
- { QVideoFrameFormat::Format_YUV422P, "422p" },
- { QVideoFrameFormat::Format_UYVY, "uyvy" },
- { QVideoFrameFormat::Format_YUYV, "yuyv" },
- { QVideoFrameFormat::Format_Y8, "y8" },
- { QVideoFrameFormat::Format_Y16, "y16" },
- { QVideoFrameFormat::Format_P010, "p010" },
- { QVideoFrameFormat::Format_P016, "p016" },
- { QVideoFrameFormat::Format_YUV420P10, "yuv420p10" }
-};
+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;
+}
-// clang-format on
+bool supportsCpuConversion(QVideoFrameFormat::PixelFormat format)
+{
+ return format != QVideoFrameFormat::Format_YUV420P10;
+}
QString toString(QVideoFrameFormat::PixelFormat f)
{
- if (!s_formats.contains(f)) {
- Q_ASSERT(false);
- return {};
- }
-
- return s_formats.value(f);
+ return QVideoFrameFormat::pixelFormatToString(f);
}
-QList<QVideoFrameFormat::PixelFormat> pixelFormats()
+QSet<QVideoFrameFormat::PixelFormat> pixelFormats()
{
- return s_formats.keys();
+ return s_formats;
}
bool isSupportedPixelFormat(QVideoFrameFormat::PixelFormat pixelFormat)
@@ -139,11 +141,15 @@ std::vector<QVideoFrameFormat::ColorSpace> colorSpaces()
QString name(const TestParams &p)
{
- return QStringLiteral("%1_%2_%3_%4")
- .arg(p.fileName)
- .arg(toString(p.pixelFormat))
- .arg(toString(p.colorSpace))
- .arg(toString(p.colorRange));
+ 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")
@@ -381,7 +387,7 @@ class tst_qvideoframecolormanagement : public QObject
Q_OBJECT
private slots:
- void toImage_savesWithCorrectColors_data()
+ void qImageFromVideoFrame_returnsQImageWithCorrectColors_data()
{
QTest::addColumn<QString>("fileName");
QTest::addColumn<TestParams>("params");
@@ -389,12 +395,22 @@ private slots:
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 (!isSupportedPixelFormat(pixelFormat))
+ continue;
- TestParams param{ file, pixelFormat, colorSpace, colorRange };
- QTest::addRow("%s", name(param).toLatin1().data()) << file << param;
+ 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;
+ }
}
}
}
@@ -402,10 +418,11 @@ private slots:
}
// This test is a regression test for the QMultimedia display pipeline.
- // It compares rendered output (as created by toImage) 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 toImage_savesWithCorrectColors()
+ // 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);
@@ -416,7 +433,8 @@ private slots:
const QVideoFrame frame = createTestFrame(params, templateImage);
// Act
- const QImage actual = frame.toImage();
+ const QImage actual =
+ qImageFromVideoFrame(frame, QtVideo::Rotation::None, false, false, params.forceCpu);
// Assert
constexpr int diffThreshold = 4;
@@ -439,6 +457,7 @@ private slots:
QCOMPARE_LT(result->MaxDiff, 6); // Maximum per-channel difference
}
+
private:
ReferenceData m_reference;
};
diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt
index 08e38e893..b3b608206 100644
--- a/tests/manual/CMakeLists.txt
+++ b/tests/manual/CMakeLists.txt
@@ -6,6 +6,10 @@ add_subdirectory(devices)
add_subdirectory(minimal-player)
add_subdirectory(wasm)
+if(QT_FEATURE_gstreamer)
+ add_subdirectory(gstreamer-custom-camera)
+endif()
+
if(TARGET Qt::Quick)
add_subdirectory(qml-minimal-camera)
add_subdirectory(qml-minimal-player)
diff --git a/tests/manual/gstreamer-custom-camera/CMakeLists.txt b/tests/manual/gstreamer-custom-camera/CMakeLists.txt
new file mode 100644
index 000000000..34281957d
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(sidepanel LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/gstreamer-custom-camera")
+
+find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia MultimediaWidgets)
+
+qt_add_executable( gstreamer-custom-camera WIN32 MACOSX_BUNDLE
+ gstreamer-custom-camera.cpp
+)
+
+target_link_libraries( gstreamer-custom-camera PUBLIC
+ Qt::Widgets
+ Qt::Multimedia
+ Qt::MultimediaPrivate
+ Qt::MultimediaWidgets
+)
+
+install(TARGETS gstreamer-custom-camera
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+set_target_properties( gstreamer-custom-camera PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+)
diff --git a/tests/manual/gstreamer-custom-camera/Info.plist.in b/tests/manual/gstreamer-custom-camera/Info.plist.in
new file mode 100644
index 000000000..46a9ecf2d
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera/Info.plist.in
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSCameraUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Qt Multimedia Example</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp b/tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp
new file mode 100644
index 000000000..dbd729d15
--- /dev/null
+++ b/tests/manual/gstreamer-custom-camera/gstreamer-custom-camera.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtMultimedia/QAudioOutput>
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+#include <QtMultimediaWidgets/QtMultimediaWidgets>
+#include <QtWidgets/QApplication>
+#include <QtCore/QCommandLineParser>
+
+using namespace std::chrono_literals;
+using namespace Qt::Literals;
+
+int main(int argc, char **argv)
+{
+ qputenv("QT_MEDIA_BACKEND", "gstreamer");
+
+ QApplication app(argc, argv);
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("GStreamer Custom Camera");
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addPositionalArgument(
+ "pipeline", "Pipeline string, e.g. `videotestsrc pattern=smpte-rp-219 is-live=true`");
+
+ parser.process(app);
+
+ QByteArray pipelineString;
+
+ if (parser.positionalArguments().isEmpty()) {
+ // pipelineString = "videotestsrc pattern=smpte-rp-219 is-live=true";
+ pipelineString = "videotestsrc is-live=true ! gamma gamma=2.0";
+ } else {
+ pipelineString = parser.positionalArguments()[0].toLatin1();
+ }
+
+ QVideoWidget wid;
+
+ QMediaCaptureSession session;
+ session.setVideoSink(wid.videoSink());
+
+ QCamera *cam = QGStreamerPlatformSpecificInterface::instance()->makeCustomGStreamerCamera(
+ pipelineString, &session);
+ session.setCamera(cam);
+ cam->start();
+
+ wid.show();
+
+ return QApplication::exec();
+}