summaryrefslogtreecommitdiffstats
path: root/src/multimedia
diff options
context:
space:
mode:
Diffstat (limited to 'src/multimedia')
-rw-r--r--src/multimedia/.prev_CMakeLists.txt571
-rw-r--r--src/multimedia/CMakeLists.txt542
-rw-r--r--src/multimedia/alsa/alsa.json3
-rw-r--r--src/multimedia/alsa/qalsaaudiodevice.cpp (renamed from src/multimedia/platform/alsa/qalsaaudiodevice.cpp)44
-rw-r--r--src/multimedia/alsa/qalsaaudiodevice_p.h49
-rw-r--r--src/multimedia/alsa/qalsaaudiosink.cpp (renamed from src/multimedia/platform/alsa/qalsaaudiosink.cpp)100
-rw-r--r--src/multimedia/alsa/qalsaaudiosink_p.h122
-rw-r--r--src/multimedia/alsa/qalsaaudiosource.cpp (renamed from src/multimedia/platform/alsa/qalsaaudiosource.cpp)51
-rw-r--r--src/multimedia/alsa/qalsaaudiosource_p.h (renamed from src/multimedia/platform/alsa/qalsaaudiosource_p.h)46
-rw-r--r--src/multimedia/alsa/qalsamediadevices.cpp108
-rw-r--r--src/multimedia/alsa/qalsamediadevices_p.h41
-rw-r--r--src/multimedia/android/qandroidaudiodevice.cpp39
-rw-r--r--src/multimedia/android/qandroidaudiodevice_p.h37
-rw-r--r--src/multimedia/android/qandroidaudiosink.cpp (renamed from src/multimedia/platform/android/audio/qandroidaudiosink.cpp)146
-rw-r--r--src/multimedia/android/qandroidaudiosink_p.h127
-rw-r--r--src/multimedia/android/qandroidaudiosource.cpp (renamed from src/multimedia/platform/android/audio/qandroidaudiosource.cpp)75
-rw-r--r--src/multimedia/android/qandroidaudiosource_p.h (renamed from src/multimedia/platform/android/audio/qandroidaudiosource_p.h)44
-rw-r--r--src/multimedia/android/qandroidmediadevices.cpp117
-rw-r--r--src/multimedia/android/qandroidmediadevices_p.h42
-rw-r--r--src/multimedia/android/qopenslesengine.cpp (renamed from src/multimedia/platform/android/audio/qopenslesengine.cpp)112
-rw-r--r--src/multimedia/android/qopenslesengine_p.h65
-rw-r--r--src/multimedia/audio/qaudio.h60
-rw-r--r--src/multimedia/audio/qaudiobuffer.cpp125
-rw-r--r--src/multimedia/audio/qaudiobuffer.h46
-rw-r--r--src/multimedia/audio/qaudiodecoder.cpp174
-rw-r--r--src/multimedia/audio/qaudiodecoder.h48
-rw-r--r--src/multimedia/audio/qaudiodecoder_p.h40
-rw-r--r--src/multimedia/audio/qaudiodevice.cpp185
-rw-r--r--src/multimedia/audio/qaudiodevice.h45
-rw-r--r--src/multimedia/audio/qaudiodevice_p.h58
-rw-r--r--src/multimedia/audio/qaudioformat.cpp147
-rw-r--r--src/multimedia/audio/qaudioformat.h55
-rw-r--r--src/multimedia/audio/qaudiohelpers.cpp42
-rw-r--r--src/multimedia/audio/qaudiohelpers_p.h43
-rw-r--r--src/multimedia/audio/qaudioinput.cpp223
-rw-r--r--src/multimedia/audio/qaudioinput.h49
-rw-r--r--src/multimedia/audio/qaudiooutput.cpp238
-rw-r--r--src/multimedia/audio/qaudiooutput.h50
-rw-r--r--src/multimedia/audio/qaudiosink.cpp148
-rw-r--r--src/multimedia/audio/qaudiosink.h51
-rw-r--r--src/multimedia/audio/qaudiosource.cpp138
-rw-r--r--src/multimedia/audio/qaudiosource.h51
-rw-r--r--src/multimedia/audio/qaudiostatemachine.cpp150
-rw-r--r--src/multimedia/audio/qaudiostatemachine_p.h149
-rw-r--r--src/multimedia/audio/qaudiostatemachineutils_p.h96
-rw-r--r--src/multimedia/audio/qaudiosystem.cpp254
-rw-r--r--src/multimedia/audio/qaudiosystem_p.h68
-rw-r--r--src/multimedia/audio/qsamplecache_p.cpp83
-rw-r--r--src/multimedia/audio/qsamplecache_p.h44
-rw-r--r--src/multimedia/audio/qsoundeffect.cpp213
-rw-r--r--src/multimedia/audio/qsoundeffect.h40
-rw-r--r--src/multimedia/audio/qtaudio.cpp (renamed from src/multimedia/audio/qaudio.cpp)68
-rw-r--r--src/multimedia/audio/qtaudio.h18
-rw-r--r--src/multimedia/audio/qwavedecoder.cpp124
-rw-r--r--src/multimedia/audio/qwavedecoder.h47
-rw-r--r--src/multimedia/camera/qcamera.cpp693
-rw-r--r--src/multimedia/camera/qcamera.h75
-rw-r--r--src/multimedia/camera/qcamera_p.h53
-rw-r--r--src/multimedia/camera/qcameradevice.cpp319
-rw-r--r--src/multimedia/camera/qcameradevice.h49
-rw-r--r--src/multimedia/camera/qcameradevice_p.h67
-rw-r--r--src/multimedia/camera/qimagecapture.cpp169
-rw-r--r--src/multimedia/camera/qimagecapture.h41
-rw-r--r--src/multimedia/compat/removed_api.cpp16
-rw-r--r--src/multimedia/configure.cmake131
-rw-r--r--src/multimedia/darwin/qcoreaudiosessionmanager.mm (renamed from src/multimedia/platform/darwin/audio/qcoreaudiosessionmanager.mm)40
-rw-r--r--src/multimedia/darwin/qcoreaudiosessionmanager_p.h (renamed from src/multimedia/platform/darwin/audio/qcoreaudiosessionmanager_p.h)40
-rw-r--r--src/multimedia/darwin/qcoreaudioutils.mm344
-rw-r--r--src/multimedia/darwin/qcoreaudioutils_p.h72
-rw-r--r--src/multimedia/darwin/qdarwinaudiodevice.mm108
-rw-r--r--src/multimedia/darwin/qdarwinaudiodevice_p.h52
-rw-r--r--src/multimedia/darwin/qdarwinaudiosink.mm (renamed from src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm)352
-rw-r--r--src/multimedia/darwin/qdarwinaudiosink_p.h (renamed from src/multimedia/platform/darwin/audio/qdarwinaudiosink_p.h)106
-rw-r--r--src/multimedia/darwin/qdarwinaudiosource.mm (renamed from src/multimedia/platform/darwin/audio/qdarwinaudiosource.mm)67
-rw-r--r--src/multimedia/darwin/qdarwinaudiosource_p.h (renamed from src/multimedia/platform/darwin/audio/qdarwinaudiosource_p.h)48
-rw-r--r--src/multimedia/darwin/qdarwinmediadevices.mm269
-rw-r--r--src/multimedia/darwin/qdarwinmediadevices_p.h49
-rw-r--r--src/multimedia/darwin/qmacosaudiodatautils_p.h112
-rw-r--r--src/multimedia/doc/QtMultimediaDoc7
-rw-r--r--src/multimedia/doc/qtmultimedia.qdocconf35
-rw-r--r--src/multimedia/doc/snippets/CMakeLists.txt7
-rw-r--r--src/multimedia/doc/snippets/doc_src_qtmultimedia.cpp53
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/audio.cpp76
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/camera.cpp63
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/devices.cpp38
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/media.cpp53
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml41
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp51
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml40
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml40
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/video.cpp50
-rw-r--r--src/multimedia/doc/src/audiooverview.qdoc106
-rw-r--r--src/multimedia/doc/src/cameraoverview.qdoc69
-rw-r--r--src/multimedia/doc/src/examples/video-qml-paint-rate.qdocinc6
-rw-r--r--src/multimedia/doc/src/images/camera_correctionAngle_90.pngbin0 -> 48562 bytes
-rw-r--r--src/multimedia/doc/src/multimedia-overview.qdoc126
-rw-r--r--src/multimedia/doc/src/platform-notes-apple.qdoc40
-rw-r--r--src/multimedia/doc/src/platform-notes-wasm.qdoc35
-rw-r--r--src/multimedia/doc/src/qm-external-pages.qdoc68
-rw-r--r--src/multimedia/doc/src/qt6-changes.qdoc47
-rw-r--r--src/multimedia/doc/src/qtmultimedia-building-from-source.qdoc94
-rw-r--r--src/multimedia/doc/src/qtmultimedia-cpp.qdoc41
-rw-r--r--src/multimedia/doc/src/qtmultimedia-examples.qdoc38
-rw-r--r--src/multimedia/doc/src/qtmultimedia-index.qdoc302
-rw-r--r--src/multimedia/doc/src/qtmultimedia-qml-types.qdoc47
-rw-r--r--src/multimedia/doc/src/videooverview.qdoc90
-rw-r--r--src/multimedia/platform/alsa/qalsaaudiodevice_p.h85
-rw-r--r--src/multimedia/platform/alsa/qalsaaudiosink_p.h157
-rw-r--r--src/multimedia/platform/alsa/qalsaintegration.cpp61
-rw-r--r--src/multimedia/platform/alsa/qalsaintegration_p.h73
-rw-r--r--src/multimedia/platform/alsa/qalsamediadevices.cpp128
-rw-r--r--src/multimedia/platform/alsa/qalsamediadevices_p.h76
-rw-r--r--src/multimedia/platform/android/audio/qandroidaudiodecoder.cpp436
-rw-r--r--src/multimedia/platform/android/audio/qandroidaudiodecoder_p.h151
-rw-r--r--src/multimedia/platform/android/audio/qandroidaudiodevice.cpp75
-rw-r--r--src/multimedia/platform/android/audio/qandroidaudiodevice_p.h73
-rw-r--r--src/multimedia/platform/android/audio/qandroidaudiosink_p.h158
-rw-r--r--src/multimedia/platform/android/audio/qopenslesengine_p.h100
-rw-r--r--src/multimedia/platform/android/common/qandroidaudiooutput_p.h66
-rw-r--r--src/multimedia/platform/android/common/qandroidglobal_p.h64
-rw-r--r--src/multimedia/platform/android/common/qandroidmultimediautils.cpp176
-rw-r--r--src/multimedia/platform/android/common/qandroidmultimediautils_p.h78
-rw-r--r--src/multimedia/platform/android/common/qandroidvideooutput.cpp465
-rw-r--r--src/multimedia/platform/android/common/qandroidvideooutput_p.h213
-rw-r--r--src/multimedia/platform/android/common/qandroidvideosink.cpp70
-rw-r--r--src/multimedia/platform/android/common/qandroidvideosink_p.h77
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidcamera.cpp590
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidcamera_p.h133
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp794
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidcamerasession_p.h196
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidcapturesession.cpp472
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidcapturesession_p.h188
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidimagecapture.cpp113
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidimagecapture_p.h84
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidmediacapturesession.cpp152
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidmediacapturesession_p.h102
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidmediaencoder.cpp108
-rw-r--r--src/multimedia/platform/android/mediacapture/qandroidmediaencoder_p.h86
-rw-r--r--src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp983
-rw-r--r--src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h164
-rw-r--r--src/multimedia/platform/android/mediaplayer/qandroidmetadata.cpp202
-rw-r--r--src/multimedia/platform/android/mediaplayer/qandroidmetadata_p.h83
-rw-r--r--src/multimedia/platform/android/qandroidformatsinfo.cpp106
-rw-r--r--src/multimedia/platform/android/qandroidformatsinfo_p.h67
-rw-r--r--src/multimedia/platform/android/qandroidintegration.cpp161
-rw-r--r--src/multimedia/platform/android/qandroidintegration_p.h86
-rw-r--r--src/multimedia/platform/android/qandroidmediadevices.cpp116
-rw-r--r--src/multimedia/platform/android/qandroidmediadevices_p.h77
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidcamera.cpp1747
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidcamera_p.h242
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever.cpp171
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever_p.h102
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmediaplayer.cpp581
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmediaplayer_p.h169
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmediarecorder.cpp344
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmediarecorder_p.h196
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmultimediautils.cpp79
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidmultimediautils_p.h76
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidsurfacetexture.cpp183
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidsurfacetexture_p.h95
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidsurfaceview.cpp186
-rw-r--r--src/multimedia/platform/android/wrappers/jni/androidsurfaceview_p.h113
-rw-r--r--src/multimedia/platform/darwin/audio/avfaudiodecoder.mm529
-rw-r--r--src/multimedia/platform/darwin/audio/avfaudiodecoder_p.h130
-rw-r--r--src/multimedia/platform/darwin/audio/qcoreaudioutils.mm219
-rw-r--r--src/multimedia/platform/darwin/audio/qcoreaudioutils_p.h104
-rw-r--r--src/multimedia/platform/darwin/audio/qdarwinaudiodevice.mm153
-rw-r--r--src/multimedia/platform/darwin/audio/qdarwinaudiodevice_p.h87
-rw-r--r--src/multimedia/platform/darwin/avfvideobuffer.mm315
-rw-r--r--src/multimedia/platform/darwin/avfvideobuffer_p.h112
-rw-r--r--src/multimedia/platform/darwin/avfvideosink.mm212
-rw-r--r--src/multimedia/platform/darwin/avfvideosink_p.h129
-rw-r--r--src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate.mm134
-rw-r--r--src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate_p.h76
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamera.mm1004
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamera_p.h139
-rw-r--r--src/multimedia/platform/darwin/camera/avfcameradebug_p.h68
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerarenderer.mm298
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h129
-rw-r--r--src/multimedia/platform/darwin/camera/avfcameraservice.mm201
-rw-r--r--src/multimedia/platform/darwin/camera/avfcameraservice_p.h120
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerasession.mm521
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerasession_p.h162
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerautility.mm714
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerautility_p.h201
-rw-r--r--src/multimedia/platform/darwin/camera/avfimagecapture.mm416
-rw-r--r--src/multimedia/platform/darwin/camera/avfimagecapture_p.h117
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm579
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaassetwriter_p.h90
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaencoder.mm649
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaencoder_p.h131
-rw-r--r--src/multimedia/platform/darwin/common/avfmetadata.mm398
-rw-r--r--src/multimedia/platform/darwin/common/avfmetadata_p.h73
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfdisplaylink.mm241
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfdisplaylink_p.h101
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm1161
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h180
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm272
-rw-r--r--src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h103
-rw-r--r--src/multimedia/platform/darwin/qdarwinformatsinfo.mm246
-rw-r--r--src/multimedia/platform/darwin/qdarwinformatsinfo_p.h74
-rw-r--r--src/multimedia/platform/darwin/qdarwinintegration.mm113
-rw-r--r--src/multimedia/platform/darwin/qdarwinintegration_p.h84
-rw-r--r--src/multimedia/platform/darwin/qdarwinmediadevices.mm348
-rw-r--r--src/multimedia/platform/darwin/qdarwinmediadevices_p.h94
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp558
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder_p.h144
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice.cpp92
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice_p.h78
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiosink.cpp395
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiosink_p.h157
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiosource.cpp407
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiosource_p.h159
-rw-r--r--src/multimedia/platform/gstreamer/common/qgst_p.h620
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstappsrc.cpp308
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstappsrc_p.h132
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstpipeline.cpp375
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstpipeline_p.h139
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreameraudioinput.cpp135
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreameraudioinput_p.h107
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreameraudiooutput.cpp120
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreameraudiooutput_p.h104
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe.cpp119
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe_p.h92
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp864
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h187
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermessage.cpp90
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermessage_p.h86
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermetadata.cpp305
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermetadata_p.h73
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp180
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h106
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp253
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideooverlay_p.h110
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp261
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h116
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstsubtitlesink.cpp192
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstsubtitlesink_p.h106
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstutils.cpp423
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstutils_p.h85
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp373
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h103
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp601
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h171
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera.cpp738
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera_p.h138
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture.cpp301
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture_p.h121
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp370
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h129
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder.cpp439
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder_p.h125
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamerformatinfo.cpp459
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamerformatinfo_p.h81
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamerintegration.cpp123
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamerintegration_p.h90
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamermediadevices.cpp265
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamermediadevices_p.h86
-rw-r--r--src/multimedia/platform/pulseaudio/qaudioengine_pulse.cpp479
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiodevice.cpp87
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiodevice_p.h75
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiointegration.cpp68
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiointegration_p.h76
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiomediadevices.cpp82
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiomediadevices_p.h79
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiosink.cpp709
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiosink_p.h155
-rw-r--r--src/multimedia/platform/pulseaudio/qpulseaudiosource.cpp645
-rw-r--r--src/multimedia/platform/pulseaudio/qpulsehelpers.cpp126
-rw-r--r--src/multimedia/platform/pulseaudio/qpulsehelpers_p.h70
-rw-r--r--src/multimedia/platform/qnx/audio/qnxaudioutils.cpp128
-rw-r--r--src/multimedia/platform/qnx/audio/qnxaudioutils_p.h66
-rw-r--r--src/multimedia/platform/qnx/audio/qqnxaudiodevice.cpp122
-rw-r--r--src/multimedia/platform/qnx/audio/qqnxaudiodevice_p.h77
-rw-r--r--src/multimedia/platform/qnx/audio/qqnxaudiosink_p.h150
-rw-r--r--src/multimedia/platform/qnx/audio/qqnxaudiosource_p.h142
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol.cpp87
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol_p.h77
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameracontrol.cpp97
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameracontrol_p.h96
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraexposurecontrol.cpp288
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraexposurecontrol_p.h89
-rw-r--r--src/multimedia/platform/qnx/camera/bbcamerafocuscontrol.cpp300
-rw-r--r--src/multimedia/platform/qnx/camera/bbcamerafocuscontrol_p.h99
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol.cpp89
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol_p.h80
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol.cpp118
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol_p.h75
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol.cpp149
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol_p.h84
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraorientationhandler.cpp113
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraorientationhandler_p.h80
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraservice.cpp96
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameraservice_p.h100
-rw-r--r--src/multimedia/platform/qnx/camera/bbcamerasession.cpp1049
-rw-r--r--src/multimedia/platform/qnx/camera/bbcamerasession_p.h202
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol.cpp88
-rw-r--r--src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol_p.h78
-rw-r--r--src/multimedia/platform/qnx/common/windowgrabber.cpp419
-rw-r--r--src/multimedia/platform/qnx/common/windowgrabber_p.h155
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp630
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol_p.h183
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata.cpp298
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata_p.h110
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp192
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol_p.h95
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrendererutil.cpp165
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrendererutil_p.h68
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp378
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol_p.h118
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol.cpp229
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol_p.h95
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmreventthread.cpp121
-rw-r--r--src/multimedia/platform/qnx/mediaplayer/mmreventthread_p.h90
-rw-r--r--src/multimedia/platform/qnx/qqnxdevicemanager.cpp122
-rw-r--r--src/multimedia/platform/qnx/qqnxdevicemanager_p.h73
-rw-r--r--src/multimedia/platform/qnx/qqnxintegration.cpp69
-rw-r--r--src/multimedia/platform/qnx/qqnxintegration_p.h76
-rw-r--r--src/multimedia/platform/qplatformaudiodecoder.cpp201
-rw-r--r--src/multimedia/platform/qplatformaudiodecoder_p.h59
-rw-r--r--src/multimedia/platform/qplatformaudioinput_p.h49
-rw-r--r--src/multimedia/platform/qplatformaudiooutput_p.h45
-rw-r--r--src/multimedia/platform/qplatformaudioresampler_p.h33
-rw-r--r--src/multimedia/platform/qplatformcamera.cpp116
-rw-r--r--src/multimedia/platform/qplatformcamera_p.h73
-rw-r--r--src/multimedia/platform/qplatformcapturablewindows_p.h44
-rw-r--r--src/multimedia/platform/qplatformimagecapture.cpp164
-rw-r--r--src/multimedia/platform/qplatformimagecapture_p.h41
-rw-r--r--src/multimedia/platform/qplatformmediacapture.cpp59
-rw-r--r--src/multimedia/platform/qplatformmediacapture_p.h68
-rw-r--r--src/multimedia/platform/qplatformmediadevices.cpp151
-rw-r--r--src/multimedia/platform/qplatformmediadevices_p.h101
-rw-r--r--src/multimedia/platform/qplatformmediaencoder.cpp195
-rw-r--r--src/multimedia/platform/qplatformmediaformatinfo.cpp40
-rw-r--r--src/multimedia/platform/qplatformmediaformatinfo_p.h40
-rw-r--r--src/multimedia/platform/qplatformmediaintegration.cpp313
-rw-r--r--src/multimedia/platform/qplatformmediaintegration_p.h127
-rw-r--r--src/multimedia/platform/qplatformmediaplayer.cpp354
-rw-r--r--src/multimedia/platform/qplatformmediaplayer_p.h94
-rw-r--r--src/multimedia/platform/qplatformmediaplugin.cpp14
-rw-r--r--src/multimedia/platform/qplatformmediaplugin_p.h42
-rw-r--r--src/multimedia/platform/qplatformmediarecorder.cpp75
-rw-r--r--src/multimedia/platform/qplatformmediarecorder_p.h (renamed from src/multimedia/platform/qplatformmediaencoder_p.h)72
-rw-r--r--src/multimedia/platform/qplatformsurfacecapture.cpp83
-rw-r--r--src/multimedia/platform/qplatformsurfacecapture_p.h88
-rw-r--r--src/multimedia/platform/qplatformvideodevices.cpp12
-rw-r--r--src/multimedia/platform/qplatformvideodevices_p.h46
-rw-r--r--src/multimedia/platform/qplatformvideosink.cpp142
-rw-r--r--src/multimedia/platform/qplatformvideosink_p.h99
-rw-r--r--src/multimedia/platform/qplatformvideosource.cpp15
-rw-r--r--src/multimedia/platform/qplatformvideosource_p.h53
-rw-r--r--src/multimedia/platform/wasm/audio/qwasmaudiodevice.cpp83
-rw-r--r--src/multimedia/platform/wasm/audio/qwasmaudiodevice_p.h67
-rw-r--r--src/multimedia/platform/wasm/audio/qwasmaudiosink_p.h124
-rw-r--r--src/multimedia/platform/wasm/audio/qwasmaudiosource_p.h111
-rw-r--r--src/multimedia/platform/wasm/qwasmmediadevices.cpp92
-rw-r--r--src/multimedia/platform/wasm/qwasmmediadevices_p.h81
-rw-r--r--src/multimedia/platform/wasm/qwasmmediaintegration.cpp75
-rw-r--r--src/multimedia/platform/wasm/qwasmmediaintegration_p.h76
-rw-r--r--src/multimedia/platform/windows/audio/qwindowsaudiodevice_p.h91
-rw-r--r--src/multimedia/platform/windows/audio/qwindowsaudiosink.cpp608
-rw-r--r--src/multimedia/platform/windows/audio/qwindowsaudiosink_p.h160
-rw-r--r--src/multimedia/platform/windows/audio/qwindowsaudiosource.cpp698
-rw-r--r--src/multimedia/platform/windows/audio/qwindowsaudiosource_p.h170
-rw-r--r--src/multimedia/platform/windows/audio/qwindowsaudioutils.cpp114
-rw-r--r--src/multimedia/platform/windows/audio/qwindowsaudioutils_p.h153
-rw-r--r--src/multimedia/platform/windows/common/mfmetadata.cpp521
-rw-r--r--src/multimedia/platform/windows/common/mfmetadata_p.h66
-rw-r--r--src/multimedia/platform/windows/common/qwindowsiupointer_p.h90
-rw-r--r--src/multimedia/platform/windows/common/qwindowsmultimediautils_p.h80
-rw-r--r--src/multimedia/platform/windows/decoder/mfaudiodecodercontrol.cpp454
-rw-r--r--src/multimedia/platform/windows/decoder/mfaudiodecodercontrol_p.h117
-rw-r--r--src/multimedia/platform/windows/decoder/mfdecodersourcereader.cpp197
-rw-r--r--src/multimedia/platform/windows/decoder/mfdecodersourcereader_p.h101
-rw-r--r--src/multimedia/platform/windows/evr/evrcustompresenter.cpp2005
-rw-r--r--src/multimedia/platform/windows/evr/evrcustompresenter_p.h387
-rw-r--r--src/multimedia/platform/windows/evr/evrd3dpresentengine.cpp393
-rw-r--r--src/multimedia/platform/windows/evr/evrd3dpresentengine_p.h165
-rw-r--r--src/multimedia/platform/windows/evr/evrdefs.cpp48
-rw-r--r--src/multimedia/platform/windows/evr/evrdefs_p.h364
-rw-r--r--src/multimedia/platform/windows/evr/evrhelpers.cpp174
-rw-r--r--src/multimedia/platform/windows/evr/evrhelpers_p.h112
-rw-r--r--src/multimedia/platform/windows/evr/evrvideowindowcontrol.cpp269
-rw-r--r--src/multimedia/platform/windows/evr/evrvideowindowcontrol_p.h107
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowscamera.cpp135
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowscamera_p.h91
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsimagecapture.cpp225
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsimagecapture_p.h100
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediacapture.cpp143
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediacapture_p.h98
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader.cpp1054
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader_p.h189
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp399
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession_p.h136
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder.cpp253
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder_p.h106
-rw-r--r--src/multimedia/platform/windows/mfstream.cpp361
-rw-r--r--src/multimedia/platform/windows/mfstream_p.h159
-rw-r--r--src/multimedia/platform/windows/player/mfactivate.cpp87
-rw-r--r--src/multimedia/platform/windows/player/mfactivate_p.h223
-rw-r--r--src/multimedia/platform/windows/player/mfevrvideowindowcontrol.cpp91
-rw-r--r--src/multimedia/platform/windows/player/mfevrvideowindowcontrol_p.h74
-rw-r--r--src/multimedia/platform/windows/player/mfplayercontrol.cpp328
-rw-r--r--src/multimedia/platform/windows/player/mfplayercontrol_p.h139
-rw-r--r--src/multimedia/platform/windows/player/mfplayersession.cpp2009
-rw-r--r--src/multimedia/platform/windows/player/mfplayersession_p.h275
-rw-r--r--src/multimedia/platform/windows/player/mftvideo.cpp725
-rw-r--r--src/multimedia/platform/windows/player/mftvideo_p.h131
-rw-r--r--src/multimedia/platform/windows/player/mfvideorenderercontrol.cpp2318
-rw-r--r--src/multimedia/platform/windows/player/mfvideorenderercontrol_p.h95
-rw-r--r--src/multimedia/platform/windows/player/samplegrabber.cpp172
-rw-r--r--src/multimedia/platform/windows/player/samplegrabber_p.h103
-rw-r--r--src/multimedia/platform/windows/qwindowsformatinfo.cpp104
-rw-r--r--src/multimedia/platform/windows/qwindowsformatinfo_p.h69
-rw-r--r--src/multimedia/platform/windows/qwindowsintegration.cpp126
-rw-r--r--src/multimedia/platform/windows/qwindowsintegration_p.h89
-rw-r--r--src/multimedia/platform/windows/qwindowsmediadevices.cpp532
-rw-r--r--src/multimedia/platform/windows/qwindowsmediadevices_p.h96
-rw-r--r--src/multimedia/platform/windows/sourceresolver.cpp325
-rw-r--r--src/multimedia/platform/windows/sourceresolver_p.h115
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp766
-rw-r--r--src/multimedia/playback/qmediaplayer.h61
-rw-r--r--src/multimedia/playback/qmediaplayer_p.h61
-rw-r--r--src/multimedia/pulseaudio/pulseaudio.json3
-rw-r--r--src/multimedia/pulseaudio/qaudioengine_pulse.cpp508
-rw-r--r--src/multimedia/pulseaudio/qaudioengine_pulse_p.h (renamed from src/multimedia/platform/pulseaudio/qaudioengine_pulse_p.h)42
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiodevice.cpp46
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiodevice_p.h41
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiomediadevices.cpp55
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiomediadevices_p.h45
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiosink.cpp749
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiosink_p.h136
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiosource.cpp566
-rw-r--r--src/multimedia/pulseaudio/qpulseaudiosource_p.h (renamed from src/multimedia/platform/pulseaudio/qpulseaudiosource_p.h)60
-rw-r--r--src/multimedia/pulseaudio/qpulsehelpers.cpp284
-rw-r--r--src/multimedia/pulseaudio/qpulsehelpers_p.h55
-rw-r--r--src/multimedia/qerrorinfo_p.h57
-rw-r--r--src/multimedia/qmaybe_p.h96
-rw-r--r--src/multimedia/qmediadevices.cpp222
-rw-r--r--src/multimedia/qmediadevices.h43
-rw-r--r--src/multimedia/qmediaenumdebug.h40
-rw-r--r--src/multimedia/qmediaformat.cpp378
-rw-r--r--src/multimedia/qmediaformat.h60
-rw-r--r--src/multimedia/qmediametadata.cpp183
-rw-r--r--src/multimedia/qmediametadata.h48
-rw-r--r--src/multimedia/qmediastoragelocation.cpp66
-rw-r--r--src/multimedia/qmediastoragelocation_p.h45
-rw-r--r--src/multimedia/qmediatimerange.cpp60
-rw-r--r--src/multimedia/qmediatimerange.h42
-rw-r--r--src/multimedia/qmultimediautils.cpp135
-rw-r--r--src/multimedia/qmultimediautils_p.h80
-rw-r--r--src/multimedia/qnx/qqnxaudiodevice.cpp85
-rw-r--r--src/multimedia/qnx/qqnxaudiodevice_p.h35
-rw-r--r--src/multimedia/qnx/qqnxaudiosink.cpp (renamed from src/multimedia/platform/qnx/audio/qqnxaudiosink.cpp)377
-rw-r--r--src/multimedia/qnx/qqnxaudiosink_p.h119
-rw-r--r--src/multimedia/qnx/qqnxaudiosource.cpp (renamed from src/multimedia/platform/qnx/audio/qqnxaudiosource.cpp)199
-rw-r--r--src/multimedia/qnx/qqnxaudiosource_p.h113
-rw-r--r--src/multimedia/qnx/qqnxaudioutils.cpp148
-rw-r--r--src/multimedia/qnx/qqnxaudioutils_p.h51
-rw-r--r--src/multimedia/qnx/qqnxmediadevices.cpp70
-rw-r--r--src/multimedia/qnx/qqnxmediadevices_p.h39
-rw-r--r--src/multimedia/qt_cmdline.cmake3
-rw-r--r--src/multimedia/qtmultimediaglobal.h56
-rw-r--r--src/multimedia/qtmultimediaglobal_p.h40
-rw-r--r--src/multimedia/recording/qcapturablewindow.cpp156
-rw-r--r--src/multimedia/recording/qcapturablewindow.h66
-rw-r--r--src/multimedia/recording/qcapturablewindow_p.h41
-rw-r--r--src/multimedia/recording/qmediacapturesession.cpp336
-rw-r--r--src/multimedia/recording/qmediacapturesession.h58
-rw-r--r--src/multimedia/recording/qmediarecorder.cpp328
-rw-r--r--src/multimedia/recording/qmediarecorder.h54
-rw-r--r--src/multimedia/recording/qmediarecorder_p.h49
-rw-r--r--src/multimedia/recording/qscreencapture-limitations.qdocinc22
-rw-r--r--src/multimedia/recording/qscreencapture.cpp261
-rw-r--r--src/multimedia/recording/qscreencapture.h72
-rw-r--r--src/multimedia/recording/qwindowcapture.cpp268
-rw-r--r--src/multimedia/recording/qwindowcapture.h71
-rw-r--r--src/multimedia/shaders/abgr.frag15
-rw-r--r--src/multimedia/shaders/argb.frag15
-rw-r--r--src/multimedia/shaders/ayuv.frag19
-rw-r--r--src/multimedia/shaders/bgra.frag15
-rw-r--r--src/multimedia/shaders/colorconvert.glsl19
-rw-r--r--src/multimedia/shaders/colortransfer.glsl118
-rwxr-xr-xsrc/multimedia/shaders/compile.bat39
-rw-r--r--src/multimedia/shaders/externalsampler.frag10
-rw-r--r--src/multimedia/shaders/externalsampler.vert10
-rw-r--r--src/multimedia/shaders/externalsampler_gles.frag6
-rw-r--r--src/multimedia/shaders/hdrtonemapper.glsl38
-rw-r--r--src/multimedia/shaders/imc2.frag23
-rw-r--r--src/multimedia/shaders/imc4.frag19
-rw-r--r--src/multimedia/shaders/nv12.frag19
-rw-r--r--src/multimedia/shaders/nv12_bt2020_hlg.frag42
-rw-r--r--src/multimedia/shaders/nv12_bt2020_pq.frag48
-rw-r--r--src/multimedia/shaders/nv21.frag19
-rw-r--r--src/multimedia/shaders/rectsampler.vert10
-rw-r--r--src/multimedia/shaders/rectsampler_bgra.frag17
-rw-r--r--src/multimedia/shaders/rgba.frag15
-rw-r--r--src/multimedia/shaders/uniformbuffer.glsl11
-rw-r--r--src/multimedia/shaders/uyvy.frag19
-rw-r--r--src/multimedia/shaders/vertex.vert10
-rw-r--r--src/multimedia/shaders/y.frag19
-rw-r--r--src/multimedia/shaders/yuv_triplanar.frag19
-rw-r--r--src/multimedia/shaders/yuv_triplanar_p10.frag29
-rw-r--r--src/multimedia/shaders/yuyv.frag19
-rw-r--r--src/multimedia/shaders/yvu_triplanar.frag19
-rw-r--r--src/multimedia/video/qabstractvideobuffer.cpp51
-rw-r--r--src/multimedia/video/qabstractvideobuffer_p.h62
-rw-r--r--src/multimedia/video/qimagevideobuffer.cpp90
-rw-r--r--src/multimedia/video/qimagevideobuffer_p.h43
-rw-r--r--src/multimedia/video/qmemoryvideobuffer.cpp69
-rw-r--r--src/multimedia/video/qmemoryvideobuffer_p.h49
-rw-r--r--src/multimedia/video/qtvideo.cpp30
-rw-r--r--src/multimedia/video/qtvideo.h23
-rw-r--r--src/multimedia/video/qvideoframe.cpp386
-rw-r--r--src/multimedia/video/qvideoframe.h71
-rw-r--r--src/multimedia/video/qvideoframe_p.h63
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper.cpp179
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_avx2.cpp87
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_p.h107
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_sse2.cpp90
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp50
-rw-r--r--src/multimedia/video/qvideoframeconverter.cpp458
-rw-r--r--src/multimedia/video/qvideoframeconverter_p.h34
-rw-r--r--src/multimedia/video/qvideoframeformat.cpp442
-rw-r--r--src/multimedia/video/qvideoframeformat.h112
-rw-r--r--src/multimedia/video/qvideooutputorientationhandler.cpp46
-rw-r--r--src/multimedia/video/qvideooutputorientationhandler_p.h41
-rw-r--r--src/multimedia/video/qvideosink.cpp78
-rw-r--r--src/multimedia/video/qvideosink.h47
-rw-r--r--src/multimedia/video/qvideotexturehelper.cpp611
-rw-r--r--src/multimedia/video/qvideotexturehelper_p.h66
-rw-r--r--src/multimedia/video/qvideowindow.cpp224
-rw-r--r--src/multimedia/video/qvideowindow_p.h71
-rw-r--r--src/multimedia/wasm/qwasmaudiodevice.cpp56
-rw-r--r--src/multimedia/wasm/qwasmaudiodevice_p.h31
-rw-r--r--src/multimedia/wasm/qwasmaudiosink.cpp (renamed from src/multimedia/platform/wasm/audio/qwasmaudiosink.cpp)83
-rw-r--r--src/multimedia/wasm/qwasmaudiosink_p.h89
-rw-r--r--src/multimedia/wasm/qwasmaudiosource.cpp (renamed from src/multimedia/platform/wasm/audio/qwasmaudiosource.cpp)76
-rw-r--r--src/multimedia/wasm/qwasmaudiosource_p.h75
-rw-r--r--src/multimedia/wasm/qwasmmediadevices.cpp276
-rw-r--r--src/multimedia/wasm/qwasmmediadevices_p.h89
-rw-r--r--src/multimedia/windows/qcomptr_p.h33
-rw-r--r--src/multimedia/windows/qcomtaskresource_p.h152
-rw-r--r--src/multimedia/windows/qwindowsaudiodevice.cpp (renamed from src/multimedia/platform/windows/audio/qwindowsaudiodevice.cpp)99
-rw-r--r--src/multimedia/windows/qwindowsaudiodevice_p.h60
-rw-r--r--src/multimedia/windows/qwindowsaudiosink.cpp388
-rw-r--r--src/multimedia/windows/qwindowsaudiosink_p.h97
-rw-r--r--src/multimedia/windows/qwindowsaudiosource.cpp406
-rw-r--r--src/multimedia/windows/qwindowsaudiosource_p.h96
-rw-r--r--src/multimedia/windows/qwindowsaudioutils.cpp208
-rw-r--r--src/multimedia/windows/qwindowsaudioutils_p.h45
-rw-r--r--src/multimedia/windows/qwindowsmediadevices.cpp345
-rw-r--r--src/multimedia/windows/qwindowsmediadevices_p.h65
-rw-r--r--src/multimedia/windows/qwindowsmediafoundation.cpp70
-rw-r--r--src/multimedia/windows/qwindowsmediafoundation_p.h59
-rw-r--r--src/multimedia/windows/qwindowsmfdefs.cpp26
-rw-r--r--src/multimedia/windows/qwindowsmfdefs_p.h94
-rw-r--r--src/multimedia/windows/qwindowsmultimediautils.cpp (renamed from src/multimedia/platform/windows/common/qwindowsmultimediautils.cpp)81
-rw-r--r--src/multimedia/windows/qwindowsmultimediautils_p.h47
-rw-r--r--src/multimedia/windows/qwindowsresampler.cpp241
-rw-r--r--src/multimedia/windows/qwindowsresampler_p.h75
561 files changed, 19434 insertions, 76744 deletions
diff --git a/src/multimedia/.prev_CMakeLists.txt b/src/multimedia/.prev_CMakeLists.txt
deleted file mode 100644
index 4d5240d9f..000000000
--- a/src/multimedia/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,571 +0,0 @@
-# Generated from multimedia.pro.
-
-#####################################################################
-## Multimedia Module:
-#####################################################################
-
-qt_internal_add_module(Multimedia
- PLUGIN_TYPES video/gstvideorenderer video/videonode
- SOURCES
- audio/qaudio.cpp audio/qaudio.h
- audio/qaudiobuffer.cpp audio/qaudiobuffer.h audio/qaudiobuffer_p.h
- audio/qaudiodecoder.cpp audio/qaudiodecoder.h
- audio/qaudiodeviceinfo.cpp audio/qaudiodeviceinfo.h audio/qaudiodeviceinfo_p.h
- audio/qaudioformat.cpp audio/qaudioformat.h
- audio/qaudiohelpers.cpp audio/qaudiohelpers_p.h
- audio/qaudioinput.cpp audio/qaudioinput.h
- audio/qaudiooutput.cpp audio/qaudiooutput.h
- audio/qaudioprobe.cpp audio/qaudioprobe.h
- audio/qaudiosystem.cpp audio/qaudiosystem_p.h
- audio/qsamplecache_p.cpp audio/qsamplecache_p.h
- audio/qsoundeffect.cpp audio/qsoundeffect.h
- audio/qwavedecoder.cpp audio/qwavedecoder.h
- camera/qcamera.cpp camera/qcamera.h camera/qcamera_p.h
- camera/qcameraexposure.cpp camera/qcameraexposure.h
- camera/qcamerafocus.cpp camera/qcamerafocus.h
- camera/qcameraimagecapture.cpp camera/qcameraimagecapture.h
- camera/qcameraimageprocessing.cpp camera/qcameraimageprocessing.h
- camera/qcamerainfo.cpp camera/qcamerainfo.h camera/qcamerainfo_p.h
- camera/qcameraviewfindersettings.cpp camera/qcameraviewfindersettings.h
- controls/qplatformaudiodecoder.cpp controls/qplatformaudiodecoder_p.h
- controls/qaudioencodersettingscontrol.cpp controls/qaudioencodersettingscontrol.h
- controls/qplatformcamera.cpp controls/qplatformcamera_p.h
- controls/qplatformcameraexposure.cpp controls/qplatformcameraexposure_p.h
- controls/qplatformcamerafocus.cpp controls/qplatformcamerafocus_p.h
- controls/qplatformcameraimagecapture.cpp controls/qplatformcameraimagecapture_p.h
- controls/qplatformcameraimageprocessing.cpp controls/qplatformcameraimageprocessing_p.h
- controls/qimageencodercontrol.cpp controls/qimageencodercontrol.h
- controls/qmediaaudioprobecontrol.cpp controls/qmediaaudioprobecontrol.h
- controls/qmediacontainercontrol.cpp controls/qmediacontainercontrol.h
- controls/qmediaplayercontrol.cpp controls/qplatformmediaplayer_p.h
- controls/qplatformmediarecorder.cpp controls/qplatformmediarecorder_p.h
- controls/qmediastreamscontrol.cpp controls/qmediastreamscontrol.h
- controls/qmediavideoprobecontrol.cpp controls/qmediavideoprobecontrol.h
- controls/qmetadatareadercontrol.cpp controls/qmetadatareadercontrol.h
- controls/qmetadatawritercontrol.cpp controls/qmetadatawritercontrol.h
- controls/qvideodeviceselectorcontrol.cpp controls/qvideodeviceselectorcontrol.h
- controls/qvideoencodersettingscontrol.cpp controls/qvideoencodersettingscontrol.h
- controls/qvideorenderercontrol.cpp controls/qvideorenderercontrol.h
- controls/qvideowindowcontrol.cpp controls/qvideowindowcontrol.h
- platform/qmediaplatformcaptureinterface.cpp platform/qmediaplatformcaptureinterface_p.h
- platform/qmediaplatformmediadevices.cpp platform/qmediaplatformmediadevices_p.h
- platform/qmediaplatformintegration.cpp platform/qmediaplatformintegration_p.h
- platform/qmediaplatformplayerinterface.cpp platform/qmediaplatformplayerinterface_p.h
- playback/qmediaplayer.cpp playback/qmediaplayer.h
- playback/qmediaplaylist.cpp playback/qmediaplaylist.h playback/qmediaplaylist_p.h
- playback/qplaylistfileparser.cpp playback/qplaylistfileparser_p.h
- qmediadevices.cpp qmediadevices.h
- qmediaenumdebug.h
- qmediametadata.cpp qmediametadata.h
- qmediapluginloader.cpp qmediapluginloader_p.h
- qmediaservice.cpp qmediaservice.h qmediaservice_p.h
- qmediaserviceprovider.cpp qmediaserviceprovider_p.h
- qmediaserviceproviderplugin.h
- qmediasink.cpp qmediasink.h
- qmediasource.cpp qmediasource.h qmediasource_p.h
- qmediastoragelocation.cpp qmediastoragelocation_p.h
- qmediatimerange.cpp qmediatimerange.h
- qmultimedia.cpp qmultimedia.h
- qmultimediautils.cpp qmultimediautils_p.h
- qtmultimediaglobal.h qtmultimediaglobal_p.h
- recording/qmediaencodersettings.cpp recording/qmediaencodersettings.h
- recording/qmediarecorder.cpp recording/qmediarecorder.h recording/qmediarecorder_p.h
- video/qabstractvideobuffer.cpp video/qabstractvideobuffer.h video/qabstractvideobuffer_p.h
- video/qabstractvideofilter.cpp video/qabstractvideofilter.h
- video/qabstractvideosurface.cpp video/qabstractvideosurface.h
- video/qimagevideobuffer.cpp video/qimagevideobuffer_p.h
- video/qmemoryvideobuffer.cpp video/qmemoryvideobuffer_p.h
- video/qvideoframe.cpp video/qvideoframe.h
- video/qvideoframeconversionhelper.cpp video/qvideoframeconversionhelper_p.h
- video/qvideooutputorientationhandler.cpp video/qvideooutputorientationhandler_p.h
- video/qvideoprobe.cpp video/qvideoprobe.h
- video/qvideosurfaceformat.cpp video/qvideosurfaceformat.h
- video/qvideosurfaceoutput.cpp video/qvideosurfaceoutput_p.h
- video/qvideosurfaces.cpp video/qvideosurfaces_p.h
- INCLUDE_DIRECTORIES
- .
- audio
- camera
- controls
- playback
- recording
- video
- LIBRARIES
- Qt::CorePrivate
- Qt::GuiPrivate
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::Gui
- Qt::Network
- PRIVATE_MODULE_INTERFACE
- Qt::CorePrivate
- Qt::GuiPrivate
-)
-
-
-qt_internal_add_simd_part(Multimedia SIMD sse2
- SOURCES
- video/qvideoframeconversionhelper_sse2.cpp
-)
-
-qt_internal_add_simd_part(Multimedia SIMD ssse3
- SOURCES
- video/qvideoframeconversionhelper_ssse3.cpp
-)
-
-qt_internal_add_simd_part(Multimedia SIMD avx2
- SOURCES
- video/qvideoframeconversionhelper_avx2.cpp
-)
-
-
-if(ANDROID)
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
- jar/Qt${QtMultimedia_VERSION_MAJOR}AndroidMultimedia.jar:org.qtproject.qt.android.multimedia.QtMultimediaUtils
- )
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_LIB_DEPENDENCIES
- lib/libQt6MultimediaQuick.so:Qt6Quick
- plugins/mediaservice/libplugins_mediaservice_qtmedia_android.so
- )
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_BUNDLED_FILES
- lib/libQt6MultimediaQuick.so
- )
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_PERMISSIONS
- android.permission.CAMERA android.permission.RECORD_AUDIO
- )
-endif()
-
-#### Keys ignored in scope 1:.:.:multimedia.pro:<TRUE>:
-# ANDROID_FEATURES = "android.hardware.camera" "android.hardware.camera.autofocus" "android.hardware.microphone"
-# MODULE_WINRT_CAPABILITIES_DEVICE = "microphone" "webcam"
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(Multimedia CONDITION WIN32
- SOURCES
- platform/windows/audio/qwindowsaudiodeviceinfo.cpp platform/windows/audio/qwindowsaudiodeviceinfo_p.h
- platform/windows/audio/qwindowsaudioinput.cpp platform/windows/audio/qwindowsaudioinput_p.h
- platform/windows/audio/qwindowsaudiooutput.cpp platform/windows/audio/qwindowsaudiooutput_p.h
- platform/windows/audio/qwindowsaudioutils.cpp platform/windows/audio/qwindowsaudioutils_p.h
- platform/windows/decoder/mfaudiodecodercontrol.cpp platform/windows/decoder/mfaudiodecodercontrol_p.h
- platform/windows/decoder/mfdecodersourcereader.cpp platform/windows/decoder/mfdecodersourcereader_p.h
- platform/windows/evr/evrcustompresenter.cpp platform/windows/evr/evrcustompresenter_p.h
- platform/windows/evr/evrd3dpresentengine.cpp platform/windows/evr/evrd3dpresentengine_p.h
- platform/windows/evr/evrdefs.cpp platform/windows/evr/evrdefs_p.h
- platform/windows/evr/evrhelpers.cpp platform/windows/evr/evrhelpers_p.h
- platform/windows/evr/evrvideowindowcontrol.cpp platform/windows/evr/evrvideowindowcontrol_p.h
- platform/windows/mfstream.cpp platform/windows/mfstream_p.h
- platform/windows/player/mfactivate.cpp platform/windows/player/mfactivate_p.h
- platform/windows/player/mfaudioprobecontrol.cpp platform/windows/player/mfaudioprobecontrol_p.h
- platform/windows/player/mfevrvideowindowcontrol.cpp platform/windows/player/mfevrvideowindowcontrol_p.h
- platform/windows/player/mfmetadatacontrol.cpp platform/windows/player/mfmetadatacontrol_p.h
- platform/windows/player/mfplayercontrol.cpp platform/windows/player/mfplayercontrol_p.h
- platform/windows/player/mfplayerservice.cpp platform/windows/player/mfplayerservice_p.h
- platform/windows/player/mfplayersession.cpp platform/windows/player/mfplayersession_p.h
- platform/windows/player/mftvideo.cpp platform/windows/player/mftvideo_p.h
- platform/windows/player/mfvideoprobecontrol.cpp platform/windows/player/mfvideoprobecontrol_p.h
- platform/windows/player/mfvideorenderercontrol.cpp platform/windows/player/mfvideorenderercontrol_p.h
- platform/windows/player/samplegrabber.cpp platform/windows/player/samplegrabber_p.h
- platform/windows/qwindowsmediadevices.cpp platform/windows/qwindowsmediadevices_p.h
- platform/windows/qwindowsintegration.cpp platform/windows/qwindowsintegration_p.h
- platform/windows/sourceresolver.cpp platform/windows/sourceresolver_p.h
- INCLUDE_DIRECTORIES
- .
- platform/windows/decoder
- platform/windows/evr
- platform/windows/player
- LIBRARIES
- Qt::GuiPrivate
- uuid
- PUBLIC_LIBRARIES
- Qt::Gui
- Qt::Network
- d3d9
- dxva2
- evr
- gdi32
- mf
- mfplat
- mfreadwrite
- mfuuid
- ole32
- oleaut32
- strmiids
- user32
- winmm
- wmcodecdspuuid
- wmf
- PRIVATE_MODULE_INTERFACE
- Qt::GuiPrivate
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer
- SOURCES
- platform/gstreamer/audio/qaudiodeviceinfo_gstreamer.cpp platform/gstreamer/audio/qaudiodeviceinfo_gstreamer_p.h
- platform/gstreamer/audio/qaudioengine_gstreamer.cpp platform/gstreamer/audio/qaudioengine_gstreamer_p.h
- platform/gstreamer/audio/qaudioinput_gstreamer.cpp platform/gstreamer/audio/qaudioinput_gstreamer_p.h
- platform/gstreamer/audio/qaudiooutput_gstreamer.cpp platform/gstreamer/audio/qaudiooutput_gstreamer_p.h
- platform/gstreamer/audio/qgstreameraudiodecodercontrol.cpp platform/gstreamer/audio/qgstreameraudiodecodercontrol_p.h
- platform/gstreamer/common/qgstappsrc.cpp platform/gstreamer/common/qgstappsrc_p.h
- platform/gstreamer/common/qgstcodecsinfo.cpp platform/gstreamer/common/qgstcodecsinfo_p.h
- platform/gstreamer/common/qgstreameraudioprobecontrol.cpp platform/gstreamer/common/qgstreameraudioprobecontrol_p.h
- platform/gstreamer/common/qgstreamerbufferprobe.cpp platform/gstreamer/common/qgstreamerbufferprobe_p.h
- platform/gstreamer/common/qgstreamerbushelper.cpp platform/gstreamer/common/qgstreamerbushelper_p.h
- platform/gstreamer/common/qgstreamermessage.cpp platform/gstreamer/common/qgstreamermessage_p.h
- platform/gstreamer/common/qgstreamerplayercontrol.cpp platform/gstreamer/common/qgstreamerplayercontrol_p.h
- platform/gstreamer/common/qgstreamerplayersession.cpp platform/gstreamer/common/qgstreamerplayersession_p.h
- platform/gstreamer/common/qgstreamervideoinputdevicecontrol.cpp platform/gstreamer/common/qgstreamervideoinputdevicecontrol_p.h
- platform/gstreamer/common/qgstreamervideooverlay.cpp platform/gstreamer/common/qgstreamervideooverlay_p.h
- platform/gstreamer/common/qgstreamervideoprobecontrol.cpp platform/gstreamer/common/qgstreamervideoprobecontrol_p.h
- platform/gstreamer/common/qgstreamervideorenderer.cpp platform/gstreamer/common/qgstreamervideorenderer_p.h
- platform/gstreamer/common/qgstreamervideorendererinterface.cpp platform/gstreamer/common/qgstreamervideorendererinterface_p.h
- platform/gstreamer/common/qgstreamervideowindow.cpp platform/gstreamer/common/qgstreamervideowindow_p.h
- platform/gstreamer/common/qgstutils.cpp platform/gstreamer/common/qgstutils_p.h
- platform/gstreamer/common/qgstvideobuffer.cpp platform/gstreamer/common/qgstvideobuffer_p.h
- platform/gstreamer/common/qgstvideorendererplugin.cpp platform/gstreamer/common/qgstvideorendererplugin_p.h
- platform/gstreamer/common/qgstvideorenderersink.cpp platform/gstreamer/common/qgstvideorenderersink_p.h
- platform/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp platform/gstreamer/mediaplayer/qgstreamermetadataprovider_p.h
- platform/gstreamer/mediaplayer/qgstreamerplayerservice.cpp platform/gstreamer/mediaplayer/qgstreamerplayerservice_p.h
- platform/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp platform/gstreamer/mediaplayer/qgstreamerstreamscontrol_p.h
- platform/gstreamer/qgstreamermediadevices.cpp platform/gstreamer/qgstreamermediadevices_p.h
- platform/gstreamer/qgstreamerintegration.cpp platform/gstreamer/qgstreamerintegration_p.h
- DEFINES
- GLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_26
- INCLUDE_DIRECTORIES
- platform/gstreamer/mediaplayer
- LIBRARIES
- gstreamer
- gstreamer_app
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND use_camerabin
- SOURCES
- platform/gstreamer/camerabin/camerabinaudioencoder.cpp platform/gstreamer/camerabin/camerabinaudioencoder_p.h
- platform/gstreamer/camerabin/camerabincontainer.cpp platform/gstreamer/camerabin/camerabincontainer_p.h
- platform/gstreamer/camerabin/camerabincontrol.cpp platform/gstreamer/camerabin/camerabincontrol_p.h
- platform/gstreamer/camerabin/camerabinimagecapture.cpp platform/gstreamer/camerabin/camerabinimagecapture_p.h
- platform/gstreamer/camerabin/camerabinimageencoder.cpp platform/gstreamer/camerabin/camerabinimageencoder_p.h
- platform/gstreamer/camerabin/camerabinimageprocessing.cpp platform/gstreamer/camerabin/camerabinimageprocessing_p.h
- platform/gstreamer/camerabin/camerabinmetadata.cpp platform/gstreamer/camerabin/camerabinmetadata_p.h
- platform/gstreamer/camerabin/camerabinrecorder.cpp platform/gstreamer/camerabin/camerabinrecorder_p.h
- platform/gstreamer/camerabin/camerabinservice.cpp platform/gstreamer/camerabin/camerabinservice_p.h
- platform/gstreamer/camerabin/camerabinserviceplugin.cpp platform/gstreamer/camerabin/camerabinserviceplugin_p.h
- platform/gstreamer/camerabin/camerabinsession.cpp platform/gstreamer/camerabin/camerabinsession_p.h
- platform/gstreamer/camerabin/camerabinvideoencoder.cpp platform/gstreamer/camerabin/camerabinvideoencoder_p.h
- DEFINES
- GST_USE_CAMERABIN
-)
-
-qt_internal_extend_target(Multimedia CONDITION ((QT_FEATURE_gstreamer) AND (use_camerabin)) AND (qtConfig(gstreamer__p.hotography))
- SOURCES
- platform/gstreamer/camerabin/camerabinexposure.cpp platform/gstreamer/camerabin/camerabinexposure_p.h
- platform/gstreamer/camerabin/camerabinfocus.cpp platform/gstreamer/camerabin/camerabinfocus_p.h
- DEFINES
- GST_USE_UNSTABLE_API
- PUBLIC_LIBRARIES
- gstreamer_photography
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND QT_FEATURE_gstreamer_gl AND use_camerabin
- PUBLIC_LIBRARIES
- gstreamer_gl
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND QT_FEATURE_linux_v4l AND use_camerabin
- SOURCES
- platform/gstreamer/camerabin/camerabinv4limageprocessing.cpp platform/gstreamer/camerabin/camerabinv4limageprocessing_p.h
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND NOT use_camerabin
- SOURCES
- platform/gstreamer/mediacapture/qgstreameraudioencode.cpp platform/gstreamer/mediacapture/qgstreameraudioencode_p.h
- platform/gstreamer/mediacapture/qgstreamercameracontrol.cpp platform/gstreamer/mediacapture/qgstreamercameracontrol_p.h
- platform/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp platform/gstreamer/mediacapture/qgstreamercapturemetadatacontrol_p.h
- platform/gstreamer/mediacapture/qgstreamercaptureservice.cpp platform/gstreamer/mediacapture/qgstreamercaptureservice_p.h
- platform/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp platform/gstreamer/mediacapture/qgstreamercaptureserviceplugin_p.h
- platform/gstreamer/mediacapture/qgstreamercapturesession.cpp platform/gstreamer/mediacapture/qgstreamercapturesession_p.h
- platform/gstreamer/mediacapture/qgstreamerimagecapturecontrol.cpp platform/gstreamer/mediacapture/qgstreamerimagecapturecontrol_p.h
- platform/gstreamer/mediacapture/qgstreamerimageencode.cpp platform/gstreamer/mediacapture/qgstreamerimageencode_p.h
- platform/gstreamer/mediacapture/qgstreamermediacontainercontrol.cpp platform/gstreamer/mediacapture/qgstreamermediacontainercontrol_p.h
- platform/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp platform/gstreamer/mediacapture/qgstreamerrecordercontrol_p.h
- platform/gstreamer/mediacapture/qgstreamervideoencode.cpp platform/gstreamer/mediacapture/qgstreamervideoencode_p.h
- INCLUDE_DIRECTORIES
- platform/gstreamer/mediacapture
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND QT_FEATURE_linux_v4l AND use_gstreamer_camera AND NOT use_camerabin
- SOURCES
- platform/gstreamer/mediacapture/qgstreamerv4l2input.cpp platform/gstreamer/mediacapture/qgstreamerv4l2input_p.h
- DEFINES
- USE_GSTREAMER_CAMERA
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND QT_FEATURE_gstreamer_gl
- PUBLIC_LIBRARIES
- gstreamer_gl
-)
-
-qt_internal_extend_target(Multimedia CONDITION ANDROID AND QT_FEATURE_gstreamer
- LIBRARIES
- # Remove: L$ENV{GSTREAMER_ROOT_ANDROID}/armv7/lib
- # Remove: Wl,--_p.hole-archive
- # Remove: Wl,--no-_p.hole-archive
- WrapIconv::WrapIconv
- ffi
- glib-2.0
- gmodule-2.0
- gobject-2.0
- gstapp-1.0
- gstaudio-1.0
- gstbase-1.0
- gstpbutils-1.0
- gstreamer-1.0
- gsttag-1.0
- gstvideo-1.0
- intl
- orc-0.4
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_pulseaudio
- SOURCES
- platform/pulseaudio/qaudiodeviceinfo_pulse.cpp platform/pulseaudio/qaudiodeviceinfo_pulse_p.h
- platform/pulseaudio/qaudioengine_pulse.cpp platform/pulseaudio/qaudioengine_pulse_p.h
- platform/pulseaudio/qaudioinput_pulse.cpp platform/pulseaudio/qaudioinput_pulse_p.h
- platform/pulseaudio/qaudiooutput_pulse.cpp platform/pulseaudio/qaudiooutput_pulse_p.h
- platform/pulseaudio/qpulseaudiomediadevices.cpp platform/pulseaudio/qpulseaudiomediadevices_p.h
- platform/pulseaudio/qpulseaudiointegration.cpp platform/pulseaudio/qpulseaudiointegration_p.h
- platform/pulseaudio/qpulsehelpers.cpp platform/pulseaudio/qpulsehelpers_p.h
- LIBRARIES
- pulseaudio
-)
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_alsa
- SOURCES
- platform/alsa/qalsaaudiodeviceinfo.cpp platform/alsa/qalsaaudiodeviceinfo_p.h
- platform/alsa/qalsaaudioinput.cpp platform/alsa/qalsaaudioinput_p.h
- platform/alsa/qalsaaudiooutput.cpp platform/alsa/qalsaaudiooutput_p.h
- platform/alsa/qalsamediadevices.cpp platform/alsa/qalsamediadevices_p.h
- platform/alsa/qalsaintegration.cpp platform/alsa/qalsaintegration_p.h
- LIBRARIES
- alsa
-)
-
-qt_internal_extend_target(Multimedia CONDITION ANDROID
- SOURCES
- platform/android/audio/qopenslesaudioinput.cpp platform/android/audio/qopenslesaudioinput_p.h
- platform/android/audio/qopenslesaudiooutput.cpp platform/android/audio/qopenslesaudiooutput_p.h
- platform/android/audio/qopenslesdeviceinfo.cpp platform/android/audio/qopenslesdeviceinfo_p.h
- platform/android/audio/qopenslesengine.cpp platform/android/audio/qopenslesengine_p.h
- platform/android/common/qandroidglobal_p.h
- platform/android/common/qandroidmultimediautils.cpp platform/android/common/qandroidmultimediautils_p.h
- platform/android/common/qandroidvideooutput.cpp platform/android/common/qandroidvideooutput_p.h
- platform/android/mediacapture/qandroidaudioencodersettingscontrol.cpp platform/android/mediacapture/qandroidaudioencodersettingscontrol_p.h
- platform/android/mediacapture/qandroidcameracontrol.cpp platform/android/mediacapture/qandroidcameracontrol_p.h
- platform/android/mediacapture/qandroidcameraexposurecontrol.cpp platform/android/mediacapture/qandroidcameraexposurecontrol_p.h
- platform/android/mediacapture/qandroidcamerafocuscontrol.cpp platform/android/mediacapture/qandroidcamerafocuscontrol_p.h
- platform/android/mediacapture/qandroidcameraimagecapturecontrol.cpp platform/android/mediacapture/qandroidcameraimagecapturecontrol_p.h
- platform/android/mediacapture/qandroidcameraimageprocessingcontrol.cpp platform/android/mediacapture/qandroidcameraimageprocessingcontrol_p.h
- platform/android/mediacapture/qandroidcamerasession.cpp platform/android/mediacapture/qandroidcamerasession_p.h
- platform/android/mediacapture/qandroidcameravideorenderercontrol.cpp platform/android/mediacapture/qandroidcameravideorenderercontrol_p.h
- platform/android/mediacapture/qandroidcaptureservice.cpp platform/android/mediacapture/qandroidcaptureservice_p.h
- platform/android/mediacapture/qandroidcapturesession.cpp platform/android/mediacapture/qandroidcapturesession_p.h
- platform/android/mediacapture/qandroidimageencodercontrol.cpp platform/android/mediacapture/qandroidimageencodercontrol_p.h
- platform/android/mediacapture/qandroidmediacontainercontrol.cpp platform/android/mediacapture/qandroidmediacontainercontrol_p.h
- platform/android/mediacapture/qandroidmediarecordercontrol.cpp platform/android/mediacapture/qandroidmediarecordercontrol_p.h
- platform/android/mediacapture/qandroidmediavideoprobecontrol.cpp platform/android/mediacapture/qandroidmediavideoprobecontrol_p.h
- platform/android/mediacapture/qandroidvideodeviceselectorcontrol.cpp platform/android/mediacapture/qandroidvideodeviceselectorcontrol_p.h
- platform/android/mediacapture/qandroidvideoencodersettingscontrol.cpp platform/android/mediacapture/qandroidvideoencodersettingscontrol_p.h
- platform/android/mediaplayer/qandroidmediaplayercontrol.cpp platform/android/mediaplayer/qandroidmediaplayercontrol_p.h
- platform/android/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp platform/android/mediaplayer/qandroidmediaplayervideorenderercontrol_p.h
- platform/android/mediaplayer/qandroidmediaservice.cpp platform/android/mediaplayer/qandroidmediaservice_p.h
- platform/android/mediaplayer/qandroidmetadatareadercontrol.cpp platform/android/mediaplayer/qandroidmetadatareadercontrol_p.h
- platform/android/qandroidmediadevices.cpp platform/android/qandroidmediadevices_p.h
- platform/android/qandroidintegration.cpp platform/android/qandroidintegration_p.h
- platform/android/qandroidmediaserviceplugin.cpp platform/android/qandroidmediaserviceplugin_p.h
- platform/android/wrappers/jni/androidcamera.cpp platform/android/wrappers/jni/androidcamera_p.h
- platform/android/wrappers/jni/androidmediametadataretriever.cpp platform/android/wrappers/jni/androidmediametadataretriever_p.h
- platform/android/wrappers/jni/androidmediaplayer.cpp platform/android/wrappers/jni/androidmediaplayer_p.h
- platform/android/wrappers/jni/androidmediarecorder.cpp platform/android/wrappers/jni/androidmediarecorder_p.h
- platform/android/wrappers/jni/androidmultimediautils.cpp platform/android/wrappers/jni/androidmultimediautils_p.h
- platform/android/wrappers/jni/androidsurfacetexture.cpp platform/android/wrappers/jni/androidsurfacetexture_p.h
- platform/android/wrappers/jni/androidsurfaceview.cpp platform/android/wrappers/jni/androidsurfaceview_p.h
- INCLUDE_DIRECTORIES
- platform/android/common
- platform/android/mediacapture
- platform/android/mediaplayer
- platform/android/wrappers/jni
- LIBRARIES
- Qt::CorePrivate
- PUBLIC_LIBRARIES
- OpenSLES
- Qt::Core
- Qt::Network
- Qt::OpenGL
- PRIVATE_MODULE_INTERFACE
- Qt::CorePrivate
-)
-
-qt_internal_extend_target(Multimedia CONDITION WIN32 AND NOT TARGET Qt::OpenGL
- LIBRARIES
- gdi32
- user32
-)
-
-qt_internal_extend_target(Multimedia CONDITION TARGET Qt::Widgets AND WIN32
- PUBLIC_LIBRARIES
- Qt::Widgets
-)
-
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT WATCHOS
- SOURCES
- platform/darwin/audio/qcoreaudiodeviceinfo.mm platform/darwin/audio/qcoreaudiodeviceinfo_p.h
- platform/darwin/audio/qcoreaudioinput.mm platform/darwin/audio/qcoreaudioinput_p.h
- platform/darwin/audio/qcoreaudiooutput.mm platform/darwin/audio/qcoreaudiooutput_p.h
- platform/darwin/audio/qcoreaudioutils.mm platform/darwin/audio/qcoreaudioutils_p.h
- platform/darwin/mediaplayer/avfmediaplayercontrol.mm platform/darwin/mediaplayer/avfmediaplayercontrol_p.h
- platform/darwin/mediaplayer/avfmediaplayermetadatacontrol.mm platform/darwin/mediaplayer/avfmediaplayermetadatacontrol_p.h
- platform/darwin/mediaplayer/avfmediaplayerservice.mm platform/darwin/mediaplayer/avfmediaplayerservice_p.h
- platform/darwin/mediaplayer/avfmediaplayersession.mm platform/darwin/mediaplayer/avfmediaplayersession_p.h
- platform/darwin/mediaplayer/avfvideooutput.mm platform/darwin/mediaplayer/avfvideooutput_p.h
- platform/darwin/mediaplayer/avfvideowindowcontrol.mm platform/darwin/mediaplayer/avfvideowindowcontrol_p.h
- platform/darwin/qdarwinmediadevices.mm platform/darwin/qdarwinmediadevices_p.h
- platform/darwin/qdarwinintegration.mm platform/darwin/qdarwinintegration_p.h
- PUBLIC_LIBRARIES
- ${FWAudioToolbox}
- ${FWCoreAudio}
- ${FWCoreFoundation}
- ${FWCoreMedia}
- ${FWCoreVideo}
- ${FWFoundation}
- ${FWMetal}
- ${FWQt::OpenGL}
- ${FWQuartzCore}
- Qt::Network
- avfoundation
-)
-
-qt_internal_extend_target(Multimedia CONDITION MACOS AND NOT WATCHOS
- PUBLIC_LIBRARIES
- ${FWAppKit}
- ${FWAudioUnit}
-)
-
-qt_internal_extend_target(Multimedia CONDITION IOS AND NOT WATCHOS
- PUBLIC_LIBRARIES
- ${FWCoreGraphics}
- ${FWCoreVideo}
-)
-
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT TVOS AND NOT WATCHOS
- SOURCES
- platform/darwin/camera/avfaudioencodersettingscontrol.mm platform/darwin/camera/avfaudioencodersettingscontrol_p.h
- platform/darwin/camera/avfcamera.mm platform/darwin/camera/avfcamera_p.h
- platform/darwin/camera/avfcameradebug_p.h
- platform/darwin/camera/avfcameradevicecontrol.mm platform/darwin/camera/avfcameradevicecontrol_p.h
- platform/darwin/camera/avfcameraexposure.mm platform/darwin/camera/avfcameraexposure_p.h
- platform/darwin/camera/avfcamerafocus.mm platform/darwin/camera/avfcamerafocus_p.h
- platform/darwin/camera/avfcamerametadatacontrol.mm platform/darwin/camera/avfcamerametadatacontrol_p.h
- platform/darwin/camera/avfcamerarenderer.mm platform/darwin/camera/avfcamerarenderer_p.h
- platform/darwin/camera/avfcameraservice.mm platform/darwin/camera/avfcameraservice_p.h
- platform/darwin/camera/avfcameraserviceplugin.mm platform/darwin/camera/avfcameraserviceplugin_p.h
- platform/darwin/camera/avfcamerasession.mm platform/darwin/camera/avfcamerasession_p.h
- platform/darwin/camera/avfcamerautility.mm platform/darwin/camera/avfcamerautility_p.h
- platform/darwin/camera/avfcamerawindowcontrol.mm platform/darwin/camera/avfcamerawindowcontrol_p.h
- platform/darwin/camera/avfcameraimagecapture.mm platform/darwin/camera/avfcameraimagecapture_p.h
- platform/darwin/camera/avfimageencodercontrol.mm platform/darwin/camera/avfimageencodercontrol_p.h
- platform/darwin/camera/avfmediacontainercontrol.mm platform/darwin/camera/avfmediacontainercontrol_p.h
- platform/darwin/camera/avfmediavideoprobecontrol.mm platform/darwin/camera/avfmediavideoprobecontrol_p.h
- platform/darwin/camera/avfstoragelocation.mm platform/darwin/camera/avfstoragelocation_p.h
- platform/darwin/camera/avfvideoencodersettingscontrol.mm platform/darwin/camera/avfvideoencodersettingscontrol_p.h
-)
-
-qt_internal_extend_target(Multimedia CONDITION MACOS AND NOT TVOS AND NOT WATCHOS
- SOURCES
- platform/darwin/camera/avfmediaencoder.mm platform/darwin/camera/avfmediaencoder_p.h
-)
-
-qt_internal_extend_target(Multimedia CONDITION IOS AND NOT TVOS AND NOT WATCHOS
- SOURCES
- platform/darwin/camera/avfmediaassetwriter.mm platform/darwin/camera/avfmediaassetwriter_p.h
- platform/darwin/camera/avfmediaencoder_ios.mm platform/darwin/camera/avfmediaencoder_ios_p.h
-)
-
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT WATCHOS AND (IOS OR TVOS)
- SOURCES
- platform/darwin/audio/qcoreaudiosessionmanager.mm platform/darwin/audio/qcoreaudiosessionmanager_p.h
- PUBLIC_LIBRARIES
- ${FWAVFoundation}
- ${FWFoundation}
-)
-
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT IOS AND NOT TVOS AND NOT WATCHOS
- PUBLIC_LIBRARIES
- ${FWAppKit}
- ${FWApplicationServices}
- ${FWAudioUnit}
-)
-
-qt_internal_extend_target(Multimedia CONDITION APPLE AND QT_FEATURE_opengl AND NOT WATCHOS AND (IOS OR TVOS)
- SOURCES
- platform/darwin/mediaplayer/avfdisplaylink.mm platform/darwin/mediaplayer/avfdisplaylink_p.h
- platform/darwin/mediaplayer/avfvideoframerenderer_ios.mm platform/darwin/mediaplayer/avfvideoframerenderer_ios_p.h
- platform/darwin/mediaplayer/avfvideorenderercontrol.mm platform/darwin/mediaplayer/avfvideorenderercontrol_p.h
-)
-
-qt_internal_extend_target(Multimedia CONDITION APPLE AND QT_FEATURE_opengl AND NOT IOS AND NOT TVOS AND NOT WATCHOS
- SOURCES
- platform/darwin/mediaplayer/avfdisplaylink.mm platform/darwin/mediaplayer/avfdisplaylink_p.h
- platform/darwin/mediaplayer/avfvideoframerenderer.mm platform/darwin/mediaplayer/avfvideoframerenderer_p.h
- platform/darwin/mediaplayer/avfvideorenderercontrol.mm platform/darwin/mediaplayer/avfvideorenderercontrol_p.h
-)
-
-qt_internal_extend_target(Multimedia CONDITION QNX
- SOURCES
- platform/qnx/audio/neutrinoserviceplugin.cpp platform/qnx/audio/neutrinoserviceplugin_p.h
- platform/qnx/audio/qnxaudiodeviceinfo.cpp platform/qnx/audio/qnxaudiodeviceinfo_p.h
- platform/qnx/audio/qnxaudioinput.cpp platform/qnx/audio/qnxaudioinput_p.h
- platform/qnx/audio/qnxaudiooutput.cpp platform/qnx/audio/qnxaudiooutput_p.h
- platform/qnx/audio/qnxaudioutils.cpp platform/qnx/audio/qnxaudioutils_p.h
- platform/qnx/camera/bbcameraaudioencodersettingscontrol.cpp platform/qnx/camera/bbcameraaudioencodersettingscontrol_p.h
- platform/qnx/camera/bbcameracontrol.cpp platform/qnx/camera/bbcameracontrol_p.h
- platform/qnx/camera/bbcameraexposurecontrol.cpp platform/qnx/camera/bbcameraexposurecontrol_p.h
- platform/qnx/camera/bbcamerafocuscontrol.cpp platform/qnx/camera/bbcamerafocuscontrol_p.h
- platform/qnx/camera/bbcameraimagecapturecontrol.cpp platform/qnx/camera/bbcameraimagecapturecontrol_p.h
- platform/qnx/camera/bbcameraimageprocessingcontrol.cpp platform/qnx/camera/bbcameraimageprocessingcontrol_p.h
- platform/qnx/camera/bbcameramediarecordercontrol.cpp platform/qnx/camera/bbcameramediarecordercontrol_p.h
- platform/qnx/camera/bbcameraorientatio_p.handler.cpp platform/qnx/camera/bbcameraorientatio_p.handler.h
- platform/qnx/camera/bbcameraservice.cpp platform/qnx/camera/bbcameraservice_p.h
- platform/qnx/camera/bbcamerasession.cpp platform/qnx/camera/bbcamerasession_p.h
- platform/qnx/camera/bbcameravideoencodersettingscontrol.cpp platform/qnx/camera/bbcameravideoencodersettingscontrol_p.h
- platform/qnx/camera/bbcameraviewfindersettingscontrol.cpp platform/qnx/camera/bbcameraviewfindersettingscontrol_p.h
- platform/qnx/camera/bbimageencodercontrol.cpp platform/qnx/camera/bbimageencodercontrol_p.h
- platform/qnx/camera/bbmediastoragelocation.cpp platform/qnx/camera/bbmediastoragelocation_p.h
- platform/qnx/camera/bbvideodeviceselectorcontrol.cpp platform/qnx/camera/bbvideodeviceselectorcontrol_p.h
- platform/qnx/camera/bbvideorenderercontrol.cpp platform/qnx/camera/bbvideorenderercontrol_p.h
- platform/qnx/common/windowgrabber.cpp platform/qnx/common/windowgrabber_p.h
- platform/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp platform/qnx/mediaplayer/mmrenderermediaplayercontrol_p.h
- platform/qnx/mediaplayer/mmrenderermediaplayerservice.cpp platform/qnx/mediaplayer/mmrenderermediaplayerservice_p.h
- platform/qnx/mediaplayer/mmrenderermetadata.cpp platform/qnx/mediaplayer/mmrenderermetadata_p.h
- platform/qnx/mediaplayer/mmrenderermetadatareadercontrol.cpp platform/qnx/mediaplayer/mmrenderermetadatareadercontrol_p.h
- platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol_p.h
- platform/qnx/mediaplayer/mmrendererutil.cpp platform/qnx/mediaplayer/mmrendererutil_p.h
- platform/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp platform/qnx/mediaplayer/mmrenderervideowindowcontrol_p.h
- platform/qnx/mediaplayer/mmrevent_p.hread.cpp platform/qnx/mediaplayer/mmrevent_p.hread.h
- platform/qnx/mediaplayer/mmreventmediaplayercontrol.cpp platform/qnx/mediaplayer/mmreventmediaplayercontrol_p.h
- platform/qnx/qqnxmediadevices.cpp platform/qnx/qqnxmediadevices_p.h
- platform/qnx/qqnxintegration.cpp platform/qnx/qqnxintegration_p.h
- INCLUDE_DIRECTORIES
- platform/qnx/camera
- platform/qnx/common
- platform/qnx/mediaplayer
- PUBLIC_LIBRARIES
- asound
- audio_manager
- camapi
- mmrenderer
-)
-qt_internal_add_docs(Multimedia
- doc/qtmultimedia.qdocconf
-)
-
diff --git a/src/multimedia/CMakeLists.txt b/src/multimedia/CMakeLists.txt
index 6fbd94055..1cca4c2de 100644
--- a/src/multimedia/CMakeLists.txt
+++ b/src/multimedia/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from multimedia.pro.
#####################################################################
@@ -6,17 +9,18 @@
find_package(Qt6 COMPONENTS ShaderTools)
-qt_internal_find_apple_system_framework(FWCoreMedia CoreMedia) # special case
qt_internal_find_apple_system_framework(FWCoreAudio CoreAudio) # special case
+qt_internal_find_apple_system_framework(FWCoreVideo CoreVideo) # special case
qt_internal_find_apple_system_framework(FWAudioUnit AudioUnit) # special case
-qt_internal_find_apple_system_framework(FWAVFoundation AVFoundation) # special case
+qt_internal_find_apple_system_framework(FWCoreMedia CoreMedia) # special case
+qt_internal_find_apple_system_framework(FWAudioToolbox AudioToolbox) # special case
qt_internal_add_module(Multimedia
- PLUGIN_TYPES video/gstvideorenderer video/videonode
+ PLUGIN_TYPES multimedia
SOURCES
- audio/qaudio.cpp audio/qaudio.h
+ audio/qtaudio.cpp audio/qtaudio.h audio/qaudio.h
audio/qaudiobuffer.cpp audio/qaudiobuffer.h
- audio/qaudiodecoder.cpp audio/qaudiodecoder.h
+ 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/qaudiooutput.cpp audio/qaudiooutput.h
@@ -25,25 +29,34 @@ qt_internal_add_module(Multimedia
audio/qaudiosource.cpp audio/qaudiosource.h
audio/qaudiosink.cpp audio/qaudiosink.h
audio/qaudiosystem.cpp audio/qaudiosystem_p.h
+ audio/qaudiostatemachine.cpp audio/qaudiostatemachine_p.h
+ audio/qaudiostatemachineutils_p.h
audio/qsamplecache_p.cpp audio/qsamplecache_p.h
audio/qsoundeffect.cpp audio/qsoundeffect.h
audio/qwavedecoder.cpp audio/qwavedecoder.h
camera/qcamera.cpp camera/qcamera.h camera/qcamera_p.h
camera/qcameradevice.cpp camera/qcameradevice.h camera/qcameradevice_p.h
camera/qimagecapture.cpp camera/qimagecapture.h
+ compat/removed_api.cpp
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/qplatformimagecapture.cpp platform/qplatformimagecapture_p.h
platform/qplatformmediacapture.cpp platform/qplatformmediacapture_p.h
platform/qplatformmediadevices.cpp platform/qplatformmediadevices_p.h
- platform/qplatformmediaencoder.cpp platform/qplatformmediaencoder_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/qplatformvideodevices.cpp platform/qplatformvideodevices_p.h
platform/qplatformvideosink.cpp platform/qplatformvideosink_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
@@ -51,18 +64,26 @@ qt_internal_add_module(Multimedia
qmediastoragelocation.cpp qmediastoragelocation_p.h
qmediatimerange.cpp qmediatimerange.h
qmultimediautils.cpp qmultimediautils_p.h
+ qmaybe_p.h
qtmultimediaglobal.h qtmultimediaglobal_p.h
+ qerrorinfo_p.h
recording/qmediacapturesession.cpp recording/qmediacapturesession.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
video/qabstractvideobuffer.cpp video/qabstractvideobuffer_p.h
video/qmemoryvideobuffer.cpp video/qmemoryvideobuffer_p.h
- video/qvideoframe.cpp video/qvideoframe.h
+ video/qimagevideobuffer.cpp video/qimagevideobuffer_p.h
+ video/qvideoframe.cpp video/qvideoframe.h video/qvideoframe_p.h
video/qvideosink.cpp video/qvideosink.h
video/qvideotexturehelper.cpp video/qvideotexturehelper_p.h
video/qvideoframeconversionhelper.cpp video/qvideoframeconversionhelper_p.h
video/qvideooutputorientationhandler.cpp video/qvideooutputorientationhandler_p.h
+ video/qvideoframeconverter.cpp video/qvideoframeconverter_p.h
video/qvideoframeformat.cpp video/qvideoframeformat.h
video/qvideowindow.cpp video/qvideowindow_p.h
+ video/qtvideo.cpp video/qtvideo.h
INCLUDE_DIRECTORIES
audio
camera
@@ -81,6 +102,9 @@ qt_internal_add_module(Multimedia
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
Qt::GuiPrivate
+ NO_PCH_SOURCES
+ compat/removed_api.cpp
+ GENERATE_CPP_EXPORTS
)
qt_internal_add_simd_part(Multimedia SIMD sse2
@@ -93,402 +117,228 @@ qt_internal_add_simd_part(Multimedia SIMD ssse3
video/qvideoframeconversionhelper_ssse3.cpp
)
-qt_internal_add_simd_part(Multimedia SIMD avx2
+qt_internal_add_simd_part(Multimedia SIMD arch_haswell
SOURCES
video/qvideoframeconversionhelper_avx2.cpp
+ EXCLUDE_OSX_ARCHITECTURES
+ arm64
)
+qt_internal_add_docs(Multimedia
+ doc/qtmultimedia.qdocconf
+)
-if(ANDROID)
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
- jar/Qt${QtMultimedia_VERSION_MAJOR}AndroidMultimedia.jar:org.qtproject.qt.android.multimedia.QtMultimediaUtils
- jar/Qt${QtMultimedia_VERSION_MAJOR}AndroidMultimedia.jar:org.qtproject.qt.android.multimedia.QtAudioDeviceManager
- )
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_LIB_DEPENDENCIES
- lib/libQt6MultimediaQuick.so:Qt6Quick
- )
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_BUNDLED_FILES
- lib/libQt6MultimediaQuick.so
- )
- set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_PERMISSIONS
- android.permission.CAMERA android.permission.RECORD_AUDIO
- android.permission.BLUETOOTH
- android.permission.MODIFY_AUDIO_SETTINGS
- )
-endif()
-
-#### Keys ignored in scope 1:.:.:multimedia.pro:<TRUE>:
-# ANDROID_FEATURES = "android.hardware.camera" "android.hardware.camera.autofocus" "android.hardware.microphone"
-# MODULE_WINRT_CAPABILITIES_DEVICE = "microphone" "webcam"
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_wmf
+qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_alsa
SOURCES
- platform/windows/audio/qwindowsaudiodevice.cpp platform/windows/audio/qwindowsaudiodevice_p.h
- platform/windows/audio/qwindowsaudiosource.cpp platform/windows/audio/qwindowsaudiosource_p.h
- platform/windows/audio/qwindowsaudiosink.cpp platform/windows/audio/qwindowsaudiosink_p.h
- platform/windows/audio/qwindowsaudioutils.cpp platform/windows/audio/qwindowsaudioutils_p.h
- platform/windows/common/mfmetadata.cpp platform/windows/common/mfmetadata_p.h
- platform/windows/common/qwindowsmultimediautils.cpp platform/windows/common/qwindowsmultimediautils_p.h
- platform/windows/common/qwindowsiupointer_p.h
- platform/windows/decoder/mfaudiodecodercontrol.cpp platform/windows/decoder/mfaudiodecodercontrol_p.h
- platform/windows/decoder/mfdecodersourcereader.cpp platform/windows/decoder/mfdecodersourcereader_p.h
- platform/windows/evr/evrcustompresenter.cpp platform/windows/evr/evrcustompresenter_p.h
- platform/windows/evr/evrd3dpresentengine.cpp platform/windows/evr/evrd3dpresentengine_p.h
- platform/windows/evr/evrdefs.cpp platform/windows/evr/evrdefs_p.h
- platform/windows/evr/evrhelpers.cpp platform/windows/evr/evrhelpers_p.h
- platform/windows/evr/evrvideowindowcontrol.cpp platform/windows/evr/evrvideowindowcontrol_p.h
- platform/windows/mfstream.cpp platform/windows/mfstream_p.h
- platform/windows/player/mfactivate.cpp platform/windows/player/mfactivate_p.h
- platform/windows/player/mfevrvideowindowcontrol.cpp platform/windows/player/mfevrvideowindowcontrol_p.h
- platform/windows/player/mfplayercontrol.cpp platform/windows/player/mfplayercontrol_p.h
- platform/windows/player/mfplayersession.cpp platform/windows/player/mfplayersession_p.h
- platform/windows/player/mftvideo.cpp platform/windows/player/mftvideo_p.h
- platform/windows/player/mfvideorenderercontrol.cpp platform/windows/player/mfvideorenderercontrol_p.h
- platform/windows/player/samplegrabber.cpp platform/windows/player/samplegrabber_p.h
- platform/windows/mediacapture/qwindowscamera.cpp
- platform/windows/mediacapture/qwindowscamera_p.h
- platform/windows/mediacapture/qwindowsimagecapture.cpp
- platform/windows/mediacapture/qwindowsimagecapture_p.h
- platform/windows/mediacapture/qwindowsmediacapture.cpp
- platform/windows/mediacapture/qwindowsmediacapture_p.h
- platform/windows/mediacapture/qwindowsmediadevicereader.cpp
- platform/windows/mediacapture/qwindowsmediadevicereader_p.h
- platform/windows/mediacapture/qwindowsmediadevicesession.cpp
- platform/windows/mediacapture/qwindowsmediadevicesession_p.h
- platform/windows/mediacapture/qwindowsmediaencoder.cpp
- platform/windows/mediacapture/qwindowsmediaencoder_p.h
- platform/windows/qwindowsmediadevices.cpp platform/windows/qwindowsmediadevices_p.h
- platform/windows/qwindowsformatinfo.cpp platform/windows/qwindowsformatinfo_p.h
- platform/windows/qwindowsintegration.cpp platform/windows/qwindowsintegration_p.h
- platform/windows/sourceresolver.cpp platform/windows/sourceresolver_p.h
+ alsa/qalsaaudiodevice.cpp alsa/qalsaaudiodevice_p.h
+ alsa/qalsaaudiosource.cpp alsa/qalsaaudiosource_p.h
+ alsa/qalsaaudiosink.cpp alsa/qalsaaudiosink_p.h
+ alsa/qalsamediadevices.cpp alsa/qalsamediadevices_p.h
INCLUDE_DIRECTORIES
- platform/windows/common
- platform/windows/decoder
- platform/windows/evr
- platform/windows/player
- platform/windows/mediacapture
+ alsa
LIBRARIES
- uuid
- WMF::WMF
- d3d9
- dxva2
- evr
- gdi32
- mf
- mfplat
- mfreadwrite
- mfuuid
- ole32
- oleaut32
- strmiids
- user32
- winmm
- wmcodecdspuuid
+ ALSA::ALSA
)
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer
+qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_pulseaudio
SOURCES
- platform/gstreamer/audio/qgstreameraudiodevice.cpp platform/gstreamer/audio/qgstreameraudiodevice_p.h
- platform/gstreamer/audio/qgstreameraudiosource.cpp platform/gstreamer/audio/qgstreameraudiosource_p.h
- platform/gstreamer/audio/qgstreameraudiosink.cpp platform/gstreamer/audio/qgstreameraudiosink_p.h
- platform/gstreamer/audio/qgstreameraudiodecoder.cpp platform/gstreamer/audio/qgstreameraudiodecoder_p.h
- platform/gstreamer/common/qgst_p.h
- platform/gstreamer/common/qgstappsrc.cpp platform/gstreamer/common/qgstappsrc_p.h
- platform/gstreamer/common/qgstreameraudioinput.cpp platform/gstreamer/common/qgstreameraudioinput_p.h
- platform/gstreamer/common/qgstreameraudiooutput.cpp platform/gstreamer/common/qgstreameraudiooutput_p.h
- platform/gstreamer/common/qgstreamerbufferprobe.cpp platform/gstreamer/common/qgstreamerbufferprobe_p.h
- platform/gstreamer/common/qgstreamermetadata.cpp platform/gstreamer/common/qgstreamermetadata_p.h
- platform/gstreamer/common/qgstreamermessage.cpp platform/gstreamer/common/qgstreamermessage_p.h
- platform/gstreamer/common/qgstreamermediaplayer.cpp platform/gstreamer/common/qgstreamermediaplayer_p.h
- platform/gstreamer/common/qgstreamervideooutput.cpp platform/gstreamer/common/qgstreamervideooutput_p.h
- platform/gstreamer/common/qgstreamervideooverlay.cpp platform/gstreamer/common/qgstreamervideooverlay_p.h
- platform/gstreamer/common/qgstreamervideosink.cpp platform/gstreamer/common/qgstreamervideosink_p.h
- platform/gstreamer/common/qgstpipeline.cpp platform/gstreamer/common/qgstpipeline_p.h
- platform/gstreamer/common/qgstutils.cpp platform/gstreamer/common/qgstutils_p.h
- platform/gstreamer/common/qgstvideobuffer.cpp platform/gstreamer/common/qgstvideobuffer_p.h
- platform/gstreamer/common/qgstvideorenderersink.cpp platform/gstreamer/common/qgstvideorenderersink_p.h
- platform/gstreamer/common/qgstsubtitlesink.cpp platform/gstreamer/common/qgstsubtitlesink_p.h
- platform/gstreamer/qgstreamermediadevices.cpp platform/gstreamer/qgstreamermediadevices_p.h
- platform/gstreamer/qgstreamerformatinfo.cpp platform/gstreamer/qgstreamerformatinfo_p.h
- platform/gstreamer/qgstreamerintegration.cpp platform/gstreamer/qgstreamerintegration_p.h
- platform/gstreamer/mediacapture/qgstreamercamera.cpp platform/gstreamer/mediacapture/qgstreamercamera_p.h
- platform/gstreamer/mediacapture/qgstreamerimagecapture.cpp platform/gstreamer/mediacapture/qgstreamerimagecapture_p.h
- platform/gstreamer/mediacapture/qgstreamermediacapture.cpp platform/gstreamer/mediacapture/qgstreamermediacapture_p.h
- platform/gstreamer/mediacapture/qgstreamermediaencoder.cpp platform/gstreamer/mediacapture/qgstreamermediaencoder_p.h
- DEFINES
- GLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_26
+ pulseaudio/qpulseaudiodevice.cpp pulseaudio/qpulseaudiodevice_p.h
+ pulseaudio/qaudioengine_pulse.cpp pulseaudio/qaudioengine_pulse_p.h
+ pulseaudio/qpulseaudiosource.cpp pulseaudio/qpulseaudiosource_p.h
+ pulseaudio/qpulseaudiosink.cpp pulseaudio/qpulseaudiosink_p.h
+ pulseaudio/qpulsehelpers.cpp pulseaudio/qpulsehelpers_p.h
+ pulseaudio/qpulseaudiomediadevices.cpp pulseaudio/qpulseaudiomediadevices_p.h
INCLUDE_DIRECTORIES
- platform/gstreamer/mediaplayer
- platform/gstreamer/mediacapture
+ pulseaudio
LIBRARIES
- GStreamer::GStreamer # special case
- GStreamer::App # special case
+ WrapPulseAudio::WrapPulseAudio
)
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND QT_FEATURE_gstreamer_photography
+qt_internal_extend_target(Multimedia CONDITION ANDROID
+ SOURCES
+ android/qandroidaudiosource.cpp android/qandroidaudiosource_p.h
+ android/qandroidaudiosink.cpp android/qandroidaudiosink_p.h
+ android/qandroidaudiodevice.cpp android/qandroidaudiodevice_p.h
+ android/qopenslesengine.cpp android/qopenslesengine_p.h
+ android/qandroidmediadevices.cpp android/qandroidmediadevices_p.h
+ INCLUDE_DIRECTORIES
+ android
LIBRARIES
- -lgstphotography-1.0#GStreamer::Photography # special case
+ OpenSLES
)
-if (QT_FEATURE_gstreamer AND QT_FEATURE_gstreamer_gl)
- qt_find_package(EGL)
+if (ANDROID)
+ set_property(TARGET Multimedia APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
+ jar/Qt${QtMultimedia_VERSION_MAJOR}AndroidMultimedia.jar:org.qtproject.qt.android.multimedia.QtAudioDeviceManager
+ )
endif()
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_gstreamer AND QT_FEATURE_gstreamer_gl
- LIBRARIES
- GStreamer::Gl # special case
- EGL::EGL
-)
-
-qt_internal_extend_target(Multimedia CONDITION ANDROID AND QT_FEATURE_gstreamer
+qt_internal_extend_target(Multimedia CONDITION APPLE
+ SOURCES
+ darwin/qdarwinaudiodevice.mm darwin/qdarwinaudiodevice_p.h
+ darwin/qdarwinaudiosource.mm darwin/qdarwinaudiosource_p.h
+ darwin/qdarwinaudiosink.mm darwin/qdarwinaudiosink_p.h
+ darwin/qcoreaudioutils.mm darwin/qcoreaudioutils_p.h
+ darwin/qdarwinmediadevices.mm darwin/qdarwinmediadevices_p.h
+ INCLUDE_DIRECTORIES
+ darwin
LIBRARIES
- # Remove: L$ENV{GSTREAMER_ROOT_ANDROID}/armv7/lib
- # Remove: Wl,--_p.hole-archive
- # Remove: Wl,--no-_p.hole-archive
- WrapIconv::WrapIconv
- ffi
- glib-2.0
- gmodule-2.0
- gobject-2.0
- gstapp-1.0
- gstaudio-1.0
- gstbase-1.0
- gstpbutils-1.0
- gstreamer-1.0
- gsttag-1.0
- gstvideo-1.0
- intl
- orc-0.4
+ ${FWAudioToolbox}
+ ${FWCoreAudio}
+ ${FWCoreMedia}
+ ${FWCoreFoundation}
)
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_pulseaudio
+qt_internal_extend_target(Multimedia CONDITION MACOS
SOURCES
- platform/pulseaudio/qpulseaudiodevice.cpp platform/pulseaudio/qpulseaudiodevice_p.h
- platform/pulseaudio/qaudioengine_pulse.cpp platform/pulseaudio/qaudioengine_pulse_p.h
- platform/pulseaudio/qpulseaudiosource.cpp platform/pulseaudio/qpulseaudiosource_p.h
- platform/pulseaudio/qpulseaudiosink.cpp platform/pulseaudio/qpulseaudiosink_p.h
- platform/pulseaudio/qpulseaudiomediadevices.cpp platform/pulseaudio/qpulseaudiomediadevices_p.h
- platform/pulseaudio/qpulseaudiointegration.cpp platform/pulseaudio/qpulseaudiointegration_p.h
- platform/pulseaudio/qpulsehelpers.cpp platform/pulseaudio/qpulsehelpers_p.h
- LIBRARIES
- WrapPulseAudio::WrapPulseAudio
+ darwin/qmacosaudiodatautils_p.h
)
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_alsa
+qt_internal_extend_target(Multimedia CONDITION IOS OR TVOS
SOURCES
- platform/alsa/qalsaaudiodevice.cpp platform/alsa/qalsaaudiodevice_p.h
- platform/alsa/qalsaaudiosource.cpp platform/alsa/qalsaaudiosource_p.h
- platform/alsa/qalsaaudiosink.cpp platform/alsa/qalsaaudiosink_p.h
- platform/alsa/qalsamediadevices.cpp platform/alsa/qalsamediadevices_p.h
- platform/alsa/qalsaintegration.cpp platform/alsa/qalsaintegration_p.h
+ darwin/qcoreaudiosessionmanager.mm darwin/qcoreaudiosessionmanager_p.h
LIBRARIES
- ALSA::ALSA
+ ${FWAVFoundation}
+ ${FWFoundation}
)
-qt_internal_extend_target(Multimedia CONDITION ANDROID
+qt_internal_extend_target(Multimedia CONDITION QNX
SOURCES
- platform/android/audio/qandroidaudiosource.cpp platform/android/audio/qandroidaudiosource_p.h
- platform/android/audio/qandroidaudiosink.cpp platform/android/audio/qandroidaudiosink_p.h
- platform/android/audio/qandroidaudiodevice.cpp platform/android/audio/qandroidaudiodevice_p.h
- platform/android/audio/qopenslesengine.cpp platform/android/audio/qopenslesengine_p.h
- platform/android/common/qandroidaudiooutput_p.h
- platform/android/audio/qandroidaudiodecoder.cpp platform/android/audio/qandroidaudiodecoder_p.h
- platform/android/common/qandroidglobal_p.h
- platform/android/common/qandroidmultimediautils.cpp platform/android/common/qandroidmultimediautils_p.h
- platform/android/common/qandroidvideosink.cpp platform/android/common/qandroidvideosink_p.h
- platform/android/common/qandroidvideooutput.cpp platform/android/common/qandroidvideooutput_p.h
- platform/android/mediacapture/qandroidcamera.cpp platform/android/mediacapture/qandroidcamera_p.h
- platform/android/mediacapture/qandroidimagecapture.cpp platform/android/mediacapture/qandroidimagecapture_p.h
- platform/android/mediacapture/qandroidcamerasession.cpp platform/android/mediacapture/qandroidcamerasession_p.h
- platform/android/mediacapture/qandroidmediacapturesession.cpp platform/android/mediacapture/qandroidmediacapturesession_p.h
- platform/android/mediacapture/qandroidcapturesession.cpp platform/android/mediacapture/qandroidcapturesession_p.h
- platform/android/mediacapture/qandroidmediaencoder.cpp platform/android/mediacapture/qandroidmediaencoder_p.h
- platform/android/mediaplayer/qandroidmediaplayer.cpp platform/android/mediaplayer/qandroidmediaplayer_p.h
- platform/android/mediaplayer/qandroidmetadata.cpp platform/android/mediaplayer/qandroidmetadata_p.h
- platform/android/qandroidmediadevices.cpp platform/android/qandroidmediadevices_p.h
- platform/android/qandroidformatsinfo.cpp platform/android/qandroidformatsinfo_p.h
- platform/android/qandroidintegration.cpp platform/android/qandroidintegration_p.h
- platform/android/wrappers/jni/androidcamera.cpp platform/android/wrappers/jni/androidcamera_p.h
- platform/android/wrappers/jni/androidmediametadataretriever.cpp platform/android/wrappers/jni/androidmediametadataretriever_p.h
- platform/android/wrappers/jni/androidmediaplayer.cpp platform/android/wrappers/jni/androidmediaplayer_p.h
- platform/android/wrappers/jni/androidmediarecorder.cpp platform/android/wrappers/jni/androidmediarecorder_p.h
- platform/android/wrappers/jni/androidmultimediautils.cpp platform/android/wrappers/jni/androidmultimediautils_p.h
- platform/android/wrappers/jni/androidsurfacetexture.cpp platform/android/wrappers/jni/androidsurfacetexture_p.h
- platform/android/wrappers/jni/androidsurfaceview.cpp platform/android/wrappers/jni/androidsurfaceview_p.h
+ qnx/qqnxaudiodevice.cpp qnx/qqnxaudiodevice_p.h
+ qnx/qqnxaudiosink.cpp qnx/qqnxaudiosink_p.h
+ qnx/qqnxaudiosource.cpp qnx/qqnxaudiosource_p.h
+ qnx/qqnxaudioutils.cpp qnx/qqnxaudioutils_p.h
+ qnx/qqnxmediadevices.cpp qnx/qqnxmediadevices_p.h
INCLUDE_DIRECTORIES
- platform/android/common
- platform/android/mediacapture
- platform/android/mediaplayer
- platform/android/wrappers/jni
- PUBLIC_LIBRARIES
- OpenSLES
- mediandk
-)
-
-qt_internal_extend_target(Multimedia CONDITION WASM
- SOURCES
- platform/wasm/qwasmmediaintegration.cpp platform/wasm/qwasmmediaintegration_p.h
- platform/wasm/qwasmmediadevices.cpp platform/wasm/qwasmmediadevices_p.h
- platform/wasm/audio/qwasmaudiosource.cpp platform/wasm/audio/qwasmaudiosource_p.h
- platform/wasm/audio/qwasmaudiosink.cpp platform/wasm/audio/qwasmaudiosink_p.h
- platform/wasm/audio/qwasmaudiodevice.cpp platform/wasm/audio/qwasmaudiodevice_p.h
- PUBLIC_LIBRARIES
- openal
-)
-
-qt_internal_extend_target(Multimedia CONDITION WIN32
+ qnx
LIBRARIES
- gdi32
- user32
+ asound
)
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT WATCHOS
+qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_wmf
SOURCES
- platform/darwin/audio/avfaudiodecoder.mm platform/darwin/audio/avfaudiodecoder_p.h
- platform/darwin/audio/qdarwinaudiodevice.mm platform/darwin/audio/qdarwinaudiodevice_p.h
- platform/darwin/audio/qdarwinaudiosource.mm platform/darwin/audio/qdarwinaudiosource_p.h
- platform/darwin/audio/qdarwinaudiosink.mm platform/darwin/audio/qdarwinaudiosink_p.h
- platform/darwin/audio/qcoreaudioutils.mm platform/darwin/audio/qcoreaudioutils_p.h
- platform/darwin/mediaplayer/avfdisplaylink.mm platform/darwin/mediaplayer/avfdisplaylink_p.h
- platform/darwin/mediaplayer/avfmediaplayer.mm platform/darwin/mediaplayer/avfmediaplayer_p.h
- platform/darwin/common/avfmetadata.mm platform/darwin/common/avfmetadata_p.h
- platform/darwin/mediaplayer/avfvideorenderercontrol.mm platform/darwin/mediaplayer/avfvideorenderercontrol_p.h
- platform/darwin/avfvideosink.mm platform/darwin/avfvideosink_p.h
- platform/darwin/avfvideobuffer.mm platform/darwin/avfvideobuffer_p.h
- platform/darwin/qdarwinmediadevices.mm platform/darwin/qdarwinmediadevices_p.h
- platform/darwin/qdarwinformatsinfo.mm platform/darwin/qdarwinformatsinfo_p.h
- platform/darwin/qdarwinintegration.mm platform/darwin/qdarwinintegration_p.h
- PUBLIC_LIBRARIES
- ${FWAudioToolbox}
- ${FWCoreAudio}
- ${FWCoreFoundation}
- ${FWCoreMedia}
- ${FWCoreVideo}
- ${FWFoundation}
- ${FWMetal}
- ${FWQuartzCore}
- AVFoundation::AVFoundation
+ windows/qwindowsaudiodevice.cpp windows/qwindowsaudiodevice_p.h
+ windows/qwindowsaudiosource.cpp windows/qwindowsaudiosource_p.h
+ windows/qwindowsaudiosink.cpp windows/qwindowsaudiosink_p.h
+ windows/qwindowsaudioutils.cpp windows/qwindowsaudioutils_p.h
+ windows/qwindowsmediadevices.cpp windows/qwindowsmediadevices_p.h
+ windows/qwindowsmediafoundation.cpp windows/qwindowsmediafoundation_p.h
+ windows/qwindowsresampler.cpp windows/qwindowsresampler_p.h
+ windows/qwindowsmultimediautils.cpp windows/qwindowsmultimediautils_p.h
+ windows/qwindowsmfdefs.cpp windows/qwindowsmfdefs_p.h
+ windows/qcomptr_p.h
+ windows/qcomtaskresource_p.h
+ INCLUDE_DIRECTORIES
+ windows
+ LIBRARIES
+ winmm
+ ksuser
)
-qt_internal_extend_target(Multimedia CONDITION MACOS AND NOT WATCHOS
- PUBLIC_LIBRARIES
- ${FWAppKit}
- ${FWAudioUnit}
+# Only on Windows' MinGW/LLVM build, symbols from `strmif.h` and `ddraw.h` conflicts
+# with symbols defined in `ksmedia.h`.
+qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_wmf AND MINGW
+ NO_UNITY_BUILD_SOURCES
+ windows/qwindowsaudiodevice.cpp windows/qwindowsaudiodevice_p.h
+ windows/qwindowsaudiosource.cpp windows/qwindowsaudiosource_p.h
+ windows/qwindowsaudiosink.cpp windows/qwindowsaudiosink_p.h
+ windows/qwindowsaudioutils.cpp windows/qwindowsaudioutils_p.h
+ windows/qwindowsmediadevices.cpp windows/qwindowsmediadevices_p.h
+ windows/qwindowsmediafoundation.cpp windows/qwindowsmediafoundation_p.h
+ windows/qwindowsresampler.cpp windows/qwindowsresampler_p.h
+ windows/qwindowsmultimediautils.cpp windows/qwindowsmultimediautils_p.h
+ windows/qwindowsmfdefs.cpp windows/qwindowsmfdefs_p.h
+ windows/qcomptr_p.h
+ windows/qcomtaskresource_p.h
)
-qt_internal_extend_target(Multimedia CONDITION IOS AND NOT WATCHOS
+qt_internal_extend_target(Multimedia CONDITION WASM
+ SOURCES
+ wasm/qwasmmediadevices.cpp wasm/qwasmmediadevices_p.h
+ wasm/qwasmaudiosource.cpp wasm/qwasmaudiosource_p.h
+ wasm/qwasmaudiosink.cpp wasm/qwasmaudiosink_p.h
+ wasm/qwasmaudiodevice.cpp wasm/qwasmaudiodevice_p.h
+ INCLUDE_DIRECTORIES
+ wasm
PUBLIC_LIBRARIES
- ${FWCoreGraphics}
- ${FWCoreVideo}
+ openal
+ NO_UNITY_BUILD_SOURCES
+ wasm/qwasmaudiosink.cpp
+ # To avoid collision between symbols defined in wasm/qwasmaudiosource.cpp.
)
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT TVOS AND NOT WATCHOS
- SOURCES
- platform/darwin/camera/avfcamera.mm platform/darwin/camera/avfcamera_p.h
- platform/darwin/camera/avfcameradebug_p.h
- platform/darwin/camera/avfaudiopreviewdelegate.mm platform/darwin/camera/avfaudiopreviewdelegate_p.h
- platform/darwin/camera/avfcamerarenderer.mm platform/darwin/camera/avfcamerarenderer_p.h
- platform/darwin/camera/avfcameraservice.mm platform/darwin/camera/avfcameraservice_p.h
- platform/darwin/camera/avfcamerasession.mm platform/darwin/camera/avfcamerasession_p.h
- platform/darwin/camera/avfcamerautility.mm platform/darwin/camera/avfcamerautility_p.h
- platform/darwin/camera/avfimagecapture.mm platform/darwin/camera/avfimagecapture_p.h
+set(VIDEO_VERTEX_SHADERS
+ "shaders/vertex.vert"
+ "shaders/externalsampler.vert"
)
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT TVOS AND NOT WATCHOS
- SOURCES
- platform/darwin/camera/avfmediaassetwriter.mm platform/darwin/camera/avfmediaassetwriter_p.h
- platform/darwin/camera/avfmediaencoder.mm platform/darwin/camera/avfmediaencoder_p.h
+set(VIDEO_SHADERS
+ "shaders/externalsampler.frag@glsl,100es,shaders/externalsampler_gles.frag"
+ "shaders/abgr.frag"
+ "shaders/argb.frag"
+ "shaders/rgba.frag"
+ "shaders/bgra.frag"
+ "shaders/y.frag"
+ "shaders/nv12.frag"
+ "shaders/nv21.frag"
+ "shaders/imc2.frag"
+ "shaders/imc4.frag"
+ "shaders/uyvy.frag"
+ "shaders/yuv_triplanar.frag"
+ "shaders/yuv_triplanar_p10.frag"
+ "shaders/yvu_triplanar.frag"
+ "shaders/yuyv.frag"
+ "shaders/ayuv.frag"
+ "shaders/nv12_bt2020_pq.frag"
+ "shaders/nv12_bt2020_hlg.frag"
)
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT WATCHOS AND (IOS OR TVOS)
- SOURCES
- platform/darwin/audio/qcoreaudiosessionmanager.mm platform/darwin/audio/qcoreaudiosessionmanager_p.h
- PUBLIC_LIBRARIES
- ${FWAVFoundation}
- ${FWFoundation}
+qt_internal_add_shaders(Multimedia "qtmultimedia_shaders"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ "/qt-project.org/multimedia"
+ FILES
+ ${VIDEO_VERTEX_SHADERS}
+ ${VIDEO_SHADERS}
)
-qt_internal_extend_target(Multimedia CONDITION APPLE AND NOT IOS AND NOT TVOS AND NOT WATCHOS
- PUBLIC_LIBRARIES
- ${FWAppKit}
- ${FWApplicationServices}
- ${FWAudioUnit}
-)
+string(REPLACE ".frag" "_linear.frag.qsb" LINEAR_VIDEO_SHADERS "${VIDEO_SHADERS}")
-qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_mmrenderer
- SOURCES
- platform/qnx/audio/neutrinoserviceplugin.cpp platform/qnx/audio/neutrinoserviceplugin_p.h
- platform/qnx/audio/qqnxaudiodevice.cpp platform/qnx/audio/qqnxaudiodevice_p.h
- platform/qnx/audio/qqnxaudiosource.cpp platform/qnx/audio/qqnxaudiosource_p.h
- platform/qnx/audio/qqnxaudiosink.cpp platform/qnx/audio/qqnxaudiosink_p.h
- platform/qnx/audio/qnxaudioutils.cpp platform/qnx/audio/qnxaudioutils_p.h
- platform/qnx/camera/bbcameraaudioencodersettingscontrol.cpp platform/qnx/camera/bbcameraaudioencodersettingscontrol_p.h
- platform/qnx/camera/bbcameracontrol.cpp platform/qnx/camera/bbcameracontrol_p.h
- platform/qnx/camera/bbcameraexposurecontrol.cpp platform/qnx/camera/bbcameraexposurecontrol_p.h
- platform/qnx/camera/bbcamerafocuscontrol.cpp platform/qnx/camera/bbcamerafocuscontrol_p.h
- platform/qnx/camera/bbcameraimagecapturecontrol.cpp platform/qnx/camera/bbcameraimagecapturecontrol_p.h
- platform/qnx/camera/bbcameraimageprocessingcontrol.cpp platform/qnx/camera/bbcameraimageprocessingcontrol_p.h
- platform/qnx/camera/bbcameramediarecordercontrol.cpp platform/qnx/camera/bbcameramediarecordercontrol_p.h
- platform/qnx/camera/bbcameraorientatio_p.handler.cpp platform/qnx/camera/bbcameraorientatio_p.handler.h
- platform/qnx/camera/bbcameraservice.cpp platform/qnx/camera/bbcameraservice_p.h
- platform/qnx/camera/bbcamerasession.cpp platform/qnx/camera/bbcamerasession_p.h
- platform/qnx/camera/bbcameravideoencodersettingscontrol.cpp platform/qnx/camera/bbcameravideoencodersettingscontrol_p.h
- platform/qnx/camera/bbvideorenderercontrol.cpp platform/qnx/camera/bbvideorenderercontrol_p.h
- platform/qnx/common/windowgrabber.cpp platform/qnx/common/windowgrabber_p.h
- platform/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp platform/qnx/mediaplayer/mmrenderermediaplayercontrol_p.h
- platform/qnx/mediaplayer/mmrenderermetadata.cpp platform/qnx/mediaplayer/mmrenderermetadata_p.h
- platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol_p.h
- platform/qnx/mediaplayer/mmrendererutil.cpp platform/qnx/mediaplayer/mmrendererutil_p.h
- platform/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp platform/qnx/mediaplayer/mmrenderervideowindowcontrol_p.h
- platform/qnx/mediaplayer/mmrevent_p.hread.cpp platform/qnx/mediaplayer/mmrevent_p.hread.h
- platform/qnx/mediaplayer/mmreventmediaplayercontrol.cpp platform/qnx/mediaplayer/mmreventmediaplayercontrol_p.h
- platform/qnx/qqnxmediadevices.cpp platform/qnx/qqnxmediadevices_p.h
- platform/qnx/qqnxintegration.cpp platform/qnx/qqnxintegration_p.h
- INCLUDE_DIRECTORIES
- platform/qnx/camera
- platform/qnx/common
- platform/qnx/mediaplayer
- PUBLIC_LIBRARIES
- MMRenderer::MMRenderer
- asound
- audio_manager
- camapi
-)
-qt_internal_add_docs(Multimedia
- doc/qtmultimedia.qdocconf
+qt_internal_add_shaders(Multimedia "qtmultimedia_shaders_linear"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ "/qt-project.org/multimedia"
+ FILES
+ ${VIDEO_SHADERS}
+ OUTPUTS
+ ${LINEAR_VIDEO_SHADERS}
+ DEFINES
+ QMM_OUTPUTSURFACE_LINEAR
)
-qt_internal_add_shaders(Multimedia "shaders"
+qt_internal_add_shaders(Multimedia "qtmultimedia_shaders_gl_macos"
SILENT
BATCHABLE
PRECOMPILE
OPTIMIZED
PREFIX
"/qt-project.org/multimedia"
+ GLSL
+ "120,150"
+ NOHLSL
+ NOMSL
FILES
- "shaders/vertex.vert"
- "shaders/externalsampler.vert"
- "shaders/externalsampler.frag@glsl,100es,shaders/externalsampler_gles.frag"
- "shaders/abgr.frag"
- "shaders/argb.frag"
- "shaders/bgra.frag"
- "shaders/rgba.frag"
- "shaders/y.frag"
- "shaders/nv12.frag"
- "shaders/nv21.frag"
- "shaders/imc2.frag"
- "shaders/imc4.frag"
- "shaders/uyvy.frag"
- "shaders/yuv_triplanar.frag"
- "shaders/yvu_triplanar.frag"
- "shaders/yuyv.frag"
- "shaders/ayuv.frag"
+ "shaders/rectsampler.vert"
+ "shaders/rectsampler_bgra.frag"
)
-qt_internal_add_shaders(Multimedia "shaders_gl_macos"
+qt_internal_add_shaders(Multimedia "qtmultimedia_shaders_gl_macos_linear"
SILENT
BATCHABLE
PRECOMPILE
@@ -500,6 +350,12 @@ qt_internal_add_shaders(Multimedia "shaders_gl_macos"
NOHLSL
NOMSL
FILES
- "shaders/rectsampler.vert"
"shaders/rectsampler_bgra.frag"
+ OUTPUTS
+ "shaders/rectsampler_bgra_linear.frag.qsb"
)
+
+if (DEFINED QT_DEFAULT_MEDIA_BACKEND)
+ target_compile_definitions(Multimedia
+ PRIVATE QT_DEFAULT_MEDIA_BACKEND="${QT_DEFAULT_MEDIA_BACKEND}")
+endif()
diff --git a/src/multimedia/alsa/alsa.json b/src/multimedia/alsa/alsa.json
new file mode 100644
index 000000000..71abb213c
--- /dev/null
+++ b/src/multimedia/alsa/alsa.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "alsa" ]
+}
diff --git a/src/multimedia/platform/alsa/qalsaaudiodevice.cpp b/src/multimedia/alsa/qalsaaudiodevice.cpp
index ed0aa0030..f5d4a2209 100644
--- a/src/multimedia/platform/alsa/qalsaaudiodevice.cpp
+++ b/src/multimedia/alsa/qalsaaudiodevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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
@@ -74,6 +38,10 @@ QAlsaAudioDeviceInfo::QAlsaAudioDeviceInfo(const QByteArray &dev, const QString
maximumSampleRate = 48000;
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()
diff --git a/src/multimedia/alsa/qalsaaudiodevice_p.h b/src/multimedia/alsa/qalsaaudiodevice_p.h
new file mode 100644
index 000000000..f82ea4f5a
--- /dev/null
+++ b/src/multimedia/alsa/qalsaaudiodevice_p.h
@@ -0,0 +1,49 @@
+// 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 QALSAAUDIODEVICEINFO_H
+#define QALSAAUDIODEVICEINFO_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <private/qaudiodevice_p.h>
+#include <private/qaudiosystem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QAlsaAudioDeviceInfo : public QAudioDevicePrivate
+{
+public:
+ QAlsaAudioDeviceInfo(const QByteArray &dev, const QString &description, QAudioDevice::Mode mode);
+ ~QAlsaAudioDeviceInfo();
+
+private:
+ void checkSurround();
+ bool surround40;
+ bool surround51;
+ bool surround71;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QALSAAUDIODEVICEINFO_H
diff --git a/src/multimedia/platform/alsa/qalsaaudiosink.cpp b/src/multimedia/alsa/qalsaaudiosink.cpp
index 7157e9508..98a68861f 100644
--- a/src/multimedia/platform/alsa/qalsaaudiosink.cpp
+++ b/src/multimedia/alsa/qalsaaudiosink.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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
@@ -57,36 +21,16 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcAlsaOutput, "qt.multimedia.alsa.output")
+static Q_LOGGING_CATEGORY(lcAlsaOutput, "qt.multimedia.alsa.output")
//#define DEBUG_AUDIO 1
-QAlsaAudioSink::QAlsaAudioSink(const QByteArray &device)
+QAlsaAudioSink::QAlsaAudioSink(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSink(parent)
{
- bytesAvailable = 0;
- handle = 0;
- access = SND_PCM_ACCESS_RW_INTERLEAVED;
- pcmformat = SND_PCM_FORMAT_S16;
- buffer_frames = 0;
- period_frames = 0;
- buffer_size = 0;
- period_size = 0;
- buffer_time = 100000;
- period_time = 20000;
- totalTimeValue = 0;
- audioBuffer = 0;
- errorState = QAudio::NoError;
- deviceState = QAudio::StoppedState;
- audioSource = 0;
- pullMode = true;
- resuming = false;
- opened = false;
-
- m_volume = 1.0f;
-
m_device = device;
timer = new QTimer(this);
- connect(timer,SIGNAL(timeout()),SLOT(userFeed()));
+ connect(timer, SIGNAL(timeout()), this, SLOT(userFeed()));
}
QAlsaAudioSink::~QAlsaAudioSink()
@@ -171,21 +115,21 @@ int QAlsaAudioSink::setFormat()
break;
case QAudioFormat::Int16:
if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- pcmformat = SND_PCM_FORMAT_S16_LE;
- else
pcmformat = SND_PCM_FORMAT_S16_BE;
+ else
+ pcmformat = SND_PCM_FORMAT_S16_LE;
break;
case QAudioFormat::Int32:
if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- pcmformat = SND_PCM_FORMAT_S32_LE;
- else
pcmformat = SND_PCM_FORMAT_S32_BE;
+ else
+ pcmformat = SND_PCM_FORMAT_S32_LE;
break;
case QAudioFormat::Float:
if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- pcmformat = SND_PCM_FORMAT_FLOAT_LE;
- else
pcmformat = SND_PCM_FORMAT_FLOAT_BE;
+ else
+ pcmformat = SND_PCM_FORMAT_FLOAT_LE;
default:
break;
}
@@ -213,6 +157,11 @@ void QAlsaAudioSink::start(QIODevice* device)
pullMode = true;
audioSource = device;
+ connect(audioSource, &QIODevice::readyRead, timer, [this] {
+ if (!timer->isActive()) {
+ timer->start(period_time / 1000);
+ }
+ });
deviceState = QAudio::ActiveState;
open();
@@ -267,13 +216,12 @@ bool QAlsaAudioSink::open()
QTime now(QTime::currentTime());
qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
#endif
- timeStamp.restart();
elapsedTimeOffset = 0;
int dir;
int err = 0;
int count=0;
- unsigned int sampleRate=settings.sampleRate();
+ unsigned int sampleRate = settings.sampleRate();
if (!settings.isValid()) {
qWarning("QAudioSink: open error, invalid format.");
@@ -451,7 +399,6 @@ bool QAlsaAudioSink::open()
// Step 6: Start audio processing
timer->start(period_time/1000);
- timeStamp.restart();
elapsedTimeOffset = 0;
errorState = QAudio::NoError;
totalTimeValue = 0;
@@ -588,8 +535,7 @@ void QAlsaAudioSink::resume()
}
resuming = true;
- deviceState = pullMode ? QAudio::ActiveState : QAudio::IdleState;
-
+ deviceState = suspendedInState;
errorState = QAudio::NoError;
timer->start(period_time/1000);
emit stateChanged(deviceState);
@@ -598,8 +544,7 @@ void QAlsaAudioSink::resume()
void QAlsaAudioSink::setFormat(const QAudioFormat& fmt)
{
- if (deviceState == QAudio::StoppedState)
- settings = fmt;
+ settings = fmt;
}
QAudioFormat QAlsaAudioSink::format() const
@@ -610,6 +555,7 @@ QAudioFormat QAlsaAudioSink::format() const
void QAlsaAudioSink::suspend()
{
if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) {
+ suspendedInState = deviceState;
snd_pcm_drain(handle);
timer->stop();
deviceState = QAudio::SuspendedState;
@@ -665,11 +611,13 @@ bool QAlsaAudioSink::deviceReady()
} else if(l == 0) {
// Did not get any data to output
+ timer->stop();
+ snd_pcm_drain(handle);
bytesAvailable = bytesFree();
if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
// Underrun
if (deviceState != QAudio::IdleState) {
- errorState = QAudio::UnderrunError;
+ errorState = audioSource->atEnd() ? QAudio::NoError : QAudio::UnderrunError;
emit errorChanged(errorState);
deviceState = QAudio::IdleState;
emit stateChanged(deviceState);
diff --git a/src/multimedia/alsa/qalsaaudiosink_p.h b/src/multimedia/alsa/qalsaaudiosink_p.h
new file mode 100644
index 000000000..7e8836f96
--- /dev/null
+++ b/src/multimedia/alsa/qalsaaudiosink_p.h
@@ -0,0 +1,122 @@
+// 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 QAUDIOOUTPUTALSA_H
+#define QAUDIOOUTPUTALSA_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qiodevice.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodevice.h>
+#include <private/qaudiosystem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAlsaAudioSink : public QPlatformAudioSink
+{
+ friend class AlsaOutputPrivate;
+ Q_OBJECT
+public:
+ QAlsaAudioSink(const QByteArray &device, QObject *parent);
+ ~QAlsaAudioSink();
+
+ qint64 write( const char *data, qint64 len );
+
+ 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& fmt) override;
+ QAudioFormat format() const override;
+ void setVolume(qreal) override;
+ qreal volume() const override;
+
+
+ QIODevice* audioSource = nullptr;
+ QAudioFormat settings;
+ QAudio::Error errorState = QAudio::NoError;
+ QAudio::State deviceState = QAudio::StoppedState;
+ QAudio::State suspendedInState = QAudio::SuspendedState;
+
+private slots:
+ void userFeed();
+ bool deviceReady();
+
+signals:
+ void processMore();
+
+private:
+ bool opened = false;
+ bool pullMode = true;
+ bool resuming = false;
+ int buffer_size = 0;
+ int period_size = 0;
+ qint64 totalTimeValue = 0;
+ unsigned int buffer_time = 100000;
+ unsigned int period_time = 20000;
+ snd_pcm_uframes_t buffer_frames;
+ snd_pcm_uframes_t period_frames;
+ int xrun_recovery(int err);
+
+ int setFormat();
+ bool open();
+ void close();
+
+ QTimer* timer = nullptr;
+ QByteArray m_device;
+ int bytesAvailable = 0;
+ qint64 elapsedTimeOffset = 0;
+ char* audioBuffer = nullptr;
+ snd_pcm_t* handle = nullptr;
+ snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ snd_pcm_format_t pcmformat = SND_PCM_FORMAT_S16;
+ snd_pcm_hw_params_t *hwparams = nullptr;
+ qreal m_volume = 1.0f;
+};
+
+class AlsaOutputPrivate : public QIODevice
+{
+ friend class QAlsaAudioSink;
+ Q_OBJECT
+public:
+ AlsaOutputPrivate(QAlsaAudioSink* audio);
+ ~AlsaOutputPrivate();
+
+ qint64 readData( char* data, qint64 len) override;
+ qint64 writeData(const char* data, qint64 len) override;
+
+private:
+ QAlsaAudioSink *audioDevice;
+};
+
+QT_END_NAMESPACE
+
+
+#endif
diff --git a/src/multimedia/platform/alsa/qalsaaudiosource.cpp b/src/multimedia/alsa/qalsaaudiosource.cpp
index 19c85542e..ce099463d 100644
--- a/src/multimedia/platform/alsa/qalsaaudiosource.cpp
+++ b/src/multimedia/alsa/qalsaaudiosource.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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
@@ -58,7 +22,8 @@ QT_BEGIN_NAMESPACE
//#define DEBUG_AUDIO 1
-QAlsaAudioSource::QAlsaAudioSource(const QByteArray &device)
+QAlsaAudioSource::QAlsaAudioSource(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSource(parent)
{
bytesAvailable = 0;
handle = 0;
@@ -80,7 +45,7 @@ QAlsaAudioSource::QAlsaAudioSource(const QByteArray &device)
m_device = device;
timer = new QTimer(this);
- connect(timer,SIGNAL(timeout()),SLOT(userFeed()));
+ connect(timer, SIGNAL(timeout()), this, SLOT(userFeed()));
}
QAlsaAudioSource::~QAlsaAudioSource()
@@ -449,7 +414,7 @@ int QAlsaAudioSource::checkBytesReady()
return bytesAvailable;
}
-int QAlsaAudioSource::bytesReady() const
+qsizetype QAlsaAudioSource::bytesReady() const
{
return qMax(bytesAvailable, 0);
}
@@ -623,12 +588,12 @@ void QAlsaAudioSource::resume()
}
}
-void QAlsaAudioSource::setBufferSize(int value)
+void QAlsaAudioSource::setBufferSize(qsizetype value)
{
buffer_size = value;
}
-int QAlsaAudioSource::bufferSize() const
+qsizetype QAlsaAudioSource::bufferSize() const
{
return buffer_size;
}
diff --git a/src/multimedia/platform/alsa/qalsaaudiosource_p.h b/src/multimedia/alsa/qalsaaudiosource_p.h
index 95df8008b..87487a6ad 100644
--- a/src/multimedia/platform/alsa/qalsaaudiosource_p.h
+++ b/src/multimedia/alsa/qalsaaudiosource_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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
@@ -98,7 +62,7 @@ class QAlsaAudioSource : public QPlatformAudioSource
{
Q_OBJECT
public:
- QAlsaAudioSource(const QByteArray &device);
+ QAlsaAudioSource(const QByteArray &device, QObject *parent);
~QAlsaAudioSource();
qint64 read(char* data, qint64 len);
@@ -142,10 +106,10 @@ private:
QTimer* timer;
qint64 elapsedTimeOffset;
RingBuffer ringBuffer;
- int bytesAvailable;
+ qsizetype bytesAvailable;
QByteArray m_device;
bool pullMode;
- int buffer_size;
+ qsizetype buffer_size;
int period_size;
unsigned int buffer_time;
unsigned int period_time;
diff --git a/src/multimedia/alsa/qalsamediadevices.cpp b/src/multimedia/alsa/qalsamediadevices.cpp
new file mode 100644
index 000000000..5a133e9d1
--- /dev/null
+++ b/src/multimedia/alsa/qalsamediadevices.cpp
@@ -0,0 +1,108 @@
+// 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 "qalsamediadevices_p.h"
+#include "qmediadevices.h"
+#include "qcameradevice_p.h"
+
+#include "private/qalsaaudiosource_p.h"
+#include "private/qalsaaudiosink_p.h"
+#include "private/qalsaaudiodevice_p.h"
+
+#include <alsa/asoundlib.h>
+
+QT_BEGIN_NAMESPACE
+
+QAlsaMediaDevices::QAlsaMediaDevices()
+ : QPlatformMediaDevices()
+{
+}
+
+static QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode)
+{
+ QList<QAudioDevice> devices;
+
+ QByteArray filter;
+
+ // Create a list of all current audio devices that support mode
+ void **hints, **n;
+ char *name, *descr, *io;
+ bool hasDefault = false;
+
+ if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
+ qWarning() << "no alsa devices available";
+ return devices;
+ }
+ n = hints;
+
+ if(mode == QAudioDevice::Input) {
+ filter = "Input";
+ } else {
+ filter = "Output";
+ }
+
+ QAlsaAudioDeviceInfo* sysdefault = nullptr;
+
+ while (*n != NULL) {
+ name = snd_device_name_get_hint(*n, "NAME");
+ if (name != 0 && qstrcmp(name, "null") != 0) {
+ descr = snd_device_name_get_hint(*n, "DESC");
+ io = snd_device_name_get_hint(*n, "IOID");
+
+ if ((descr != NULL) && ((io == NULL) || (io == filter))) {
+ auto *infop = new QAlsaAudioDeviceInfo(name, QString::fromUtf8(descr), mode);
+ devices.append(infop->create());
+ if (!hasDefault && strcmp(name, "default") == 0) {
+ infop->isDefault = true;
+ hasDefault = true;
+ }
+ else if (!sysdefault && !hasDefault && strcmp(name, "sysdefault") == 0) {
+ sysdefault = infop;
+ }
+ }
+
+ free(descr);
+ free(io);
+ }
+ free(name);
+ ++n;
+ }
+ snd_device_name_free_hint(hints);
+
+ if (!hasDefault && sysdefault) {
+ // Make "sysdefault" the default device if there is no "default" device exists
+ sysdefault->isDefault = true;
+ hasDefault = true;
+ }
+ if (!hasDefault && devices.size() > 0) {
+ auto infop = new QAlsaAudioDeviceInfo("default", QString(), QAudioDevice::Output);
+ infop->isDefault = true;
+ devices.prepend(infop->create());
+ }
+
+ return devices;
+}
+
+QList<QAudioDevice> QAlsaMediaDevices::audioInputs() const
+{
+ return availableDevices(QAudioDevice::Input);
+}
+
+QList<QAudioDevice> QAlsaMediaDevices::audioOutputs() const
+{
+ return availableDevices(QAudioDevice::Output);
+}
+
+QPlatformAudioSource *QAlsaMediaDevices::createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QAlsaAudioSource(deviceInfo.id(), parent);
+}
+
+QPlatformAudioSink *QAlsaMediaDevices::createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QAlsaAudioSink(deviceInfo.id(), parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/alsa/qalsamediadevices_p.h b/src/multimedia/alsa/qalsamediadevices_p.h
new file mode 100644
index 000000000..d9fbb7c97
--- /dev/null
+++ b/src/multimedia/alsa/qalsamediadevices_p.h
@@ -0,0 +1,41 @@
+// 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
+
+#ifndef QALSAMEDIADEVICES_H
+#define QALSAMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+#include <qset.h>
+#include <qaudio.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAlsaEngine;
+
+class QAlsaMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QAlsaMediaDevices();
+
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/android/qandroidaudiodevice.cpp b/src/multimedia/android/qandroidaudiodevice.cpp
new file mode 100644
index 000000000..576774fd8
--- /dev/null
+++ b/src/multimedia/android/qandroidaudiodevice.cpp
@@ -0,0 +1,39 @@
+// 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 "qandroidaudiodevice_p.h"
+
+#include "qopenslesengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QOpenSLESDeviceInfo::QOpenSLESDeviceInfo(const QByteArray &device, const QString &desc, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(device, mode),
+ m_engine(QOpenSLESEngine::instance())
+{
+ description = desc;
+
+ auto channels = m_engine->supportedChannelCounts(mode);
+ if (channels.size()) {
+ minimumChannelCount = channels.first();
+ maximumChannelCount = channels.last();
+ }
+
+ auto sampleRates = m_engine->supportedSampleRates(mode);
+ if (sampleRates.size()) {
+ minimumSampleRate = sampleRates.first();
+ maximumSampleRate = sampleRates.last();
+ }
+ if (mode == QAudioDevice::Input)
+ supportedSampleFormats.append(QAudioFormat::UInt8);
+ supportedSampleFormats.append(QAudioFormat::Int16);
+
+ preferredFormat.setChannelCount(2);
+ preferredFormat.setSampleRate(48000);
+ QAudioFormat::SampleFormat f = QAudioFormat::Int16;
+ if (!supportedSampleFormats.contains(f))
+ f = supportedSampleFormats.value(0, QAudioFormat::Unknown);
+ preferredFormat.setSampleFormat(f);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/android/qandroidaudiodevice_p.h b/src/multimedia/android/qandroidaudiodevice_p.h
new file mode 100644
index 000000000..d448306fe
--- /dev/null
+++ b/src/multimedia/android/qandroidaudiodevice_p.h
@@ -0,0 +1,37 @@
+// 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 QOPENSLESDEVICEINFO_H
+#define QOPENSLESDEVICEINFO_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qaudiosystem_p.h>
+#include <private/qaudiodevice_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenSLESEngine;
+
+class QOpenSLESDeviceInfo : public QAudioDevicePrivate
+{
+public:
+ QOpenSLESDeviceInfo(const QByteArray &device, const QString &desc, QAudioDevice::Mode mode);
+ ~QOpenSLESDeviceInfo() {}
+
+private:
+ QOpenSLESEngine *m_engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENSLESDEVICEINFO_H
diff --git a/src/multimedia/platform/android/audio/qandroidaudiosink.cpp b/src/multimedia/android/qandroidaudiosink.cpp
index 1a0b622a3..4da4c5fdc 100644
--- a/src/multimedia/platform/android/audio/qandroidaudiosink.cpp
+++ b/src/multimedia/android/qandroidaudiosink.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qandroidaudiosink_p.h"
#include "qopenslesengine_p.h"
@@ -48,8 +12,6 @@
#include <SLES/OpenSLES_AndroidConfiguration.h>
#endif // ANDROID
-#define BUFFER_COUNT 2
-
QT_BEGIN_NAMESPACE
static inline void openSlDebugInfo()
@@ -64,26 +26,9 @@ static inline void openSlDebugInfo()
<< "\nDefault buffer size: " << QOpenSLESEngine::getDefaultBufferSize(format);
}
-QAndroidAudioSink::QAndroidAudioSink(const QByteArray &device)
- : m_deviceName(device),
- m_state(QAudio::StoppedState),
- m_error(QAudio::NoError),
- m_outputMixObject(nullptr),
- m_playerObject(nullptr),
- m_playItf(nullptr),
- m_volumeItf(nullptr),
- m_bufferQueueItf(nullptr),
- m_audioSource(nullptr),
- m_buffers(nullptr),
- m_volume(1.0),
- m_pullMode(false),
- m_nextBuffer(0),
- m_bufferSize(0),
- m_elapsedTime(0),
- m_processedBytes(0),
- m_availableBuffers(BUFFER_COUNT),
- m_eventMask(SL_PLAYEVENT_HEADATEND),
- m_startRequiresInit(true)
+QAndroidAudioSink::QAndroidAudioSink(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSink(parent),
+ m_deviceName(device)
{
#ifndef ANDROID
m_streamType = -1;
@@ -117,16 +62,17 @@ void QAndroidAudioSink::start(QIODevice *device)
if (!preparePlayer())
return;
+ m_endSound = false;
m_pullMode = true;
m_audioSource = device;
m_nextBuffer = 0;
m_processedBytes = 0;
- m_availableBuffers = BUFFER_COUNT;
+ m_availableBuffers = BufferCount;
setState(QAudio::ActiveState);
setError(QAudio::NoError);
// Attempt to fill buffers first.
- for (int i = 0; i != BUFFER_COUNT; ++i) {
+ for (int i = 0; i != BufferCount; ++i) {
const int index = i * m_bufferSize;
const qint64 readSize = m_audioSource->read(m_buffers + index, m_bufferSize);
if (readSize && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
@@ -145,6 +91,16 @@ void QAndroidAudioSink::start(QIODevice *device)
// Change the state to playing.
// We need to do this after filling the buffers or processedBytes might get corrupted.
startPlayer();
+ connect(m_audioSource, &QIODevice::readyRead, this, &QAndroidAudioSink::readyRead);
+}
+
+void QAndroidAudioSink::readyRead()
+{
+ if (m_pullMode && m_state == QAudio::IdleState) {
+ setState(QAudio::ActiveState);
+ setError(QAudio::NoError);
+ QMetaObject::invokeMethod(this, "bufferAvailable", Qt::QueuedConnection);
+ }
}
QIODevice *QAndroidAudioSink::start()
@@ -157,7 +113,7 @@ QIODevice *QAndroidAudioSink::start()
m_pullMode = false;
m_processedBytes = 0;
- m_availableBuffers = BUFFER_COUNT;
+ m_availableBuffers = BufferCount;
m_audioSource = new SLIODevicePrivate(this);
m_audioSource->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
@@ -222,7 +178,7 @@ void QAndroidAudioSink::resume()
return;
}
- setState(m_pullMode ? QAudio::ActiveState : QAudio::IdleState);
+ setState(m_suspendedInState);
setError(QAudio::NoError);
}
@@ -248,6 +204,7 @@ void QAndroidAudioSink::suspend()
return;
}
+ m_suspendedInState = m_state;
setState(QAudio::SuspendedState);
setError(QAudio::NoError);
}
@@ -291,18 +248,15 @@ void QAndroidAudioSink::onBytesProcessed(qint64 bytes)
m_processedBytes += bytes;
}
-void QAndroidAudioSink::bufferAvailable(quint32 count, quint32 playIndex)
+void QAndroidAudioSink::bufferAvailable()
{
- Q_UNUSED(count);
- Q_UNUSED(playIndex);
-
if (m_state == QAudio::StoppedState)
return;
if (!m_pullMode) { // We're in push mode.
// Signal that there is a new open slot in the buffer and return
const int val = m_availableBuffers.fetchAndAddRelease(1) + 1;
- if (val == BUFFER_COUNT)
+ if (val == BufferCount)
QMetaObject::invokeMethod(this, "onEOSEvent", Qt::QueuedConnection);
return;
@@ -310,7 +264,23 @@ void QAndroidAudioSink::bufferAvailable(quint32 count, quint32 playIndex)
// We're in pull mode.
const int index = m_nextBuffer * m_bufferSize;
- const qint64 readSize = m_audioSource->read(m_buffers + index, m_bufferSize);
+ qint64 readSize = 0;
+ if (m_audioSource->atEnd()) {
+ // The whole sound was passed to player buffer, but setting SL_PLAYSTATE_STOPPED state
+ // too quickly will result in cutting of end of the sound. Therefore, we make it a little
+ // longer with empty data to make sure they will be played correctly
+ if (m_endSound) {
+ m_endSound = false;
+ setState(QAudio::IdleState);
+ return;
+ }
+ m_endSound = true;
+ readSize = m_bufferSize;
+ memset(m_buffers + index, 0, readSize);
+ } else {
+ readSize = m_audioSource->read(m_buffers + index, m_bufferSize);
+ }
+
if (readSize < 1) {
QMetaObject::invokeMethod(this, "onEOSEvent", Qt::QueuedConnection);
@@ -326,8 +296,10 @@ void QAndroidAudioSink::bufferAvailable(quint32 count, quint32 playIndex)
return;
}
- m_nextBuffer = (m_nextBuffer + 1) % BUFFER_COUNT;
- QMetaObject::invokeMethod(this, "onBytesProcessed", Qt::QueuedConnection, Q_ARG(qint64, readSize));
+ m_nextBuffer = (m_nextBuffer + 1) % BufferCount;
+ if (!m_endSound) {
+ QMetaObject::invokeMethod(this, "onBytesProcessed", Qt::QueuedConnection, Q_ARG(qint64, readSize));
+ }
}
void QAndroidAudioSink::playCallback(SLPlayItf player, void *ctx, SLuint32 event)
@@ -340,10 +312,9 @@ void QAndroidAudioSink::playCallback(SLPlayItf player, void *ctx, SLuint32 event
void QAndroidAudioSink::bufferQueueCallback(SLBufferQueueItf bufferQueue, void *ctx)
{
- SLBufferQueueState state;
- (*bufferQueue)->GetState(bufferQueue, &state);
+ Q_UNUSED(bufferQueue);
QAndroidAudioSink *audioOutput = reinterpret_cast<QAndroidAudioSink *>(ctx);
- audioOutput->bufferAvailable(state.count, state.playIndex);
+ QMetaObject::invokeMethod(audioOutput, "bufferAvailable", Qt::QueuedConnection);
}
bool QAndroidAudioSink::preparePlayer()
@@ -353,6 +324,9 @@ bool QAndroidAudioSink::preparePlayer()
else
return true;
+ if (!QOpenSLESEngine::setAudioOutput(m_deviceName))
+ qWarning() << "Unable to set up Audio Output Device";
+
SLEngineItf engine = QOpenSLESEngine::instance()->slEngine();
if (!engine) {
qWarning() << "No engine";
@@ -360,8 +334,8 @@ bool QAndroidAudioSink::preparePlayer()
return false;
}
- SLDataLocator_BufferQueue bufferQueueLocator = { SL_DATALOCATOR_BUFFERQUEUE, BUFFER_COUNT };
- SLDataFormat_PCM pcmFormat = QOpenSLESEngine::audioFormatToSLFormatPCM(m_format);
+ SLDataLocator_BufferQueue bufferQueueLocator = { SL_DATALOCATOR_BUFFERQUEUE, BufferCount };
+ SLAndroidDataFormat_PCM_EX pcmFormat = QOpenSLESEngine::audioFormatToSLFormatPCM(m_format);
SLDataSource audioSrc = { &bufferQueueLocator, &pcmFormat };
@@ -492,7 +466,7 @@ bool QAndroidAudioSink::preparePlayer()
}
if (!m_buffers)
- m_buffers = new char[BUFFER_COUNT * m_bufferSize];
+ m_buffers = new char[BufferCount * m_bufferSize];
setError(QAudio::NoError);
m_startRequiresInit = false;
@@ -525,7 +499,7 @@ void QAndroidAudioSink::destroyPlayer()
m_buffers = nullptr;
m_processedBytes = 0;
m_nextBuffer = 0;
- m_availableBuffers.storeRelease(BUFFER_COUNT);
+ m_availableBuffers.storeRelease(BufferCount);
m_playItf = nullptr;
m_volumeItf = nullptr;
m_bufferQueueItf = nullptr;
@@ -536,10 +510,14 @@ void QAndroidAudioSink::stopPlayer()
{
setState(QAudio::StoppedState);
- if (m_audioSource && !m_pullMode) {
- m_audioSource->close();
- delete m_audioSource;
- m_audioSource = nullptr;
+ if (m_audioSource) {
+ if (m_pullMode) {
+ disconnect(m_audioSource, &QIODevice::readyRead, this, &QAndroidAudioSink::readyRead);
+ } else {
+ m_audioSource->close();
+ delete m_audioSource;
+ m_audioSource = nullptr;
+ }
}
// We need to change the state manually...
@@ -599,7 +577,7 @@ qint64 QAndroidAudioSink::writeData(const char *data, qint64 len)
m_processedBytes += len;
setState(QAudio::ActiveState);
setError(QAudio::NoError);
- m_nextBuffer = (m_nextBuffer + 1) % BUFFER_COUNT;
+ m_nextBuffer = (m_nextBuffer + 1) % BufferCount;
return len;
}
diff --git a/src/multimedia/android/qandroidaudiosink_p.h b/src/multimedia/android/qandroidaudiosink_p.h
new file mode 100644
index 000000000..4cb63b252
--- /dev/null
+++ b/src/multimedia/android/qandroidaudiosink_p.h
@@ -0,0 +1,127 @@
+// 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 QOPENSLESAUDIOOUTPUT_H
+#define QOPENSLESAUDIOOUTPUT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qaudiosystem_p.h>
+#include <SLES/OpenSLES.h>
+#include <qbytearray.h>
+#include <qmap.h>
+#include <QElapsedTimer>
+#include <QIODevice>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidAudioSink : public QPlatformAudioSink
+{
+ Q_OBJECT
+
+public:
+ QAndroidAudioSink(const QByteArray &device, QObject *parent);
+ ~QAndroidAudioSink();
+
+ 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:
+ friend class SLIODevicePrivate;
+
+ Q_INVOKABLE void onEOSEvent();
+ Q_INVOKABLE void onBytesProcessed(qint64 bytes);
+ Q_INVOKABLE void bufferAvailable();
+
+ static void playCallback(SLPlayItf playItf, void *ctx, SLuint32 event);
+ static void bufferQueueCallback(SLBufferQueueItf bufferQueue, void *ctx);
+
+ bool preparePlayer();
+ void destroyPlayer();
+ void stopPlayer();
+ void readyRead();
+ void startPlayer();
+ qint64 writeData(const char *data, qint64 len);
+
+ void setState(QAudio::State state);
+ void setError(QAudio::Error error);
+
+ SLmillibel adjustVolume(qreal vol);
+
+ static constexpr int BufferCount = 2;
+
+ QByteArray m_deviceName;
+ QAudio::State m_state = QAudio::StoppedState;
+ QAudio::State m_suspendedInState = QAudio::SuspendedState;
+ QAudio::Error m_error = QAudio::NoError;
+ SLObjectItf m_outputMixObject = nullptr;
+ SLObjectItf m_playerObject = nullptr;
+ SLPlayItf m_playItf = nullptr;
+ SLVolumeItf m_volumeItf = nullptr;
+ SLBufferQueueItf m_bufferQueueItf = nullptr;
+ QIODevice *m_audioSource = nullptr;
+ char *m_buffers = nullptr;
+ qreal m_volume = 1.0;
+ bool m_pullMode = false;
+ int m_nextBuffer = 0;
+ int m_bufferSize = 0;
+ qint64 m_elapsedTime = 0;
+ qint64 m_processedBytes = 0;
+ bool m_endSound = false;
+ QAtomicInt m_availableBuffers = BufferCount;
+ SLuint32 m_eventMask = SL_PLAYEVENT_HEADATEND;
+ bool m_startRequiresInit = true;
+
+ qint32 m_streamType;
+ QAudioFormat m_format;
+};
+
+class SLIODevicePrivate : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ inline SLIODevicePrivate(QAndroidAudioSink *audio) : m_audioDevice(audio) {}
+ inline ~SLIODevicePrivate() override {}
+
+protected:
+ inline qint64 readData(char *, qint64) override { return 0; }
+ inline qint64 writeData(const char *data, qint64 len) override;
+
+private:
+ QAndroidAudioSink *m_audioDevice;
+};
+
+qint64 SLIODevicePrivate::writeData(const char *data, qint64 len)
+{
+ Q_ASSERT(m_audioDevice);
+ return m_audioDevice->writeData(data, len);
+}
+
+QT_END_NAMESPACE
+
+#endif // QOPENSLESAUDIOOUTPUT_H
diff --git a/src/multimedia/platform/android/audio/qandroidaudiosource.cpp b/src/multimedia/android/qandroidaudiosource.cpp
index c7eaf57ad..3a7332fd1 100644
--- a/src/multimedia/platform/android/audio/qandroidaudiosource.cpp
+++ b/src/multimedia/android/qandroidaudiosource.cpp
@@ -1,55 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidaudiosource_p.h"
#include "qopenslesengine_p.h"
#include <private/qaudiohelpers_p.h>
-#include <QtCore/private/qandroidextras_p.h>
#include <qbuffer.h>
#include <qdebug.h>
+#include <qloggingcategory.h>
#ifdef ANDROID
#include <SLES/OpenSLES_AndroidConfiguration.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpermissions.h>
#endif
+static Q_LOGGING_CATEGORY(qLcAndroidAudioSource, "qt.multimedia.android.audiosource")
+
QT_BEGIN_NAMESPACE
#define NUM_BUFFERS 2
@@ -59,20 +26,13 @@ QT_BEGIN_NAMESPACE
#ifdef ANDROID
static bool hasRecordingPermission()
{
- if (QNativeInterface::QAndroidApplication::sdkVersion() < 23)
- return true;
-
- const QtAndroidPrivate::PermissionType key(QtAndroidPrivate::Microphone);
- // Permission already granted?
- if (QtAndroidPrivate::checkPermission(key).result() == QtAndroidPrivate::Authorized)
- return true;
+ QMicrophonePermission permission;
- if (QtAndroidPrivate::requestPermission(key).result() != QtAndroidPrivate::Authorized) {
- qDebug("Microphone permission denied by user!");
- return false;
- }
+ const bool permitted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
+ if (!permitted)
+ qCWarning(qLcAndroidAudioSource, "Missing microphone permission!");
- return true;
+ return permitted;
}
static void bufferQueueCallback(SLAndroidSimpleBufferQueueItf, void *context)
@@ -84,8 +44,9 @@ static void bufferQueueCallback(SLBufferQueueItf, void *context)
QMetaObject::invokeMethod(reinterpret_cast<QAndroidAudioSource*>(context), "processBuffer");
}
-QAndroidAudioSource::QAndroidAudioSource(const QByteArray &device)
- : m_device(device)
+QAndroidAudioSource::QAndroidAudioSource(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSource(parent)
+ , m_device(device)
, m_engine(QOpenSLESEngine::instance())
, m_recorderObject(0)
, m_recorder(0)
@@ -180,7 +141,7 @@ QIODevice *QAndroidAudioSource::start()
m_pullMode = false;
m_pushBuffer.clear();
- m_bufferIODevice = new QBuffer(&m_pushBuffer);
+ m_bufferIODevice = new QBuffer(&m_pushBuffer, this);
m_bufferIODevice->open(QIODevice::ReadOnly);
if (startRecording()) {
@@ -220,7 +181,7 @@ bool QAndroidAudioSource::startRecording()
SLDataLocator_BufferQueue loc_bq = { SL_DATALOCATOR_BUFFERQUEUE, NUM_BUFFERS };
#endif
- SLDataFormat_PCM format_pcm = QOpenSLESEngine::audioFormatToSLFormatPCM(m_format);
+ SLAndroidDataFormat_PCM_EX format_pcm = QOpenSLESEngine::audioFormatToSLFormatPCM(m_format);
SLDataSink audioSnk = { &loc_bq, &format_pcm };
// create audio recorder
@@ -398,6 +359,10 @@ void QAndroidAudioSource::processBuffer()
QByteArray *processedBuffer = &m_buffers[m_currentBuffer];
writeDataToDevice(processedBuffer->constData(), processedBuffer->size());
+ // Make sure that it was not stopped from writeDataToDevice
+ if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
+ return;
+
// Re-enqueue the buffer
SLresult result = (*m_bufferQueue)->Enqueue(m_bufferQueue,
processedBuffer->data(),
diff --git a/src/multimedia/platform/android/audio/qandroidaudiosource_p.h b/src/multimedia/android/qandroidaudiosource_p.h
index 8a4621b2c..13578509c 100644
--- a/src/multimedia/platform/android/audio/qandroidaudiosource_p.h
+++ b/src/multimedia/android/qandroidaudiosource_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOPENSLESAUDIOINPUT_H
#define QOPENSLESAUDIOINPUT_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <qaudiosystem_p.h>
+#include <private/qaudiosystem_p.h>
#include <QElapsedTimer>
#include <SLES/OpenSLES.h>
@@ -76,7 +40,7 @@ class QAndroidAudioSource : public QPlatformAudioSource
Q_OBJECT
public:
- QAndroidAudioSource(const QByteArray &device);
+ QAndroidAudioSource(const QByteArray &device, QObject *parent);
~QAndroidAudioSource();
void start(QIODevice *device);
diff --git a/src/multimedia/android/qandroidmediadevices.cpp b/src/multimedia/android/qandroidmediadevices.cpp
new file mode 100644
index 000000000..55533621c
--- /dev/null
+++ b/src/multimedia/android/qandroidmediadevices.cpp
@@ -0,0 +1,117 @@
+// 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 "qandroidmediadevices_p.h"
+#include "qmediadevices.h"
+#include "private/qcameradevice_p.h"
+
+#include "qandroidaudiosource_p.h"
+#include "qandroidaudiosink_p.h"
+#include "qandroidaudiodevice_p.h"
+#include "qopenslesengine_p.h"
+#include "private/qplatformmediaintegration_p.h"
+
+#include <qjnienvironment.h>
+#include <QJniObject>
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_JNI_CLASS(QtAudioDeviceManager,
+ "org/qtproject/qt/android/multimedia/QtAudioDeviceManager");
+
+
+QAndroidMediaDevices::QAndroidMediaDevices() : QPlatformMediaDevices()
+{
+ QtJniTypes::QtAudioDeviceManager::callStaticMethod<void>(
+ "registerAudioHeadsetStateReceiver",
+ QNativeInterface::QAndroidApplication::context());
+}
+
+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());
+}
+
+QList<QAudioDevice> QAndroidMediaDevices::audioInputs() const
+{
+ return QOpenSLESEngine::availableDevices(QAudioDevice::Input);
+}
+
+QList<QAudioDevice> QAndroidMediaDevices::audioOutputs() const
+{
+ return QOpenSLESEngine::availableDevices(QAudioDevice::Output);
+}
+
+QPlatformAudioSource *QAndroidMediaDevices::createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QAndroidAudioSource(deviceInfo.id(), parent);
+}
+
+QPlatformAudioSink *QAndroidMediaDevices::createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QAndroidAudioSink(deviceInfo.id(), parent);
+}
+
+void QAndroidMediaDevices::forwardAudioOutputsChanged()
+{
+ emit audioOutputsChanged();
+}
+
+void QAndroidMediaDevices::forwardAudioInputsChanged()
+{
+ emit audioInputsChanged();
+}
+
+static void onAudioInputDevicesUpdated(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ static_cast<QAndroidMediaDevices*>(QPlatformMediaIntegration::instance()->mediaDevices())->forwardAudioInputsChanged();
+}
+
+static void onAudioOutputDevicesUpdated(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ static_cast<QAndroidMediaDevices*>(QPlatformMediaIntegration::instance()->mediaDevices())->forwardAudioOutputsChanged();
+}
+
+Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
+{
+ static bool initialized = false;
+ if (initialized)
+ return JNI_VERSION_1_6;
+ initialized = true;
+
+ QT_USE_NAMESPACE
+ typedef union {
+ JNIEnv *nativeEnvironment;
+ void *venv;
+ } UnionJNIEnvToVoid;
+
+ UnionJNIEnvToVoid uenv;
+ uenv.venv = NULL;
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK)
+ return JNI_ERR;
+
+ const JNINativeMethod methods[] = {
+ { "onAudioInputDevicesUpdated", "()V", (void *)onAudioInputDevicesUpdated },
+ { "onAudioOutputDevicesUpdated", "()V", (void *)onAudioOutputDevicesUpdated }
+ };
+
+ bool registered = QJniEnvironment().registerNativeMethods(
+ "org/qtproject/qt/android/multimedia/QtAudioDeviceManager", methods,
+ std::size(methods));
+
+ if (!registered)
+ return JNI_ERR;
+
+ return JNI_VERSION_1_6;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/android/qandroidmediadevices_p.h b/src/multimedia/android/qandroidmediadevices_p.h
new file mode 100644
index 000000000..a77ed0451
--- /dev/null
+++ b/src/multimedia/android/qandroidmediadevices_p.h
@@ -0,0 +1,42 @@
+// 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
+
+#ifndef QANDROIDMEDIADEVICES_H
+#define QANDROIDMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+#include <qaudio.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QAndroidMediaDevices();
+
+ ~QAndroidMediaDevices();
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+
+ void forwardAudioOutputsChanged();
+ void forwardAudioInputsChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/platform/android/audio/qopenslesengine.cpp b/src/multimedia/android/qopenslesengine.cpp
index 7d207a369..738161ab7 100644
--- a/src/multimedia/platform/android/audio/qopenslesengine.cpp
+++ b/src/multimedia/android/qopenslesengine.cpp
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qopenslesengine_p.h"
#include "qandroidaudiosource_p.h"
#include "qandroidaudiodevice_p.h"
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qjniobject.h>
+#include <QtCore/qpermissions.h>
#include <QtCore/private/qandroidextras_p.h>
#include <qdebug.h>
@@ -51,6 +17,8 @@
#define CheckError(message) if (result != SL_RESULT_SUCCESS) { qWarning(message); return; }
+#define SL_ANDROID_PCM_REPRESENTATION_INVALID 0
+
Q_GLOBAL_STATIC(QOpenSLESEngine, openslesEngine);
QOpenSLESEngine::QOpenSLESEngine()
@@ -81,22 +49,53 @@ QOpenSLESEngine *QOpenSLESEngine::instance()
return openslesEngine();
}
-SLDataFormat_PCM QOpenSLESEngine::audioFormatToSLFormatPCM(const QAudioFormat &format)
+static SLuint32 getChannelMask(unsigned channelCount)
+{
+ switch (channelCount) {
+ case 1: return SL_SPEAKER_FRONT_CENTER;
+ case 2: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
+ case 3: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER;
+ case 4: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT
+ | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
+ case 5: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT
+ | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER;
+ case 6: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT
+ | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY;
+ default: return 0; // Default to 0 for an unsupported or unknown number of channels
+ }
+}
+
+SLAndroidDataFormat_PCM_EX QOpenSLESEngine::audioFormatToSLFormatPCM(const QAudioFormat &format)
{
- SLDataFormat_PCM format_pcm;
- format_pcm.formatType = SL_DATAFORMAT_PCM;
+ SLAndroidDataFormat_PCM_EX format_pcm;
+ format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
format_pcm.numChannels = format.channelCount();
- format_pcm.samplesPerSec = format.sampleRate() * 1000;
+ format_pcm.sampleRate = format.sampleRate() * 1000;
format_pcm.bitsPerSample = format.bytesPerSample() * 8;
format_pcm.containerSize = format.bytesPerSample() * 8;
- format_pcm.channelMask = (format.channelCount() == 1 ?
- SL_SPEAKER_FRONT_CENTER :
- SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
+ format_pcm.channelMask = getChannelMask(format_pcm.numChannels);
format_pcm.endianness = (QSysInfo::ByteOrder == QSysInfo::LittleEndian ?
SL_BYTEORDER_LITTLEENDIAN :
SL_BYTEORDER_BIGENDIAN);
- return format_pcm;
+ switch (format.sampleFormat()) {
+ case QAudioFormat::SampleFormat::UInt8:
+ format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
+ break;
+ case QAudioFormat::SampleFormat::Int16:
+ case QAudioFormat::SampleFormat::Int32:
+ format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
+ break;
+ case QAudioFormat::SampleFormat::Float:
+ format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
+ break;
+ case QAudioFormat::SampleFormat::NSampleFormats:
+ case QAudioFormat::SampleFormat::Unknown:
+ format_pcm.representation = SL_ANDROID_PCM_REPRESENTATION_INVALID;
+ break;
+ }
+
+ return format_pcm;
}
QList<QAudioDevice> QOpenSLESEngine::availableDevices(QAudioDevice::Mode mode)
@@ -128,15 +127,22 @@ QList<QAudioDevice> QOpenSLESEngine::availableDevices(QAudioDevice::Mode mode)
return devices;
}
+bool QOpenSLESEngine::setAudioOutput(const QByteArray &deviceId)
+{
+ return QJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
+ "setAudioOutput",
+ deviceId.toInt());
+}
+
static bool hasRecordPermission()
{
- const auto recordPerm = QtAndroidPrivate::checkPermission(QtAndroidPrivate::Microphone);
- return recordPerm.result() == QtAndroidPrivate::Authorized;
+ return qApp->checkPermission(QMicrophonePermission{}) == Qt::PermissionStatus::Granted;
}
QList<int> QOpenSLESEngine::supportedChannelCounts(QAudioDevice::Mode mode) const
{
- if (mode == QAudioDevice::Input && hasRecordPermission()) {
+ if (mode == QAudioDevice::Input) {
if (!m_checkedInputFormats)
const_cast<QOpenSLESEngine *>(this)->checkSupportedInputFormats();
return m_supportedInputChannelCounts;
@@ -147,7 +153,7 @@ QList<int> QOpenSLESEngine::supportedChannelCounts(QAudioDevice::Mode mode) cons
QList<int> QOpenSLESEngine::supportedSampleRates(QAudioDevice::Mode mode) const
{
- if (mode == QAudioDevice::Input && hasRecordPermission()) {
+ if (mode == QAudioDevice::Input) {
if (!m_checkedInputFormats)
const_cast<QOpenSLESEngine *>(this)->checkSupportedInputFormats();
return m_supportedInputSampleRates;
@@ -302,9 +308,9 @@ void QOpenSLESEngine::checkSupportedInputFormats()
defaultFormat.sampleRate = SL_SAMPLINGRATE_44_1;
defaultFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
defaultFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;
- defaultFormat.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
defaultFormat.channelMask = SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(SL_SPEAKER_FRONT_CENTER);
defaultFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
+ defaultFormat.representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
const SLuint32 rates[13] = { SL_SAMPLINGRATE_8,
SL_SAMPLINGRATE_11_025,
@@ -355,6 +361,10 @@ bool QOpenSLESEngine::inputFormatIsSupported(SLAndroidDataFormat_PCM_EX format)
SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
SLDataSink audioSnk = { &loc_bq, &format };
+ // only ask permission when it is about to create the audiorecorder
+ if (!hasRecordPermission())
+ return false;
+
result = (*m_engine)->CreateAudioRecorder(m_engine, &recorder, &audioSrc, &audioSnk, 0, 0, 0);
if (result == SL_RESULT_SUCCESS)
result = (*recorder)->Realize(recorder, false);
diff --git a/src/multimedia/android/qopenslesengine_p.h b/src/multimedia/android/qopenslesengine_p.h
new file mode 100644
index 000000000..9918ac888
--- /dev/null
+++ b/src/multimedia/android/qopenslesengine_p.h
@@ -0,0 +1,65 @@
+// 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 QOPENSLESENGINE_H
+#define QOPENSLESENGINE_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 <qglobal.h>
+#include <qaudio.h>
+#include <qlist.h>
+#include <qaudioformat.h>
+#include <qaudiodevice.h>
+#include <SLES/OpenSLES_Android.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenSLESEngine
+{
+public:
+ enum OutputValue { FramesPerBuffer, SampleRate };
+
+ QOpenSLESEngine();
+ ~QOpenSLESEngine();
+
+ static QOpenSLESEngine *instance();
+
+ SLEngineItf slEngine() const { return m_engine; }
+
+ static SLAndroidDataFormat_PCM_EX audioFormatToSLFormatPCM(const QAudioFormat &format);
+
+ static QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode);
+ static bool setAudioOutput(const QByteArray &deviceId);
+ QList<int> supportedChannelCounts(QAudioDevice::Mode mode) const;
+ QList<int> supportedSampleRates(QAudioDevice::Mode mode) const;
+
+ static int getOutputValue(OutputValue type, int defaultValue = 0);
+ static int getDefaultBufferSize(const QAudioFormat &format);
+ static int getLowLatencyBufferSize(const QAudioFormat &format);
+ static bool supportsLowLatency();
+ static bool printDebugInfo();
+
+private:
+ void checkSupportedInputFormats();
+ bool inputFormatIsSupported(SLAndroidDataFormat_PCM_EX format);
+ SLObjectItf m_engineObject;
+ SLEngineItf m_engine;
+
+ QList<int> m_supportedInputChannelCounts;
+ QList<int> m_supportedInputSampleRates;
+ bool m_checkedInputFormats;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENSLESENGINE_H
diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h
index 868ef2f6a..5ae994b9f 100644
--- a/src/multimedia/audio/qaudio.h
+++ b/src/multimedia/audio/qaudio.h
@@ -1,46 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
+// Copyright (C) 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 QAUDIO_H
#define QAUDIO_H
+#if 0
+#pragma qt_class(QAudio)
+#endif
+
#include <QtMultimedia/qtmultimediaglobal.h>
#include <QtCore/qmetatype.h>
@@ -51,7 +18,12 @@ QT_BEGIN_NAMESPACE
// Class forward declaration required for QDoc bug
class QString;
+
+#if defined(Q_QDOC)
+namespace QtAudio
+#else
namespace QAudio
+#endif
{
enum Error { NoError, OpenError, IOError, UnderrunError, FatalError };
enum State { ActiveState, SuspendedState, StoppedState, IdleState };
@@ -66,10 +38,14 @@ namespace QAudio
Q_MULTIMEDIA_EXPORT float convertVolume(float volume, VolumeScale from, VolumeScale to);
}
+#if !defined(Q_QDOC)
+namespace QtAudio = QAudio;
+#endif
+
#ifndef QT_NO_DEBUG_STREAM
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::Error error);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::State state);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::VolumeScale role);
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QtAudio::Error error);
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QtAudio::State state);
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QtAudio::VolumeScale role);
#endif
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiobuffer.cpp b/src/multimedia/audio/qaudiobuffer.cpp
index f839dc68b..69adcc5b7 100644
--- a/src/multimedia/audio/qaudiobuffer.cpp
+++ b/src/multimedia/audio/qaudiobuffer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qaudiobuffer.h"
@@ -48,9 +12,7 @@ class QAudioBufferPrivate : public QSharedData
{
public:
QAudioBufferPrivate(const QAudioFormat &f, const QByteArray &d, qint64 start)
- : format(f),
- data(d),
- startTime(start)
+ : format(f), data(d), startTime(start)
{
}
@@ -71,11 +33,12 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QAudioBufferPrivate);
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_audio
- \brief The QAudioBuffer class represents a collection of audio samples with a specific format and sample rate.
+ \brief The QAudioBuffer class represents a collection of audio samples with a specific format
+ and sample rate.
- QAudioBuffer is used by the QAudioDecoder class to hand decoded audio data over to the application. An audio buffer
- contains data in a certain QAudioFormat that can be queried using format(). It is also tagged with timing and duration
- information.
+ QAudioBuffer is used by the QAudioDecoder class to hand decoded audio data over to the
+ application. An audio buffer contains data in a certain QAudioFormat that can be queried using
+ format(). It is also tagged with timing and duration information.
To access the data stored inside the buffer, use the data() or constData() methods.
@@ -140,6 +103,12 @@ QAudioBuffer::QAudioBuffer(int numFrames, const QAudioFormat &format, qint64 sta
*/
/*!
+ \fn void QAudioBuffer::swap(QAudioBuffer &other) noexcept
+
+ Swaps the audio buffer with \a other.
+*/
+
+/*!
\fn QAudioBuffer &QAudioBuffer::operator=(QAudioBuffer &&other)
Moves \a other into this QAudioBuffer.
@@ -148,7 +117,7 @@ QAudioBuffer::QAudioBuffer(int numFrames, const QAudioFormat &format, qint64 sta
/*!
Assigns the \a other buffer to this.
*/
-QAudioBuffer &QAudioBuffer::operator =(const QAudioBuffer &other) = default;
+QAudioBuffer &QAudioBuffer::operator=(const QAudioBuffer &other) = default;
/*!
Destroys this audio buffer.
@@ -245,15 +214,15 @@ qint64 QAudioBuffer::startTime() const noexcept
}
/*!
+ \fn template <typename T> const T* QAudioBuffer::constData() const
+
Returns a pointer to this buffer's data. You can only read it.
This method is preferred over the const version of \l data() to
prevent unnecessary copying.
- There is also a templatized version of this constData() function that
- allows you to retrieve a specific type of read-only pointer to
- the data. Note that there is no checking done on the format of
- the audio buffer - this is simply a convenience function.
+ Note that there is no checking done on the format of the audio
+ buffer - this is simply a convenience function.
\code
// With a 16bit sample buffer:
@@ -261,7 +230,8 @@ qint64 QAudioBuffer::startTime() const noexcept
\endcode
*/
-const void* QAudioBuffer::constData() const noexcept
+
+const void *QAudioBuffer::constData() const noexcept
{
if (!d)
return nullptr;
@@ -269,14 +239,14 @@ const void* QAudioBuffer::constData() const noexcept
}
/*!
+ \fn template <typename T> const T* QAudioBuffer::data() const
+
Returns a pointer to this buffer's data. You can only read it.
You should use the \l constData() function rather than this
to prevent accidental deep copying.
- There is also a templatized version of this data() function that
- allows you to retrieve a specific type of read-only pointer to
- the data. Note that there is no checking done on the format of
+ Note that there is no checking done on the format of
the audio buffer - this is simply a convenience function.
\code
@@ -284,36 +254,32 @@ const void* QAudioBuffer::constData() const noexcept
const quint16 *data = buffer->data<quint16>();
\endcode
*/
-const void* QAudioBuffer::data() const noexcept
+
+const void *QAudioBuffer::data() const noexcept
{
if (!d)
return nullptr;
return d->data.constData();
}
-
-/*
- Template data/constData functions caused override problems with qdoc,
- so moved their docs into the non template versions.
-*/
-
/*!
+ \fn template <typename T> T* QAudioBuffer::data()
+
Returns a pointer to this buffer's data. You can modify the
data through the returned pointer.
Since QAudioBuffer objects are explicitly shared, you should usually
call detach() before modifying the data through this function.
- There is also a templatized version of data() allows you to retrieve
- a specific type of pointer to the data. Note that there is no
- checking done on the format of the audio buffer - this is
- simply a convenience function.
+ Note that there is no checking done on the format of the audio
+ buffer - this is simply a convenience function.
\code
// With a 16bit sample buffer:
quint16 *data = buffer->data<quint16>(); // May cause deep copy
\endcode
*/
+
void *QAudioBuffer::data()
{
if (!d)
@@ -328,4 +294,33 @@ void *QAudioBuffer::data()
channel is a \e {signed short}.
*/
+/*!
+ \typedef QAudioBuffer::U8M
+
+ This is a predefined specialization for an unsigned 8 bit mono sample.
+*/
+/*!
+ \typedef QAudioBuffer::S16M
+ This is a predefined specialization for a signed 16 bit mono sample.
+i*/
+/*!
+ \typedef QAudioBuffer::S32M
+ This is a predefined specialization for a signed 32 bit mono sample.
+*/
+/*!
+ \typedef QAudioBuffer::F32M
+ This is a predefined specialization for a 32 bit float mono sample.
+*/
+/*!
+ \typedef QAudioBuffer::U8S
+ This is a predifined specialization for an unsiged 8 bit stereo sample.
+*/
+/*!
+ \typedef QAudioBuffer::S32S
+ This is a predifined specialization for a siged 32 bit stereo sample.
+*/
+/*!
+ \typedef QAudioBuffer::F32S
+ This is a predifined specialization for a 32 bit float stereo sample.
+*/
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiobuffer.h b/src/multimedia/audio/qaudiobuffer.h
index b4c58fe10..822619f31 100644
--- a/src/multimedia/audio/qaudiobuffer.h
+++ b/src/multimedia/audio/qaudiobuffer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QAUDIOBUFFER_H
#define QAUDIOBUFFER_H
@@ -44,7 +8,7 @@
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
#include <QtMultimedia/qaudioformat.h>
QT_BEGIN_NAMESPACE
@@ -113,7 +77,7 @@ public:
return QtPrivate::AudioSampleFormatHelper<format>::Default;
return channels[idx];
}
- void setValue(QAudioFormat::AudioChannelPosition pos, value_type val) const {
+ void setValue(QAudioFormat::AudioChannelPosition pos, value_type val) {
int idx = positionToIndex(pos);
if (idx < 0)
return;
@@ -161,7 +125,7 @@ public:
QAudioBuffer(QAudioBuffer &&other) noexcept = default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QAudioBuffer)
void swap(QAudioBuffer &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool isValid() const noexcept { return d != nullptr; };
diff --git a/src/multimedia/audio/qaudiodecoder.cpp b/src/multimedia/audio/qaudiodecoder.cpp
index e0587d31a..f555f46ed 100644
--- a/src/multimedia/audio/qaudiodecoder.cpp
+++ b/src/multimedia/audio/qaudiodecoder.cpp
@@ -1,56 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qtmultimediaglobal_p.h"
-#include "qaudiodecoder.h"
+// 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 "private/qplatformaudiodecoder_p.h"
+#include "qaudiodecoder.h"
+#include <private/qaudiodecoder_p.h>
+#include <private/qmultimediautils_p.h>
+#include <private/qplatformaudiodecoder_p.h>
#include <private/qplatformmediaintegration_p.h>
-#include <private/qobject_p.h>
#include <QtCore/qcoreevent.h>
+#include <QtCore/qdebug.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/qpointer.h>
#include <QtCore/qtimer.h>
#include <QtCore/qurl.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -74,12 +37,19 @@ QT_BEGIN_NAMESPACE
/*!
Construct an QAudioDecoder instance with \a parent.
*/
-QAudioDecoder::QAudioDecoder(QObject *parent)
- : QObject(parent)
+QAudioDecoder::QAudioDecoder(QObject *parent) : QObject{ *new QAudioDecoderPrivate, parent }
{
- decoder = QPlatformMediaIntegration::instance()->createAudioDecoder(this);
-}
+ QT6_ONLY(Q_UNUSED(unused))
+
+ Q_D(QAudioDecoder);
+ auto maybeDecoder = QPlatformMediaIntegration::instance()->createAudioDecoder(this);
+ if (maybeDecoder) {
+ d->decoder.reset(maybeDecoder.value());
+ } else {
+ qWarning() << "Failed to initialize QAudioDecoder" << maybeDecoder.error();
+ }
+}
/*!
Destroys the audio decoder object.
@@ -91,7 +61,9 @@ QAudioDecoder::~QAudioDecoder() = default;
*/
bool QAudioDecoder::isSupported() const
{
- return decoder != nullptr;
+ Q_D(const QAudioDecoder);
+
+ return bool(d->decoder);
}
/*!
@@ -100,29 +72,33 @@ bool QAudioDecoder::isSupported() const
*/
bool QAudioDecoder::isDecoding() const
{
- return decoder && decoder->isDecoding();
+ Q_D(const QAudioDecoder);
+
+ return d->decoder && d->decoder->isDecoding();
}
/*!
- \property QAudioDecoder::error
- \brief The current error state.
+
+ Returns the current error state of the QAudioDecoder.
*/
QAudioDecoder::Error QAudioDecoder::error() const
{
- if (!decoder)
- return NotSupportedError;
- return decoder->error();
+ Q_D(const QAudioDecoder);
+ return d->decoder ? d->decoder->error() : NotSupportedError;
}
/*!
+ \property QAudioDecoder::error
+
Returns a human readable description of the current error, or
an empty string is there is no error.
*/
QString QAudioDecoder::errorString() const
{
- if (!decoder)
+ Q_D(const QAudioDecoder);
+ if (!d->decoder)
return tr("QAudioDecoder not supported.");
- return decoder->errorString();
+ return d->decoder->errorString();
}
/*!
@@ -139,13 +115,14 @@ QString QAudioDecoder::errorString() const
*/
void QAudioDecoder::start()
{
- if (decoder == nullptr)
+ Q_D(QAudioDecoder);
+
+ if (!d->decoder)
return;
// Reset error conditions
- decoder->clearError();
-
- decoder->start();
+ d->decoder->clearError();
+ d->decoder->start();
}
/*!
@@ -153,10 +130,10 @@ void QAudioDecoder::start()
*/
void QAudioDecoder::stop()
{
- if (!decoder)
- return;
+ Q_D(QAudioDecoder);
- decoder->stop();
+ if (d->decoder)
+ d->decoder->stop();
}
/*!
@@ -166,9 +143,8 @@ void QAudioDecoder::stop()
*/
QUrl QAudioDecoder::source() const
{
- if (decoder)
- return decoder->source();
- return QString();
+ Q_D(const QAudioDecoder);
+ return d->unresolvedUrl;
}
/*!
@@ -182,11 +158,16 @@ QUrl QAudioDecoder::source() const
*/
void QAudioDecoder::setSource(const QUrl &fileName)
{
- if (!decoder)
+ Q_D(QAudioDecoder);
+
+ if (!d->decoder)
return;
- decoder->clearError();
- decoder->setSource(fileName);
+ d->decoder->clearError();
+ d->unresolvedUrl = fileName;
+ d->decoder->setSourceDevice(nullptr);
+ QUrl url = qMediaFromUserInput(fileName);
+ d->decoder->setSource(url);
}
/*!
@@ -195,9 +176,8 @@ void QAudioDecoder::setSource(const QUrl &fileName)
*/
QIODevice *QAudioDecoder::sourceDevice() const
{
- if (decoder)
- return decoder->sourceDevice();
- return nullptr;
+ Q_D(const QAudioDecoder);
+ return d->decoder ? d->decoder->sourceDevice() : nullptr;
}
/*!
@@ -211,9 +191,11 @@ QIODevice *QAudioDecoder::sourceDevice() const
*/
void QAudioDecoder::setSourceDevice(QIODevice *device)
{
- if (!decoder)
- return;
- decoder->setSourceDevice(device);
+ Q_D(QAudioDecoder);
+ if (d->decoder) {
+ d->unresolvedUrl = QUrl{};
+ d->decoder->setSourceDevice(device);
+ }
}
/*!
@@ -226,9 +208,8 @@ void QAudioDecoder::setSourceDevice(QIODevice *device)
*/
QAudioFormat QAudioDecoder::audioFormat() const
{
- if (decoder)
- return decoder->audioFormat();
- return QAudioFormat();
+ Q_D(const QAudioDecoder);
+ return d->decoder ? d->decoder->audioFormat() : QAudioFormat{};
}
/*!
@@ -248,15 +229,18 @@ QAudioFormat QAudioDecoder::audioFormat() const
audio file, you can specify an invalid \a format.
\warning Setting a desired audio format is not yet supported
- on Android.
+ on the Android backend. It does work with the default FFMPEG
+ backend.
*/
void QAudioDecoder::setAudioFormat(const QAudioFormat &format)
{
if (isDecoding())
return;
- if (decoder != nullptr)
- decoder->setAudioFormat(format);
+ Q_D(QAudioDecoder);
+
+ if (d->decoder)
+ d->decoder->setAudioFormat(format);
}
/*!
@@ -266,9 +250,8 @@ void QAudioDecoder::setAudioFormat(const QAudioFormat &format)
*/
bool QAudioDecoder::bufferAvailable() const
{
- if (decoder)
- return decoder->bufferAvailable();
- return false;
+ Q_D(const QAudioDecoder);
+ return d->decoder && d->decoder->bufferAvailable();
}
/*!
@@ -278,9 +261,8 @@ bool QAudioDecoder::bufferAvailable() const
qint64 QAudioDecoder::position() const
{
- if (decoder)
- return decoder->position();
- return -1;
+ Q_D(const QAudioDecoder);
+ return d->decoder ? d->decoder->position() : -1;
}
/*!
@@ -290,9 +272,8 @@ qint64 QAudioDecoder::position() const
qint64 QAudioDecoder::duration() const
{
- if (decoder)
- return decoder->duration();
- return -1;
+ Q_D(const QAudioDecoder);
+ return d->decoder ? d->decoder->duration() : -1;
}
/*!
@@ -307,10 +288,8 @@ qint64 QAudioDecoder::duration() const
QAudioBuffer QAudioDecoder::read() const
{
- if (decoder)
- return decoder->read();
-
- return QAudioBuffer();
+ Q_D(const QAudioDecoder);
+ return d->decoder ? d->decoder->read() : QAudioBuffer{};
}
// Enums
@@ -328,7 +307,7 @@ QAudioBuffer QAudioDecoder::read() const
// Signals
/*!
- \fn QAudioDecoder::error(QAudioDecoder::Error error)
+ \fn void QAudioDecoder::error(QAudioDecoder::Error error)
Signals that an \a error condition has occurred.
@@ -394,7 +373,6 @@ QAudioBuffer QAudioDecoder::read() const
\sa positionChanged()
*/
-
// Properties
/*!
\property QAudioDecoder::source
diff --git a/src/multimedia/audio/qaudiodecoder.h b/src/multimedia/audio/qaudiodecoder.h
index 451c3a657..9044b6617 100644
--- a/src/multimedia/audio/qaudiodecoder.h
+++ b/src/multimedia/audio/qaudiodecoder.h
@@ -1,53 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QAUDIODECODER_H
#define QAUDIODECODER_H
#include <QtCore/qobject.h>
#include <QtMultimedia/qmediaenumdebug.h>
-
#include <QtMultimedia/qaudiobuffer.h>
QT_BEGIN_NAMESPACE
-class QPlatformAudioDecoder;
+class QAudioDecoderPrivate;
class Q_MULTIMEDIA_EXPORT QAudioDecoder : public QObject
{
Q_OBJECT
@@ -112,7 +75,10 @@ Q_SIGNALS:
private:
Q_DISABLE_COPY(QAudioDecoder)
- QPlatformAudioDecoder *decoder;
+ Q_DECLARE_PRIVATE(QAudioDecoder)
+
+ // ### Qt7: remove unused member
+ QT6_ONLY(void *unused = nullptr;) // for ABI compatibility
};
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiodecoder_p.h b/src/multimedia/audio/qaudiodecoder_p.h
new file mode 100644
index 000000000..fa7311457
--- /dev/null
+++ b/src/multimedia/audio/qaudiodecoder_p.h
@@ -0,0 +1,40 @@
+// 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 QAUDIODECODER_P_H
+#define QAUDIODECODER_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/private/qobject_p.h>
+#include <QtMultimedia/private/qplatformaudiodecoder_p.h>
+
+#include <memory.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioDecoder;
+
+class QAudioDecoderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAudioDecoder)
+
+public:
+ QAudioDecoderPrivate() = default;
+
+ QUrl unresolvedUrl;
+ std::unique_ptr<QPlatformAudioDecoder> decoder;
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIODECODER_P_H
diff --git a/src/multimedia/audio/qaudiodevice.cpp b/src/multimedia/audio/qaudiodevice.cpp
index bc2bed906..4b1e182cb 100644
--- a/src/multimedia/audio/qaudiodevice.cpp
+++ b/src/multimedia/audio/qaudiodevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qaudiosystem_p.h"
#include "qaudiodevice_p.h"
@@ -52,12 +16,14 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QAudioDevicePrivate);
/*!
\class QAudioDevice
- \brief The QAudioDevice class provides an information about audio devices and their functionality.
+ \brief The QAudioDevice class provides an information about audio devices and their
+ functionality.
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_audio
- QAudioDevice describes an audio device available in the system, either for input or for playback.
+ QAudioDevice describes an audio device available in the system, either for input or for
+ playback.
A QAudioDevice is used by Qt to construct
classes that communicate with the device -- such as
@@ -73,10 +39,9 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QAudioDevicePrivate);
minimumSampleRate(), maximumSampleRate() and supportedSampleFormats(). The
combinations supported are dependent on the audio device capabilities. If
you need a specific format, you can check if the device supports it with
- isFormatSupported(), or fetch a supported format that is as close as
- possible to the format with nearestFormat(). For instance:
+ isFormatSupported(). For instance:
- \snippet multimedia-snippets/audio.cpp Setting audio format
+ \snippet multimedia-snippets/audio.cpp Audio output setup
The set of available devices can be retrieved from the QMediaDevices class.
@@ -88,7 +53,36 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QAudioDevicePrivate);
sound, i.e., play an audio stream in a supported format. For each device we
find, we simply print the deviceName().
- \sa QAudioSink, QAudioSource
+ \sa QAudioSink, QAudioSource, QAudioFormat
+*/
+
+/*!
+ \qmlvaluetype audioDevice
+ \inqmlmodule QtMultimedia
+ \since 6.2
+ //! \instantiates QAudioDevice
+ \brief Describes an audio device.
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+ \ingroup qmlvaluetypes
+
+ The audioDevice value type describes the properties of an audio device that
+ is connected to the system.
+
+ The list of audio input or output devices can be queried from the \l{MediaDevices}
+ type. To select a certain audio device for input or output set it as the device
+ on \l{AudioInput} or \l{AudioOutput}.
+
+ \qml
+ MediaPlayer {
+ audioOutput: AudioOutput {
+ device: mediaDevices.defaultAudioOutput
+ }
+ }
+ MediaDevices {
+ id: mediaDevices
+ }
+ \endqml
*/
/*!
@@ -99,14 +93,18 @@ QAudioDevice::QAudioDevice() = default;
/*!
Constructs a copy of \a other.
*/
-QAudioDevice::QAudioDevice(const QAudioDevice& other) = default;
+QAudioDevice::QAudioDevice(const QAudioDevice &other) = default;
/*!
\fn QAudioDevice::QAudioDevice(QAudioDevice &&other)
Move constructs from \a other.
*/
+/*!
+ \fn void QAudioDevice::swap(QAudioDevice &other) noexcept
+ Swaps the audio device with the \a other.
+*/
/*!
Destroy this audio device info.
*/
@@ -115,7 +113,7 @@ QAudioDevice::~QAudioDevice() = default;
/*!
Sets the QAudioDevice object to be equal to \a other.
*/
-QAudioDevice& QAudioDevice::operator=(const QAudioDevice &other) = default;
+QAudioDevice &QAudioDevice::operator=(const QAudioDevice &other) = default;
/*!
\fn QAudioDevice& QAudioDevice::operator=(QAudioDevice &&other)
@@ -127,13 +125,13 @@ QAudioDevice& QAudioDevice::operator=(const QAudioDevice &other) = default;
Returns true if this QAudioDevice class represents the
same audio device as \a other.
*/
-bool QAudioDevice::operator ==(const QAudioDevice &other) const
+bool QAudioDevice::operator==(const QAudioDevice &other) const
{
if (d == other.d)
return true;
if (!d || !other.d)
return false;
- if (d->mode == other.d->mode && d->id == other.d->id)
+ if (d->mode == other.d->mode && d->id == other.d->id && d->isDefault == other.d->isDefault)
return true;
return false;
}
@@ -142,7 +140,7 @@ bool QAudioDevice::operator ==(const QAudioDevice &other) const
Returns true if this QAudioDevice class represents a
different audio device than \a other
*/
-bool QAudioDevice::operator !=(const QAudioDevice &other) const
+bool QAudioDevice::operator!=(const QAudioDevice &other) const
{
return !operator==(other);
}
@@ -156,6 +154,18 @@ bool QAudioDevice::isNull() const
}
/*!
+ \qmlproperty string QtMultimedia::audioDevice::id
+
+ Holds an identifier for the audio device.
+
+ Device names vary depending on the platform/audio plugin being used.
+
+ They are a unique identifier for the audio device.
+*/
+
+/*!
+ \property QAudioDevice::id
+
Returns an identifier for the audio device.
Device names vary depending on the platform/audio plugin being used.
@@ -168,6 +178,16 @@ QByteArray QAudioDevice::id() const
}
/*!
+ \qmlproperty string QtMultimedia::audioDevice::description
+
+ Holds a human readable name of the audio device.
+
+ Use this string to present the device to the user.
+*/
+
+/*!
+ \property QAudioDevice::description
+
Returns a human readable name of the audio device.
Use this string to present the device to the user.
@@ -178,7 +198,15 @@ QString QAudioDevice::description() const
}
/*!
- Returns true if this is the default audio device for it's mode.
+ \qmlproperty bool QtMultimedia::audioDevice::isDefault
+
+ Is true if this is the default audio device.
+*/
+
+/*!
+ \property QAudioDevice::isDefault
+
+ Returns true if this is the default audio device.
*/
bool QAudioDevice::isDefault() const
{
@@ -193,9 +221,11 @@ bool QAudioDevice::isFormatSupported(const QAudioFormat &settings) const
{
if (isNull())
return false;
- if (settings.sampleRate() < d->minimumSampleRate || settings.sampleRate() > d->maximumSampleRate)
+ if (settings.sampleRate() < d->minimumSampleRate
+ || settings.sampleRate() > d->maximumSampleRate)
return false;
- if (settings.channelCount() < d->minimumChannelCount || settings.channelCount() > d->maximumChannelCount)
+ if (settings.channelCount() < d->minimumChannelCount
+ || settings.channelCount() > d->maximumChannelCount)
return false;
if (!d->supportedSampleFormats.contains(settings.sampleFormat()))
return false;
@@ -207,7 +237,7 @@ bool QAudioDevice::isFormatSupported(const QAudioFormat &settings) const
These settings are provided by the platform/audio plugin being used.
- They are also dependent on the \l {QAudio}::Mode being used.
+ They are also dependent on the \l {QtAudio}::Mode being used.
A typical audio system would provide something like:
\list
@@ -265,14 +295,53 @@ QList<QAudioFormat::SampleFormat> QAudioDevice::supportedSampleFormats() const
}
/*!
+ Returns the channel configuration of the device.
+*/
+QAudioFormat::ChannelConfig QAudioDevice::channelConfiguration() const
+{
+ return isNull() ? QAudioFormat::ChannelConfigUnknown : d->channelConfiguration;
+}
+
+/*!
+ \fn QAudioDevicePrivate QAudioDevice::handle() const
\internal
*/
-QAudioDevice::QAudioDevice(QAudioDevicePrivate *p)
- : d(p)
-{}
+/*!
+ \internal
+*/
+QAudioDevice::QAudioDevice(QAudioDevicePrivate *p) : d(p) { }
/*!
- returns whether this device is an input or output device.
+ \enum QAudioDevice::Mode
+
+ Describes the mode of this device.
+
+ \value Null
+ A null device.
+ \value Input
+ An input device.
+ \value Output
+ An output device.
+*/
+
+/*!
+ \qmlproperty enumeration QtMultimedia::audioDevice::mode
+
+ Holds whether this device is an input or output device.
+
+ The returned value can be one of the following:
+
+
+ \value audioDevice.Null A null device.
+ \value audioDevice.Input input device.
+ \value audioDevice.Output An output device.
+
+*/
+
+/*!
+ \property QAudioDevice::mode
+
+ Returns whether this device is an input or output device.
*/
QAudioDevice::Mode QAudioDevice::mode() const
{
@@ -300,3 +369,5 @@ QDebug operator<<(QDebug dbg, QAudioDevice::Mode mode)
#endif
QT_END_NAMESPACE
+
+#include "moc_qaudiodevice.cpp"
diff --git a/src/multimedia/audio/qaudiodevice.h b/src/multimedia/audio/qaudiodevice.h
index f414af88f..abd1b654c 100644
--- a/src/multimedia/audio/qaudiodevice.h
+++ b/src/multimedia/audio/qaudiodevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QAUDIODEVICEINFO_H
@@ -49,7 +13,7 @@
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
#include <QtMultimedia/qaudioformat.h>
QT_BEGIN_NAMESPACE
@@ -79,7 +43,7 @@ public:
QAudioDevice(QAudioDevice &&other) noexcept = default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QAudioDevice)
void swap(QAudioDevice &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
QAudioDevice& operator=(const QAudioDevice& other);
@@ -102,6 +66,7 @@ public:
int minimumChannelCount() const;
int maximumChannelCount() const;
QList<QAudioFormat::SampleFormat> supportedSampleFormats() const;
+ QAudioFormat::ChannelConfig channelConfiguration() const;
const QAudioDevicePrivate *handle() const { return d.get(); }
private:
diff --git a/src/multimedia/audio/qaudiodevice_p.h b/src/multimedia/audio/qaudiodevice_p.h
index 9ab75800c..c59856d72 100644
--- a/src/multimedia/audio/qaudiodevice_p.h
+++ b/src/multimedia/audio/qaudiodevice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 QAUDIODEVICEINFO_P_H
@@ -53,10 +17,11 @@
//
#include <QtMultimedia/qaudiodevice.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
-class QAudioDevicePrivate : public QSharedData
+class Q_MULTIMEDIA_EXPORT QAudioDevicePrivate : public QSharedData
{
public:
QAudioDevicePrivate(const QByteArray &i, QAudioDevice::Mode m)
@@ -64,7 +29,7 @@ public:
mode(m)
{}
virtual ~QAudioDevicePrivate();
- QByteArray id;
+ QByteArray id;
QAudioDevice::Mode mode = QAudioDevice::Output;
bool isDefault = false;
@@ -75,6 +40,19 @@ public:
int minimumChannelCount = 0;
int maximumChannelCount = 0;
QList<QAudioFormat::SampleFormat> supportedSampleFormats;
+ QAudioFormat::ChannelConfig channelConfiguration = QAudioFormat::ChannelConfigUnknown;
+
+ bool operator == (const QAudioDevicePrivate &other) const
+ {
+ return id == other.id && mode == other.mode && isDefault == other.isDefault
+ && preferredFormat == other.preferredFormat && description == other.description
+ && minimumSampleRate == other.minimumSampleRate
+ && maximumSampleRate == other.maximumSampleRate
+ && minimumChannelCount == other.minimumChannelCount
+ && maximumChannelCount == other.maximumChannelCount
+ && supportedSampleFormats == other.supportedSampleFormats
+ && channelConfiguration == other.channelConfiguration;
+ }
QAudioDevice create() { return QAudioDevice(this); }
};
diff --git a/src/multimedia/audio/qaudioformat.cpp b/src/multimedia/audio/qaudioformat.cpp
index 5eee80cda..9f51759b5 100644
--- a/src/multimedia/audio/qaudioformat.cpp
+++ b/src/multimedia/audio/qaudioformat.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 <QDebug>
#include <qaudioformat.h>
#include <qalgorithms.h>
@@ -117,9 +81,15 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QAudioFormat& QAudioFormat::operator=(const QAudioFormat &other)
+ \fn bool QAudioFormat::operator==(const QAudioFormat &a, const QAudioFormat &b)
- Assigns \a other to this QAudioFormat implementation.
+ Returns \c true if audio format \a a is equal to \a b, otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QAudioFormat::operator!=(const QAudioFormat &a, const QAudioFormat &b)
+
+ Returns \c true if audio format \a a is not equal to \a b, otherwise returns \c false.
*/
/*!
@@ -172,7 +142,10 @@ QT_BEGIN_NAMESPACE
\value BottomFrontLeft
\value BottomFrontRight
*/
-
+/*!
+ \variable QAudioFormat::NChannelPositions
+ \internal
+*/
/*!
\enum QAudioFormat::ChannelConfig
@@ -182,13 +155,22 @@ QT_BEGIN_NAMESPACE
and 7.1 surround configurations.
\value ChannelConfigUnknown The channel configuration is not known.
- \value ChannelConfigMono The audio has one Center channel
- \value ChannelConfigStereo The audio has two channels, Left and Right
- \value ChannelConfig2Dot1 The audio has three channels, Left, Right and LFE (low frequency effect)
- \value ChannelConfigSurround5Dot0 The audio has five channels, Left, Right, Center, BackLeft, BackRight
- \value ChannelConfigSurround5Dot1 The audio has 6 channels, Left, Right, Center, LFE, BackLeft and BackRight
- \value ChannelConfigSurround7Dot0 The audio has 7 channels, Left, Right, Center, BackLeft, BackRight, SideLeft and SideRight
- \value ChannelConfigSurround7Dot1 The audio has 8 channels, Left, Right, Center, LFE, BackLeft, BackRight, SideLeft and SideRight
+ \value ChannelConfigMono The audio has one Center channel.
+ \value ChannelConfigStereo The audio has two channels, Left and Right.
+ \value ChannelConfig2Dot1 The audio has three channels, Left, Right and
+ LFE (low frequency effect).
+ \value ChannelConfig3Dot0 The audio has three channels, Left, Right, and
+ Center.
+ \value ChannelConfig3Dot1 The audio has four channels, Left, Right, Center,
+ and LFE (low frequency effect).
+ \value ChannelConfigSurround5Dot0 The audio has five channels, Left, Right,
+ Center, BackLeft, and BackRight.
+ \value ChannelConfigSurround5Dot1 The audio has 6 channels, Left, Right,
+ Center, LFE, BackLeft, and BackRight.
+ \value ChannelConfigSurround7Dot0 The audio has 7 channels, Left, Right,
+ Center, BackLeft, BackRight, SideLeft, and SideRight.
+ \value ChannelConfigSurround7Dot1 The audio has 8 channels, Left, Right,
+ Center, LFE, BackLeft, BackRight, SideLeft, and SideRight.
*/
/*!
@@ -228,7 +210,11 @@ int QAudioFormat::channelOffset(AudioChannelPosition channel) const noexcept
config to ChannelConfigUnknown.
*/
+/*!
+ \fn template <typename... Args> QAudioFormat::ChannelConfig QAudioFormat::channelConfig(Args... channels)
+ Returns the current channel configuration for the given \a channels.
+*/
/*!
\fn QAudioFormat::ChannelConfig QAudioFormat::channelConfig() const noexcept
@@ -374,11 +360,15 @@ float QAudioFormat::normalizedSampleValue(const void *sample) const
{
switch (m_sampleFormat) {
case UInt8:
- return ((float)*reinterpret_cast<const quint8 *>(sample))/(float)std::numeric_limits<qint8>::max() - 1.;
+ return ((float)*reinterpret_cast<const quint8 *>(sample))
+ / (float)std::numeric_limits<qint8>::max()
+ - 1.;
case Int16:
- return ((float)*reinterpret_cast<const qint16 *>(sample))/(float)std::numeric_limits<qint16>::max();
+ return ((float)*reinterpret_cast<const qint16 *>(sample))
+ / (float)std::numeric_limits<qint16>::max();
case Int32:
- return ((float)*reinterpret_cast<const qint32 *>(sample))/(float)std::numeric_limits<qint32>::max();
+ return ((float)*reinterpret_cast<const qint32 *>(sample))
+ / (float)std::numeric_limits<qint32>::max();
case Float:
return *reinterpret_cast<const float *>(sample);
case Unknown:
@@ -390,6 +380,53 @@ float QAudioFormat::normalizedSampleValue(const void *sample) const
}
/*!
+ Returns a default channel configuration for \a channelCount.
+
+ Default configurations are defined for up to 8 channels, and correspond to
+ standard Mono, Stereo and Surround configurations. For higher channel counts,
+ this simply uses the first \a channelCount audio channels defined in
+ \l QAudioFormat::AudioChannelPosition.
+*/
+QAudioFormat::ChannelConfig QAudioFormat::defaultChannelConfigForChannelCount(int channelCount)
+{
+ QAudioFormat::ChannelConfig config;
+ switch (channelCount) {
+ case 0:
+ config = QAudioFormat::ChannelConfigUnknown;
+ break;
+ case 1:
+ config = QAudioFormat::ChannelConfigMono;
+ break;
+ case 2:
+ config = QAudioFormat::ChannelConfigStereo;
+ break;
+ case 3:
+ config = QAudioFormat::ChannelConfig2Dot1;
+ break;
+ case 4:
+ config = QAudioFormat::channelConfig(QAudioFormat::FrontLeft, QAudioFormat::FrontRight,
+ QAudioFormat::BackLeft, QAudioFormat::BackRight);
+ break;
+ case 5:
+ config = QAudioFormat::ChannelConfigSurround5Dot0;
+ break;
+ case 6:
+ config = QAudioFormat::ChannelConfigSurround5Dot1;
+ break;
+ case 7:
+ config = QAudioFormat::ChannelConfigSurround7Dot0;
+ break;
+ case 8:
+ config = QAudioFormat::ChannelConfigSurround7Dot1;
+ break;
+ default:
+ // give up, simply use the first n channels
+ config = QAudioFormat::ChannelConfig((1 << (channelCount + 1)) - 1);
+ }
+ return config;
+}
+
+/*!
\enum QAudioFormat::SampleFormat
Qt will always expect and use samples in the endianness of the host platform.
@@ -398,7 +435,7 @@ float QAudioFormat::normalizedSampleValue(const void *sample) const
QAudioBuffer.
\value Unknown Not Set
- \value UInt8 Samples are unsigned 8 bit signed integers
+ \value UInt8 Samples are 8 bit unsigned integers
\value Int16 Samples are 16 bit signed integers
\value Int32 Samples are 32 bit signed integers
\value Float Samples are floats
@@ -432,12 +469,10 @@ QDebug operator<<(QDebug dbg, QAudioFormat::SampleFormat type)
QDebug operator<<(QDebug dbg, const QAudioFormat &f)
{
- dbg << "QAudioFormat(" << f.sampleRate() << "Hz, " << f.channelCount() << "Channels, " << f.sampleFormat() << "Format";
+ dbg << "QAudioFormat(" << f.sampleRate() << "Hz, " << f.channelCount() << "Channels, "
+ << f.sampleFormat() << "Format )";
return dbg;
}
#endif
-
-
QT_END_NAMESPACE
-
diff --git a/src/multimedia/audio/qaudioformat.h b/src/multimedia/audio/qaudioformat.h
index 40e8ed8eb..a04ab6e1a 100644
--- a/src/multimedia/audio/qaudioformat.h
+++ b/src/multimedia/audio/qaudioformat.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QAUDIOFORMAT_H
@@ -81,28 +45,31 @@ public:
FrontLeftOfCenter,
FrontRightOfCenter,
BackCenter,
- LFE2,
SideLeft,
SideRight,
+ TopCenter,
TopFrontLeft,
- TopFrontRight,
TopFrontCenter,
- TopCenter,
+ TopFrontRight,
TopBackLeft,
+ TopBackCenter,
TopBackRight,
+ LFE2,
TopSideLeft,
TopSideRight,
- TopBackCenter,
BottomFrontCenter,
BottomFrontLeft,
BottomFrontRight
};
+ static constexpr int NChannelPositions = BottomFrontRight + 1;
enum ChannelConfig : quint32 {
ChannelConfigUnknown = 0,
ChannelConfigMono = QtPrivate::channelConfig(FrontCenter),
ChannelConfigStereo = QtPrivate::channelConfig(FrontLeft, FrontRight),
ChannelConfig2Dot1 = QtPrivate::channelConfig(FrontLeft, FrontRight, LFE),
+ ChannelConfig3Dot0 = QtPrivate::channelConfig(FrontLeft, FrontRight, FrontCenter),
+ ChannelConfig3Dot1 = QtPrivate::channelConfig(FrontLeft, FrontRight, FrontCenter, LFE),
ChannelConfigSurround5Dot0 = QtPrivate::channelConfig(FrontLeft, FrontRight, FrontCenter, BackLeft, BackRight),
ChannelConfigSurround5Dot1 = QtPrivate::channelConfig(FrontLeft, FrontRight, FrontCenter, LFE, BackLeft, BackRight),
ChannelConfigSurround7Dot0 = QtPrivate::channelConfig(FrontLeft, FrontRight, FrontCenter, BackLeft, BackRight, SideLeft, SideRight),
@@ -110,7 +77,7 @@ public:
};
template <typename... Args>
- static ChannelConfig channelConfig(Args... channels)
+ static constexpr ChannelConfig channelConfig(Args... channels)
{
return ChannelConfig(QtPrivate::channelConfig(channels...));
}
@@ -171,6 +138,8 @@ public:
return !(a == b);
}
+ static Q_MULTIMEDIA_EXPORT ChannelConfig defaultChannelConfigForChannelCount(int channelCount);
+
private:
SampleFormat m_sampleFormat = SampleFormat::Unknown;
short m_channelCount = 0;
diff --git a/src/multimedia/audio/qaudiohelpers.cpp b/src/multimedia/audio/qaudiohelpers.cpp
index 1e7c4ac81..c2d8681c6 100644
--- a/src/multimedia/audio/qaudiohelpers.cpp
+++ b/src/multimedia/audio/qaudiohelpers.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qaudiohelpers_p.h"
@@ -60,7 +24,7 @@ template<class T> struct signedVersion {};
template<> struct signedVersion<quint8>
{
using TS = qint8;
- enum {offset = 0x80};
+ static constexpr int offset = 0x80;
};
template<class T> void adjustUnsignedSamples(qreal factor, const void *src, void *dst, int samples)
diff --git a/src/multimedia/audio/qaudiohelpers_p.h b/src/multimedia/audio/qaudiohelpers_p.h
index 33ea308d3..81e6c6382 100644
--- a/src/multimedia/audio/qaudiohelpers_p.h
+++ b/src/multimedia/audio/qaudiohelpers_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 QAUDIOHELPERS_H
#define QAUDIOHELPERS_H
@@ -52,12 +16,13 @@
//
#include <qaudioformat.h>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
namespace QAudioHelperInternal
{
-void qMultiplySamples(qreal factor, const QAudioFormat& format, const void *src, void* dest, int len);
+Q_MULTIMEDIA_EXPORT void qMultiplySamples(qreal factor, const QAudioFormat& format, const void *src, void* dest, int len);
}
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp
index 431e2a871..dc7d7335f 100644
--- a/src/multimedia/audio/qaudioinput.cpp
+++ b/src/multimedia/audio/qaudioinput.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qaudioinput.h>
#include <qaudiodevice.h>
@@ -43,6 +7,38 @@
#include <private/qplatformaudioinput_p.h>
#include <private/qplatformmediaintegration_p.h>
+#include <utility>
+
+/*!
+ \qmltype AudioInput
+ \instantiates QAudioInput
+ \brief An audio input to be used for capturing audio in a capture session.
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+
+ \qml
+ CaptureSession {
+ id: playMusic
+ audioInput: AudioInput {
+ volume: slider.value
+ }
+ recorder: MediaRecorder { ... }
+ }
+ Slider {
+ id: slider
+ from: 0.
+ to: 1.
+ }
+ \endqml
+
+ You can use AudioInput together with a QtMultiMedia::CaptureSession to capture audio from an
+ audio input device.
+
+ \sa Camera, AudioOutput
+*/
+
/*!
\class QAudioInput
\brief Represents an input channel for audio.
@@ -55,12 +51,34 @@
to be used, muting the channel, and changing the channel's volume.
*/
+QAudioInput::QAudioInput(QObject *parent) : QAudioInput(QMediaDevices::defaultAudioInput(), parent)
+{
+}
+
+QAudioInput::QAudioInput(const QAudioDevice &device, QObject *parent)
+ : QObject(parent)
+{
+ auto maybeAudioInput = QPlatformMediaIntegration::instance()->createAudioInput(this);
+ if (maybeAudioInput) {
+ d = maybeAudioInput.value();
+ d->device = device.mode() == QAudioDevice::Input ? device : QMediaDevices::defaultAudioInput();
+ d->setAudioDevice(d->device);
+ } else {
+ d = new QPlatformAudioInput(nullptr);
+ qWarning() << "Failed to initialize QAudioInput" << maybeAudioInput.error();
+ }
+}
+
+QAudioInput::~QAudioInput()
+{
+ setDisconnectFunction({});
+ delete d;
+}
+
/*!
- \property QAudioInput::volume
- \brief The current volume.
+ \qmlproperty real QtMultimedia::AudioInput::volume
- The volume is scaled linearly, ranging from \c 0 (silence) to \c 1
- (full volume).
+ The volume is scaled linearly, ranging from \c 0 (silence) to \c 1 (full volume).
\note values outside this range will be clamped.
By default the volume is \c 1.
@@ -68,61 +86,13 @@
UI volume controls should usually be scaled non-linearly. For example,
using a logarithmic scale will produce linear changes in perceived loudness,
which is what a user would normally expect from a volume control.
- \sa QAudio::convertVolume()
+ \sa QtAudio::convertVolume()
*/
-
/*!
- \property QAudioInput::muted
- \brief The muted state of the current media.
-
- The value will be \c true if the input is muted; otherwise \c false.
-*/
-
-/*!
- \property QAudioInput::device
- \brief The audio device connected to this input.
-
- The device property represents the audio device connected to this input. A
- default constructed QAudioInput object will be connected to the system's
- default audio input at construction time.
+ \property QAudioInput::volume
- This property can be used to select any other input device listed by
- QMediaDevices::audioInputs().
+ The property returns the volume of the audio input.
*/
-
-QAudioInput::QAudioInput(QObject *parent)
- : QAudioInput(QMediaDevices::defaultAudioInput(), parent)
-{}
-
-QAudioInput::QAudioInput(const QAudioDevice &device, QObject *parent)
- : QObject(parent),
- d(QPlatformMediaIntegration::instance()->createAudioInput(this))
-{
- d->device = device;
- if (!d->device.isNull() && d->device.mode() != QAudioDevice::Input)
- d->device = QMediaDevices::defaultAudioInput();
- d->setAudioDevice(d->device);
-}
-
-QAudioInput::~QAudioInput()
-{
- delete d;
-}
-
-QAudioDevice QAudioInput::device() const
-{
- return d->device;
-}
-
-void QAudioInput::setDevice(const QAudioDevice &device)
-{
- if (device.mode() == QAudioDevice::Output)
- return;
- d->device = device;
- d->setAudioDevice(device);
- emit deviceChanged();
-}
-
float QAudioInput::volume() const
{
return d->volume;
@@ -138,6 +108,20 @@ void QAudioInput::setVolume(float volume)
emit volumeChanged(volume);
}
+/*!
+ \qmlproperty bool QtMultimedia::AudioInput::muted
+
+ This property holds whether the audio input is muted.
+
+ Defaults to \c{false}.
+*/
+
+/*!
+ \property QAudioInput::muted
+ \brief The muted state of the current media.
+
+ The value will be \c true if the input is muted; otherwise \c false.
+*/
bool QAudioInput::isMuted() const
{
return d->muted;
@@ -152,4 +136,57 @@ void QAudioInput::setMuted(bool muted)
emit mutedChanged(muted);
}
+/*!
+ \qmlproperty AudioDevice QtMultimedia::AudioInput::device
+
+ This property describes the audio device connected to this input.
+
+ The device property represents the audio device this input is connected to.
+ This property can be used to select an output device from the
+ QtMultimedia::MediaDevices::audioInputs() list.
+*/
+
+/*!
+ \property QAudioInput::device
+ \brief The audio device connected to this input.
+
+ The device property represents the audio device connected to this input.
+ This property can be used to select an input device from the
+ QMediaDevices::audioInputs() list.
+
+ You can select the system default audio input by setting this property to
+ a default constructed QAudioDevice object.
+*/
+QAudioDevice QAudioInput::device() const
+{
+ return d->device;
+}
+
+void QAudioInput::setDevice(const QAudioDevice &device)
+{
+ auto dev = device;
+ if (dev.isNull())
+ dev = QMediaDevices::defaultAudioInput();
+ if (dev.mode() != QAudioDevice::Input)
+ return;
+ if (d->device == dev)
+ return;
+ d->device = dev;
+ d->setAudioDevice(dev);
+ emit deviceChanged();
+}
+
+/*!
+ \internal
+*/
+void QAudioInput::setDisconnectFunction(std::function<void()> disconnectFunction)
+{
+ if (d->disconnectFunction) {
+ auto df = d->disconnectFunction;
+ d->disconnectFunction = {};
+ df();
+ }
+ d->disconnectFunction = std::move(disconnectFunction);
+}
+
#include "moc_qaudioinput.cpp"
diff --git a/src/multimedia/audio/qaudioinput.h b/src/multimedia/audio/qaudioinput.h
index 10c3ae1c9..6f4f6b099 100644
--- a/src/multimedia/audio/qaudioinput.h
+++ b/src/multimedia/audio/qaudioinput.h
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QAUDIOINPUTDEVICE_H
#define QAUDIOINPUTDEVICE_H
#include <QtCore/qobject.h>
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
+
+#include <functional>
QT_BEGIN_NAMESPACE
@@ -75,9 +41,10 @@ Q_SIGNALS:
void volumeChanged(float volume);
void mutedChanged(bool muted);
-public:
- QPlatformAudioInput *handle() const { return d; }
private:
+ QPlatformAudioInput *handle() const { return d; }
+ void setDisconnectFunction(std::function<void()> disconnectFunction);
+ friend class QMediaCaptureSession;
Q_DISABLE_COPY(QAudioInput)
QPlatformAudioInput *d = nullptr;
};
diff --git a/src/multimedia/audio/qaudiooutput.cpp b/src/multimedia/audio/qaudiooutput.cpp
index 5f49e8f26..3bb52a4d2 100644
--- a/src/multimedia/audio/qaudiooutput.cpp
+++ b/src/multimedia/audio/qaudiooutput.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qaudiooutput.h>
#include <qaudiodevice.h>
@@ -44,6 +8,37 @@
#include <private/qplatformmediaintegration_p.h>
/*!
+ \qmltype AudioOutput
+ \instantiates QAudioOutput
+ \brief An audio output to be used for playback or monitoring of a capture session.
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+
+ \qml
+ MediaPlayer {
+ id: playMusic
+ source: "music.wav"
+ audioOutput: AudioOutput {
+ volume: slider.value
+ }
+ }
+ Slider {
+ id: slider
+ from: 0.
+ to: 1.
+ }
+ \endqml
+
+ You can use AudioOutput together with a QtMultiMedia::MediaPlayer to play audio content, or you
+ can use it in conjunction with a MultiMedia::CaptureSession to monitor the audio processed by the
+ capture session.
+
+ \sa VideoOutput, AudioInput
+*/
+
+/*!
\class QAudioOutput
\brief Represents an output channel for audio.
\inmodule QtMultimedia
@@ -56,6 +51,49 @@
physical output device to be used, muting the channel, and changing the
channel's volume.
*/
+QAudioOutput::QAudioOutput(QObject *parent)
+ : QAudioOutput(QMediaDevices::defaultAudioOutput(), parent)
+{
+}
+
+QAudioOutput::QAudioOutput(const QAudioDevice &device, QObject *parent)
+ : QObject(parent)
+{
+ auto maybeAudioOutput = QPlatformMediaIntegration::instance()->createAudioOutput(this);
+ if (maybeAudioOutput) {
+ d = maybeAudioOutput.value();
+ d->device = device.mode() == QAudioDevice::Output ? device : QMediaDevices::defaultAudioOutput();
+ d->setAudioDevice(d->device);
+ } else {
+ d = new QPlatformAudioOutput(nullptr);
+ qWarning() << "Failed to initialize QAudioOutput" << maybeAudioOutput.error();
+ }
+}
+
+QAudioOutput::~QAudioOutput()
+{
+ setDisconnectFunction({});
+ delete d;
+}
+
+/*!
+ \qmlproperty real QtMultimedia::AudioOutput::volume
+
+ This property holds the volume of the audio output.
+
+ The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume).
+ Values outside this range will be clamped: a value lower than 0.0 is set to
+ 0.0, a value higher than 1.0 will set to 1.0.
+
+ The default volume is \c{1.0}.
+
+ UI \l{volume controls} should usually be scaled non-linearly. For example,
+ using a logarithmic scale will produce linear changes in perceived \l{loudness},
+ which is what a user would normally expect from a volume control.
+
+ See \l {QtAudio::convertVolume()}{QtMultimedia.convertVolume()}
+ for more details.
+*/
/*!
\property QAudioOutput::volume
@@ -71,64 +109,8 @@
using a logarithmic scale will produce linear changes in perceived loudness,
which is what a user would normally expect from a volume control.
- \sa QAudio::convertVolume()
+ \sa QtAudio::convertVolume()
*/
-
-/*!
- \property QAudioOutput::muted
- \brief The muted state of the current media.
-
- The value will be \c true if the output is muted; otherwise \c{false}.
-*/
-
-/*!
- \property QAudioOutput::device
- \brief The audio device connected to this output.
-
- The device property represents the audio device connected to this output.
- A default constructed
- QAudioOutput object will be connected to the systems default audio output at
- construction time.
-
- This property can be used to select any other output device listed by
- QMediaDevices::audioOutputs().
-*/
-
-QAudioOutput::QAudioOutput(QObject *parent)
- : QAudioOutput(QMediaDevices::defaultAudioOutput(), parent)
-{}
-
-QAudioOutput::QAudioOutput(const QAudioDevice &device, QObject *parent)
- : QObject(parent),
- d(QPlatformMediaIntegration::instance()->createAudioOutput(this))
-{
- d->device = device;
- if (!d->device.isNull() && d->device.mode() != QAudioDevice::Output)
- d->device = QMediaDevices::defaultAudioOutput();
- d->setAudioDevice(d->device);
-}
-
-QAudioOutput::~QAudioOutput()
-{
- delete d;
-}
-
-QAudioDevice QAudioOutput::device() const
-{
- return d->device;
-}
-
-void QAudioOutput::setDevice(const QAudioDevice &device)
-{
- if (!device.isNull() && device.mode() != QAudioDevice::Output)
- return;
- if (d->device == device)
- return;
- d->device = device;
- d->setAudioDevice(device);
- emit deviceChanged();
-}
-
float QAudioOutput::volume() const
{
return d->volume;
@@ -144,6 +126,20 @@ void QAudioOutput::setVolume(float volume)
emit volumeChanged(volume);
}
+/*!
+ \qmlproperty bool QtMultimedia::AudioOutput::muted
+
+ This property holds whether the audio output is muted.
+
+ Defaults to \c{false}.
+*/
+
+/*!
+ \property QAudioOutput::muted
+ \brief The muted state of the current media.
+
+ The value will be \c true if the output is muted; otherwise \c{false}.
+*/
bool QAudioOutput::isMuted() const
{
return d->muted;
@@ -158,4 +154,56 @@ void QAudioOutput::setMuted(bool muted)
emit mutedChanged(muted);
}
+/*!
+ \qmlproperty AudioDevice QtMultimedia::AudioOutput::device
+
+ This property describes the audio device connected to this output.
+
+ The device property represents the audio device this output is connected to.
+ This property can be used to select an output device from the
+ QtMultimedia::MediaDevices::audioOutputs() list.
+*/
+
+/*!
+ \property QAudioOutput::device
+ \brief The audio device connected to this output.
+
+ The device property represents the audio device this output is connected to.
+ This property can be used to select an output device from the
+ QMediaDevices::audioOutputs() list.
+ You can select the system default audio output by setting this property to
+ a default constructed QAudioDevice object.
+*/
+QAudioDevice QAudioOutput::device() const
+{
+ return d->device;
+}
+
+void QAudioOutput::setDevice(const QAudioDevice &device)
+{
+ auto dev = device;
+ if (dev.isNull())
+ dev = QMediaDevices::defaultAudioOutput();
+ if (dev.mode() != QAudioDevice::Output)
+ return;
+ if (d->device == dev)
+ return;
+ d->device = dev;
+ d->setAudioDevice(dev);
+ emit deviceChanged();
+}
+
+/*!
+ \internal
+*/
+void QAudioOutput::setDisconnectFunction(std::function<void()> disconnectFunction)
+{
+ if (d->disconnectFunction) {
+ auto df = d->disconnectFunction;
+ d->disconnectFunction = {};
+ df();
+ }
+ d->disconnectFunction = std::move(disconnectFunction);
+}
+
#include "moc_qaudiooutput.cpp"
diff --git a/src/multimedia/audio/qaudiooutput.h b/src/multimedia/audio/qaudiooutput.h
index 0f1461a55..643d19f94 100644
--- a/src/multimedia/audio/qaudiooutput.h
+++ b/src/multimedia/audio/qaudiooutput.h
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QAUDIOOUTPUTDEVICE_H
#define QAUDIOOUTPUTDEVICE_H
#include <QtCore/qobject.h>
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
+
+#include <functional>
QT_BEGIN_NAMESPACE
@@ -75,9 +41,11 @@ Q_SIGNALS:
void volumeChanged(float volume);
void mutedChanged(bool muted);
-public:
- QPlatformAudioOutput *handle() const { return d; }
private:
+ QPlatformAudioOutput *handle() const { return d; }
+ void setDisconnectFunction(std::function<void()> disconnectFunction);
+ friend class QMediaCaptureSession;
+ friend class QMediaPlayer;
Q_DISABLE_COPY(QAudioOutput)
QPlatformAudioOutput *d = nullptr;
};
diff --git a/src/multimedia/audio/qaudiosink.cpp b/src/multimedia/audio/qaudiosink.cpp
index 6b16a71aa..12263d32a 100644
--- a/src/multimedia/audio/qaudiosink.cpp
+++ b/src/multimedia/audio/qaudiosink.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qaudio.h"
@@ -81,21 +45,22 @@ QT_BEGIN_NAMESPACE
After the file has finished playing, we need to stop the device:
- \snippet multimedia-snippets/audio.cpp Audio output state changed
+ \snippet multimedia-snippets/audio.cpp Audio output stop
At any given time, the QAudioSink will be in one of four states:
active, suspended, stopped, or idle. These states are described
- by the QAudio::State enum.
+ by the QtAudio::State enum.
State changes are reported through the stateChanged() signal. You
can use this signal to, for instance, update the GUI of the
application; the mundane example here being changing the state of
a \c { play/pause } button. You request a state change directly
with suspend(), stop(), reset(), resume(), and start().
- If an error occurs, you can fetch the \l{QAudio::Error}{error
- type} with the error() function. Please see the QAudio::Error enum
- for a description of the possible errors that are reported. When
- an error is encountered, the state changes to QAudio::StoppedState.
+ If an error occurs, you can fetch the \l{QtAudio::Error}{error
+ type} with the error() function. Please see the QtAudio::Error enum
+ for a description of the possible errors that are reported. When
+ QtAudio::UnderrunError is encountered, the state changes to QtAudio::IdleState,
+ when another error is encountered, the state changes to QtAudio::StoppedState.
You can check for errors by connecting to the stateChanged()
signal:
@@ -122,13 +87,26 @@ QAudioSink::QAudioSink(const QAudioFormat &format, QObject *parent)
QAudioSink::QAudioSink(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
QObject(parent)
{
- d = QPlatformMediaIntegration::instance()->devices()->audioOutputDevice(format, audioDevice);
- if (d) {
- connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
- }
+ d = QPlatformMediaIntegration::instance()->mediaDevices()->audioOutputDevice(format, audioDevice, parent);
+ if (d)
+ connect(d, &QPlatformAudioSink::stateChanged, this, [this](QAudio::State state) {
+ // if the signal has been emitted from another thread,
+ // the state may be already changed by main one
+ if (state == d->state())
+ emit stateChanged(state);
+ });
+ else
+ qWarning() << ("No audio device detected");
}
/*!
+ \fn bool QAudioSink::isNull() const
+
+ Returns \c true is the QAudioSink instance is \c null, otherwise returns
+ \c false.
+*/
+
+/*!
Destroys this audio output.
This will release any system resources used and free any buffers.
@@ -144,7 +122,7 @@ QAudioSink::~QAudioSink()
*/
QAudioFormat QAudioSink::format() const
{
- return d->format();
+ return d ? d->format() : QAudioFormat();
}
/*!
@@ -153,16 +131,18 @@ QAudioFormat QAudioSink::format() const
\l{QIODevice::ReadWrite}{ReadWrite} modes.
If the QAudioSink is able to successfully output audio data, state() returns
- QAudio::ActiveState, error() returns QAudio::NoError
+ QtAudio::ActiveState, error() returns QtAudio::NoError
and the stateChanged() signal is emitted.
- If a problem occurs during this process, error() returns QAudio::OpenError,
- state() returns QAudio::StoppedState and the stateChanged() signal is emitted.
+ If a problem occurs during this process, error() returns QtAudio::OpenError,
+ state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
\sa QIODevice
*/
void QAudioSink::start(QIODevice* device)
{
+ if (!d)
+ return;
d->elapsedTime.restart();
d->start(device);
}
@@ -176,16 +156,18 @@ void QAudioSink::start(QIODevice* device)
if you start another stream.
If the QAudioSink is able to access the system's audio device, state() returns
- QAudio::IdleState, error() returns QAudio::NoError
+ QtAudio::IdleState, error() returns QtAudio::NoError
and the stateChanged() signal is emitted.
- If a problem occurs during this process, error() returns QAudio::OpenError,
- state() returns QAudio::StoppedState and the stateChanged() signal is emitted.
+ If a problem occurs during this process, error() returns QtAudio::OpenError,
+ state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
\sa QIODevice
*/
QIODevice* QAudioSink::start()
{
+ if (!d)
+ return nullptr;
d->elapsedTime.restart();
return d->start();
}
@@ -193,12 +175,13 @@ QIODevice* QAudioSink::start()
/*!
Stops the audio output, detaching from the system resource.
- Sets error() to QAudio::NoError, state() to QAudio::StoppedState and
+ Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
emit stateChanged() signal.
*/
void QAudioSink::stop()
{
- d->stop();
+ if (d)
+ d->stop();
}
/*!
@@ -207,42 +190,44 @@ void QAudioSink::stop()
*/
void QAudioSink::reset()
{
- d->reset();
+ if (d)
+ d->reset();
}
/*!
Stops processing audio data, preserving buffered audio data.
- Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and
+ Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
emits stateChanged() signal.
*/
void QAudioSink::suspend()
{
- d->suspend();
+ if (d)
+ d->suspend();
}
/*!
Resumes processing audio data after a suspend().
- Sets error() to QAudio::NoError.
- Sets state() to QAudio::ActiveState if you previously called start(QIODevice*).
- Sets state() to QAudio::IdleState if you previously called start().
- emits stateChanged() signal.
+ Sets state() to the state the sink had when suspend() was called, and sets
+ error() to QAudioError::NoError. This function does nothing if the audio sink's
+ state is not QtAudio::SuspendedState.
*/
void QAudioSink::resume()
{
- d->resume();
+ if (d)
+ d->resume();
}
/*!
Returns the number of free bytes available in the audio buffer.
- \note The returned value is only valid while in QAudio::ActiveState or QAudio::IdleState
+ \note The returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
state, otherwise returns zero.
*/
qsizetype QAudioSink::bytesFree() const
{
- return d->bytesFree();
+ return d ? d->bytesFree() : 0;
}
/*!
@@ -255,7 +240,8 @@ qsizetype QAudioSink::bytesFree() const
*/
void QAudioSink::setBufferSize(qsizetype value)
{
- d->setBufferSize(value);
+ if (d)
+ d->setBufferSize(value);
}
/*!
@@ -269,7 +255,7 @@ void QAudioSink::setBufferSize(qsizetype value)
*/
qsizetype QAudioSink::bufferSize() const
{
- return d->bufferSize();
+ return d ? d->bufferSize() : 0;
}
/*!
@@ -278,7 +264,7 @@ qsizetype QAudioSink::bufferSize() const
*/
qint64 QAudioSink::processedUSecs() const
{
- return d->processedUSecs();
+ return d ? d->processedUSecs() : 0;
}
/*!
@@ -287,23 +273,23 @@ qint64 QAudioSink::processedUSecs() const
*/
qint64 QAudioSink::elapsedUSecs() const
{
- return d->state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
+ return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
}
/*!
Returns the error state.
*/
-QAudio::Error QAudioSink::error() const
+QtAudio::Error QAudioSink::error() const
{
- return d->error();
+ return d ? d->error() : QAudio::OpenError;
}
/*!
Returns the state of audio processing.
*/
-QAudio::State QAudioSink::state() const
+QtAudio::State QAudioSink::state() const
{
- return d->state();
+ return d ? d->state() : QAudio::StoppedState;
}
/*!
@@ -320,10 +306,12 @@ QAudio::State QAudioSink::state() const
UI volume controls should usually be scaled non-linearly. For example, using
a logarithmic scale will produce linear changes in perceived loudness, which
is what a user would normally expect from a volume control. See
- QAudio::convertVolume() for more details.
+ QtAudio::convertVolume() for more details.
*/
void QAudioSink::setVolume(qreal volume)
{
+ if (!d)
+ return;
qreal v = qBound(qreal(0.0), volume, qreal(1.0));
d->setVolume(v);
}
@@ -333,13 +321,17 @@ void QAudioSink::setVolume(qreal volume)
*/
qreal QAudioSink::volume() const
{
- return d->volume();
+ return d ? d->volume() : 1.0;
}
/*!
- \fn QAudioSink::stateChanged(QAudio::State state)
+ \fn QAudioSink::stateChanged(QtAudio::State state)
This signal is emitted when the device \a state has changed.
This is the current state of the audio output.
+
+ \note The QtAudio namespace was named QAudio up to and including Qt 6.6.
+ String-based connections to this signal have to use \c{QAudio::State} as
+ the parameter type: \c{connect(source, SIGNAL(stateChanged(QAudio::State)), ...);}
*/
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiosink.h b/src/multimedia/audio/qaudiosink.h
index 049011e98..e071e6fbc 100644
--- a/src/multimedia/audio/qaudiosink.h
+++ b/src/multimedia/audio/qaudiosink.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QAUDIOOUTPUT_H
@@ -45,7 +9,7 @@
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
#include <QtMultimedia/qaudioformat.h>
#include <QtMultimedia/qaudiodevice.h>
@@ -85,14 +49,19 @@ public:
qint64 processedUSecs() const;
qint64 elapsedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
+ QtAudio::Error error() const;
+ QtAudio::State state() const;
void setVolume(qreal);
qreal volume() const;
Q_SIGNALS:
+#if defined(Q_QDOC)
+ void stateChanged(QtAudio::State state);
+#else
+ // use QAudio here to keep string-based connections working
void stateChanged(QAudio::State state);
+#endif
private:
Q_DISABLE_COPY(QAudioSink)
diff --git a/src/multimedia/audio/qaudiosource.cpp b/src/multimedia/audio/qaudiosource.cpp
index a5f6de89d..1ed5e82bc 100644
--- a/src/multimedia/audio/qaudiosource.cpp
+++ b/src/multimedia/audio/qaudiosource.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qaudio.h"
@@ -89,7 +53,7 @@ QT_BEGIN_NAMESPACE
At any point in time, QAudioSource will be in one of four states:
active, suspended, stopped, or idle. These states are specified by
- the QAudio::State enum. You can request a state change directly through
+ the QtAudio::State enum. You can request a state change directly through
suspend(), resume(), stop(), reset(), and start(). The current
state is reported by state(). QAudioSink will also signal you
when the state changes (stateChanged()).
@@ -102,8 +66,8 @@ QT_BEGIN_NAMESPACE
which states the QAudioSource has been in.
If an error should occur, you can fetch its reason with error().
- The possible error reasons are described by the QAudio::Error
- enum. The QAudioSource will enter the \l{QAudio::}{StoppedState} when
+ The possible error reasons are described by the QtAudio::Error
+ enum. The QAudioSource will enter the \l{QtAudio::}{StoppedState} when
an error is encountered. Connect to the stateChanged() signal to
handle the error:
@@ -132,12 +96,27 @@ QAudioSource::QAudioSource(const QAudioFormat &format, QObject *parent)
QAudioSource::QAudioSource(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
QObject(parent)
{
- d = QPlatformMediaIntegration::instance()->devices()->audioInputDevice(format, audioDevice);
- if (d)
- connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+ d = QPlatformMediaIntegration::instance()->mediaDevices()->audioInputDevice(format, audioDevice, parent);
+ if (d) {
+ connect(d, &QPlatformAudioSource::stateChanged, this, [this](QAudio::State state) {
+ // if the signal has been emitted from another thread,
+ // the state may be already changed by main one
+ if (state == d->state())
+ emit stateChanged(state);
+ });
+ }
+ else
+ qWarning() << ("No audio device detected");
+
}
/*!
+ \fn bool QAudioSource::isNull() const
+
+ Returns \c true if the audio source is \c null, otherwise returns \c false.
+*/
+
+/*!
Destroy this audio input.
*/
@@ -152,17 +131,19 @@ QAudioSource::~QAudioSource()
\l{QIODevice::Append}{Append} or \l{QIODevice::ReadWrite}{ReadWrite} modes.
If the QAudioSource is able to successfully get audio data, state() returns
- either QAudio::ActiveState or QAudio::IdleState, error() returns QAudio::NoError
+ either QtAudio::ActiveState or QtAudio::IdleState, error() returns QtAudio::NoError
and the stateChanged() signal is emitted.
- If a problem occurs during this process, error() returns QAudio::OpenError,
- state() returns QAudio::StoppedState and the stateChanged() signal is emitted.
+ If a problem occurs during this process, error() returns QtAudio::OpenError,
+ state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
\sa QIODevice
*/
void QAudioSource::start(QIODevice* device)
{
+ if (!d)
+ return;
d->elapsedTime.start();
d->start(device);
}
@@ -176,17 +157,19 @@ void QAudioSource::start(QIODevice* device)
if you start another stream.
If the QAudioSource is able to access the system's audio device, state() returns
- QAudio::IdleState, error() returns QAudio::NoError
+ QtAudio::IdleState, error() returns QtAudio::NoError
and the stateChanged() signal is emitted.
- If a problem occurs during this process, error() returns QAudio::OpenError,
- state() returns QAudio::StoppedState and the stateChanged() signal is emitted.
+ If a problem occurs during this process, error() returns QtAudio::OpenError,
+ state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
\sa QIODevice
*/
QIODevice* QAudioSource::start()
{
+ if (!d)
+ return nullptr;
d->elapsedTime.start();
return d->start();
}
@@ -197,19 +180,20 @@ QIODevice* QAudioSource::start()
QAudioFormat QAudioSource::format() const
{
- return d->format();
+ return d ? d->format() : QAudioFormat();
}
/*!
Stops the audio input, detaching from the system resource.
- Sets error() to QAudio::NoError, state() to QAudio::StoppedState and
+ Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
emit stateChanged() signal.
*/
void QAudioSource::stop()
{
- d->stop();
+ if (d)
+ d->stop();
}
/*!
@@ -218,33 +202,36 @@ void QAudioSource::stop()
void QAudioSource::reset()
{
- d->reset();
+ if (d)
+ d->reset();
}
/*!
Stops processing audio data, preserving buffered audio data.
- Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and
+ Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
emit stateChanged() signal.
*/
void QAudioSource::suspend()
{
- d->suspend();
+ if (d)
+ d->suspend();
}
/*!
Resumes processing audio data after a suspend().
- Sets error() to QAudio::NoError.
- Sets state() to QAudio::ActiveState if you previously called start(QIODevice*).
- Sets state() to QAudio::IdleState if you previously called start().
+ Sets error() to QtAudio::NoError.
+ Sets state() to QtAudio::ActiveState if you previously called start(QIODevice*).
+ Sets state() to QtAudio::IdleState if you previously called start().
emits stateChanged() signal.
*/
void QAudioSource::resume()
{
- d->resume();
+ if (d)
+ d->resume();
}
/*!
@@ -259,7 +246,8 @@ void QAudioSource::resume()
void QAudioSource::setBufferSize(qsizetype value)
{
- d->setBufferSize(value);
+ if (d)
+ d->setBufferSize(value);
}
/*!
@@ -274,13 +262,13 @@ void QAudioSource::setBufferSize(qsizetype value)
qsizetype QAudioSource::bufferSize() const
{
- return d->bufferSize();
+ return d ? d->bufferSize() : 0;
}
/*!
Returns the amount of audio data available to read in bytes.
- Note: returned value is only valid while in QAudio::ActiveState or QAudio::IdleState
+ Note: returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
state, otherwise returns zero.
*/
@@ -290,7 +278,7 @@ qsizetype QAudioSource::bytesAvailable() const
-If not ActiveState|IdleState, return 0
-return amount of audio data available to read
*/
- return d->bytesReady();
+ return d ? d->bytesReady() : 0;
}
/*!
@@ -309,6 +297,8 @@ qsizetype QAudioSource::bytesAvailable() const
*/
void QAudioSource::setVolume(qreal volume)
{
+ if (!d)
+ return;
qreal v = qBound(qreal(0.0), volume, qreal(1.0));
d->setVolume(v);
}
@@ -321,7 +311,7 @@ void QAudioSource::setVolume(qreal volume)
*/
qreal QAudioSource::volume() const
{
- return d->volume();
+ return d ? d->volume() : 1.0;
}
/*!
@@ -331,7 +321,7 @@ qreal QAudioSource::volume() const
qint64 QAudioSource::processedUSecs() const
{
- return d->processedUSecs();
+ return d ? d->processedUSecs() : 0;
}
/*!
@@ -343,30 +333,34 @@ qint64 QAudioSource::processedUSecs() const
qint64 QAudioSource::elapsedUSecs() const
{
- return d->state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
+ return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
}
/*!
Returns the error state.
*/
-QAudio::Error QAudioSource::error() const
+QtAudio::Error QAudioSource::error() const
{
- return d->error();
+ return d ? d->error() : QAudio::OpenError;
}
/*!
Returns the state of audio processing.
*/
-QAudio::State QAudioSource::state() const
+QtAudio::State QAudioSource::state() const
{
- return d->state();
+ return d ? d->state() : QAudio::StoppedState;
}
/*!
- \fn QAudioSource::stateChanged(QAudio::State state)
+ \fn QAudioSource::stateChanged(QtAudio::State state)
This signal is emitted when the device \a state has changed.
+
+ \note The QtAudio namespace was named QAudio up to and including Qt 6.6.
+ String-based connections to this signal have to use \c{QAudio::State} as
+ the parameter type: \c{connect(source, SIGNAL(stateChanged(QAudio::State)), ...);}
*/
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiosource.h b/src/multimedia/audio/qaudiosource.h
index 9c11b85d3..f0ad0ceb5 100644
--- a/src/multimedia/audio/qaudiosource.h
+++ b/src/multimedia/audio/qaudiosource.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QAUDIOINPUT_H
@@ -45,7 +9,7 @@
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
#include <QtMultimedia/qaudioformat.h>
#include <QtMultimedia/qaudiodevice.h>
@@ -86,11 +50,16 @@ public:
qint64 processedUSecs() const;
qint64 elapsedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
+ QtAudio::Error error() const;
+ QtAudio::State state() const;
Q_SIGNALS:
+#if defined(Q_QDOC)
+ void stateChanged(QtAudio::State state);
+#else
+ // use QAudio here to keep string-based connections working
void stateChanged(QAudio::State state);
+#endif
private:
Q_DISABLE_COPY(QAudioSource)
diff --git a/src/multimedia/audio/qaudiostatemachine.cpp b/src/multimedia/audio/qaudiostatemachine.cpp
new file mode 100644
index 000000000..2d42200e6
--- /dev/null
+++ b/src/multimedia/audio/qaudiostatemachine.cpp
@@ -0,0 +1,150 @@
+// 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 "qaudiostatemachine_p.h"
+#include "qaudiosystem_p.h"
+#include <qpointer.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+using Notifier = QAudioStateMachine::Notifier;
+using namespace AudioStateMachineUtils;
+
+QAudioStateMachine::QAudioStateMachine(QAudioStateChangeNotifier &notifier) : m_notifier(&notifier)
+{
+}
+
+QAudioStateMachine::~QAudioStateMachine() = default;
+
+QAudio::State QAudioStateMachine::state() const
+{
+ return toAudioState(m_state.load(std::memory_order_acquire));
+}
+
+QAudio::Error QAudioStateMachine::error() const
+{
+ return toAudioError(m_state.load(std::memory_order_acquire));
+}
+
+template <typename StatesChecker, typename NewState>
+Notifier QAudioStateMachine::changeState(const StatesChecker &checker, const NewState &newState)
+{
+ if constexpr (std::is_same_v<RawState, NewState>)
+ return changeState(checker, [newState](RawState) { return newState; });
+ else {
+ RawState prevState = m_state.load(std::memory_order_relaxed);
+ const auto exchanged = multipleCompareExchange(m_state, prevState, checker, newState);
+
+ if (Q_LIKELY(exchanged))
+ return { this, newState(prevState), prevState };
+
+ return {};
+ }
+}
+
+Notifier QAudioStateMachine::stop(QAudio::Error error, bool shouldDrain, bool forceUpdateError)
+{
+ auto statesChecker =
+ makeStatesChecker(QAudio::ActiveState, QAudio::IdleState, QAudio::SuspendedState,
+ forceUpdateError ? QAudio::StoppedState : QAudio::ActiveState);
+
+ const auto state = toRawState(QAudio::StoppedState, error);
+ auto getNewState = [&](RawState prevState) {
+ const bool shouldAddFlag = shouldDrain && toAudioState(prevState) == QAudio::ActiveState;
+ return shouldAddFlag ? addDrainingFlag(state) : state;
+ };
+
+ return changeState(statesChecker, getNewState);
+}
+
+Notifier QAudioStateMachine::start(bool active)
+{
+ return changeState(makeStatesChecker(QAudio::StoppedState),
+ toRawState(active ? QAudio::ActiveState : QAudio::IdleState));
+}
+
+bool QAudioStateMachine::isActiveOrIdle() const
+{
+ const auto state = this->state();
+ return state == QAudio::ActiveState || state == QAudio::IdleState;
+}
+
+bool QAudioStateMachine::onDrained()
+{
+ return changeState(isDrainingState, removeDrainingFlag);
+}
+
+bool QAudioStateMachine::isDraining() const
+{
+ return isDrainingState(m_state.load(std::memory_order_acquire));
+}
+
+std::pair<bool, bool> QAudioStateMachine::getDrainedAndStopped() const
+{
+ const auto state = m_state.load(std::memory_order_acquire);
+ return { !isDrainingState(state), toAudioState(state) == QAudio::StoppedState };
+}
+
+Notifier QAudioStateMachine::suspend()
+{
+ // Due to the current documentation, we set QAudio::NoError.
+ // TBD: leave the previous error should be more reasonable (IgnoreError)
+ const auto error = QAudio::NoError;
+ auto result = changeState(makeStatesChecker(QAudio::ActiveState, QAudio::IdleState),
+ toRawState(QAudio::SuspendedState, error));
+
+ if (result)
+ m_suspendedInState = result.prevAudioState();
+
+ return result;
+}
+
+Notifier QAudioStateMachine::resume()
+{
+ // Due to the current documentation, we set QAudio::NoError.
+ // TBD: leave the previous error should be more reasonable (IgnoreError)
+ const auto error = QAudio::NoError;
+ return changeState(makeStatesChecker(QAudio::SuspendedState),
+ toRawState(m_suspendedInState, error));
+}
+
+Notifier QAudioStateMachine::activateFromIdle()
+{
+ return changeState(makeStatesChecker(QAudio::IdleState), toRawState(QAudio::ActiveState));
+}
+
+Notifier QAudioStateMachine::updateActiveOrIdle(bool isActive, QAudio::Error error)
+{
+ const auto state = isActive ? QAudio::ActiveState : QAudio::IdleState;
+ return changeState(makeStatesChecker(QAudio::ActiveState, QAudio::IdleState),
+ toRawState(state, error));
+}
+
+Notifier QAudioStateMachine::setError(QAudio::Error error)
+{
+ auto fixState = [error](RawState prevState) { return setStateError(prevState, error); };
+ return changeState([](RawState) { return true; }, fixState);
+}
+
+Notifier QAudioStateMachine::forceSetState(QAudio::State state, QAudio::Error error)
+{
+ return changeState([](RawState) { return true; }, toRawState(state, error));
+}
+
+void QAudioStateMachine::reset(RawState state, RawState prevState)
+{
+ auto notifier = m_notifier;
+
+ const auto audioState = toAudioState(state);
+ const auto audioError = toAudioError(state);
+
+ if (toAudioState(prevState) != audioState && notifier)
+ emit notifier->stateChanged(audioState);
+
+ // check the notifier in case the object was deleted in
+ if (toAudioError(prevState) != audioError && notifier)
+ emit notifier->errorChanged(audioError);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiostatemachine_p.h b/src/multimedia/audio/qaudiostatemachine_p.h
new file mode 100644
index 000000000..385453020
--- /dev/null
+++ b/src/multimedia/audio/qaudiostatemachine_p.h
@@ -0,0 +1,149 @@
+// 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 QAUDIOSTATEMACHINE_P_H
+#define QAUDIOSTATEMACHINE_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 "qaudiostatemachineutils_p.h"
+
+#include <qpointer.h>
+#include <atomic>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioStateChangeNotifier;
+
+/* QAudioStateMachine provides an opportunity to
+ * toggle QAudio::State with QAudio::Error in
+ * a thread-safe manner.
+ * The toggling functions return a notifier,
+ * which notifies about the change via
+ * QAudioStateChangeNotifier::stateChanged and errorChanged.
+ *
+ * The state machine is supposed to be used mostly in
+ * QAudioSink and QAudioSource implementations.
+ */
+class Q_MULTIMEDIA_EXPORT QAudioStateMachine
+{
+public:
+ using RawState = AudioStateMachineUtils::RawState;
+ class Notifier
+ {
+ public:
+ void reset()
+ {
+ if (auto stateMachine = std::exchange(m_stateMachine, nullptr))
+ stateMachine->reset(m_state, m_prevState);
+ }
+
+ ~Notifier() { reset(); }
+
+ Notifier(const Notifier &) = delete;
+ Notifier(Notifier &&other) noexcept
+ : m_stateMachine(std::exchange(other.m_stateMachine, nullptr)),
+ m_state(other.m_state),
+ m_prevState(other.m_prevState)
+ {
+ }
+
+ operator bool() const { return m_stateMachine != nullptr; }
+
+ QAudio::State prevAudioState() const { return AudioStateMachineUtils::toAudioState(m_prevState); }
+
+ QAudio::State audioState() const { return AudioStateMachineUtils::toAudioState(m_state); }
+
+ bool isDraining() const { return AudioStateMachineUtils::isDrainingState(m_state); }
+
+ bool isStateChanged() const { return prevAudioState() != audioState(); }
+
+ private:
+ Notifier(QAudioStateMachine *stateMachine = nullptr, RawState state = QAudio::StoppedState,
+ RawState prevState = QAudio::StoppedState)
+ : m_stateMachine(stateMachine), m_state(state), m_prevState(prevState)
+ {
+ }
+
+ private:
+ QAudioStateMachine *m_stateMachine;
+ RawState m_state;
+ const RawState m_prevState;
+
+ friend class QAudioStateMachine;
+ };
+
+ QAudioStateMachine(QAudioStateChangeNotifier &notifier);
+
+ ~QAudioStateMachine();
+
+ QAudio::State state() const;
+
+ QAudio::Error error() const;
+
+ bool isActiveOrIdle() const;
+
+ bool isDraining() const;
+
+ // atomicaly checks if the state is stopped and marked as drained
+ std::pair<bool, bool> getDrainedAndStopped() const;
+
+ // Stopped[draining] -> Stopped
+ bool onDrained();
+
+ // Active/Idle/Suspended -> Stopped
+ // or Active -> Stopped[draining] for shouldDrain = true
+ Notifier stop(QAudio::Error error = QAudio::NoError, bool shouldDrain = false,
+ bool forceUpdateError = false);
+
+ // Active/Idle/Suspended -> Stopped
+ Notifier stopOrUpdateError(QAudio::Error error = QAudio::NoError)
+ {
+ return stop(error, false, true);
+ }
+
+ // Stopped -> Active/Idle
+ Notifier start(bool isActive = true);
+
+ // Active/Idle -> Suspended + saves the exchanged state
+ Notifier suspend();
+
+ // Suspended -> saved state (Active/Idle)
+ Notifier resume();
+
+ // Idle -> Active
+ Notifier activateFromIdle();
+
+ // Active/Idle -> Active/Idle + updateError
+ Notifier updateActiveOrIdle(bool isActive, QAudio::Error error = QAudio::NoError);
+
+ // Any -> Any; better use more strict methods
+ Notifier forceSetState(QAudio::State state, QAudio::Error error = QAudio::NoError);
+
+ // force set the error
+ Notifier setError(QAudio::Error error);
+
+private:
+ template <typename StatesChecker, typename NewState>
+ Notifier changeState(const StatesChecker &statesChecker, const NewState &newState);
+
+ void reset(RawState state, RawState prevState);
+
+private:
+ QPointer<QAudioStateChangeNotifier> m_notifier;
+ std::atomic<RawState> m_state = QAudio::StoppedState;
+ QAudio::State m_suspendedInState = QAudio::SuspendedState;
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOSTATEMACHINE_P_H
diff --git a/src/multimedia/audio/qaudiostatemachineutils_p.h b/src/multimedia/audio/qaudiostatemachineutils_p.h
new file mode 100644
index 000000000..f80517f77
--- /dev/null
+++ b/src/multimedia/audio/qaudiostatemachineutils_p.h
@@ -0,0 +1,96 @@
+// 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 QAUDIOSTATEMACHINEUTILS_P_H
+#define QAUDIOSTATEMACHINEUTILS_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 "qaudio.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace AudioStateMachineUtils {
+
+using RawState = int;
+
+constexpr uint32_t AudioStateBitsCount = 8;
+constexpr RawState AudioStateMask = 0xFF;
+constexpr RawState AudioErrorMask = 0xFF00;
+constexpr RawState DrainingFlag = 0x10000;
+
+static_assert(!(AudioStateMask & DrainingFlag) && !(AudioStateMask & AudioErrorMask)
+ && !(AudioErrorMask & DrainingFlag),
+ "Invalid masks");
+
+constexpr bool isDrainingState(RawState state)
+{
+ return (state & DrainingFlag) != 0;
+}
+
+constexpr RawState addDrainingFlag(RawState state)
+{
+ return state | DrainingFlag;
+}
+
+constexpr RawState removeDrainingFlag(RawState state)
+{
+ return state & ~DrainingFlag;
+}
+
+constexpr QAudio::State toAudioState(RawState state)
+{
+ return QAudio::State(state & AudioStateMask);
+}
+
+constexpr QAudio::Error toAudioError(RawState state)
+{
+ return QAudio::Error((state & AudioErrorMask) >> AudioStateBitsCount);
+}
+
+constexpr RawState toRawState(QAudio::State state, QAudio::Error error = QAudio::NoError)
+{
+ return state | (error << AudioStateBitsCount);
+}
+
+constexpr RawState setStateError(RawState state, QAudio::Error error)
+{
+ return (error << AudioStateBitsCount) | (state & ~AudioErrorMask);
+}
+
+template <typename... States>
+constexpr auto makeStatesChecker(States... states)
+{
+ return [=](RawState state) {
+ state &= (AudioStateMask | DrainingFlag);
+ return (... || (state == states));
+ };
+}
+
+// ensures compareExchange (testAndSet) operation with opportunity
+// to check several states, can be considered as atomic
+template <typename T, typename Predicate, typename NewValueGetter>
+bool multipleCompareExchange(std::atomic<T> &target, T &prevValue, Predicate predicate,
+ NewValueGetter newValueGetter)
+{
+ while (predicate(prevValue))
+ if (target.compare_exchange_strong(prevValue, newValueGetter(prevValue),
+ std::memory_order_acq_rel))
+ return true;
+
+ return false;
+}
+} // namespace AudioStateMachineUtils
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOSTATEMACHINEUTILS_P_H
diff --git a/src/multimedia/audio/qaudiosystem.cpp b/src/multimedia/audio/qaudiosystem.cpp
index f1fd5bb30..355771f6b 100644
--- a/src/multimedia/audio/qaudiosystem.cpp
+++ b/src/multimedia/audio/qaudiosystem.cpp
@@ -1,254 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 <private/qtmultimediaglobal_p.h>
#include "qaudiosystem_p.h"
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QPlatformAudioSink
- \brief The QPlatformAudioSink class is a base class for audio backends.
-
- \ingroup multimedia
- \inmodule QtMultimedia
-
- QPlatformAudioSink implements audio functionality for
- QAudioSink, i.e., QAudioSink routes function calls to
- QPlatformAudioSink. For a description of the functionality that
- is implemented, see the QAudioSink class and function
- descriptions.
-
- \sa QAudioSink
-*/
-
-/*!
- \fn void QPlatformAudioSink::start(QIODevice* device)
- Uses the \a device as the QIODevice to transfer data.
-*/
-
-/*!
- \fn QIODevice* QPlatformAudioSink::start()
- Returns a pointer to the QIODevice being used to handle
- the data transfer. This QIODevice can be used to write() audio data directly.
-*/
-
-/*!
- \fn void QPlatformAudioSink::stop()
- Stops the audio output.
-*/
-
-/*!
- \fn void QPlatformAudioSink::reset()
- Drops all audio data in the buffers, resets buffers to zero.
-*/
-
-/*!
- \fn void QPlatformAudioSink::suspend()
- Stops processing audio data, preserving buffered audio data.
-*/
-
-/*!
- \fn void QPlatformAudioSink::resume()
- Resumes processing audio data after a suspend()
-*/
-
-/*!
- \fn qsizetype QPlatformAudioSink::bytesFree() const
- Returns the free space available in bytes in the audio buffer.
-*/
-
-/*!
- \fn void QPlatformAudioSink::setBufferSize(qsizetype value)
- Sets the audio buffer size to \a value in bytes.
-*/
-
-/*!
- \fn qsizetype QPlatformAudioSink::bufferSize() const
- Returns the audio buffer size in bytes.
-*/
-
-/*!
- \fn qint64 QPlatformAudioSink::processedUSecs() const
- Returns the amount of audio data processed since start() was called in milliseconds.
-*/
-
-/*!
- \fn QAudio::Error QPlatformAudioSink::error() const
- Returns the error state.
-*/
-
-/*!
- \fn QAudio::State QPlatformAudioSink::state() const
- Returns the state of audio processing.
-*/
-
-/*!
- \fn void QPlatformAudioSink::setFormat(const QAudioFormat& fmt)
- Set the QAudioFormat to use to \a fmt.
- Setting the format is only allowable while in QAudio::StoppedState.
-*/
-
-/*!
- \fn QAudioFormat QPlatformAudioSink::format() const
- Returns the QAudioFormat being used.
-*/
-
-/*!
- \fn void QPlatformAudioSink::setVolume(qreal volume)
- Sets the volume.
- Where \a volume is between 0.0 and 1.0.
-*/
+#include <private/qplatformmediadevices_p.h>
-/*!
- \fn qreal QPlatformAudioSink::volume() const
- Returns the volume in the range 0.0 and 1.0.
-*/
-
-/*!
- \fn QPlatformAudioSink::errorChanged(QAudio::Error error)
- This signal is emitted when the \a error state has changed.
-*/
-
-/*!
- \fn QPlatformAudioSink::stateChanged(QAudio::State state)
- This signal is emitted when the device \a state has changed.
-*/
-
-/*!
- \class QPlatformAudioSource
- \brief The QPlatformAudioSource class provides access for QAudioSource to access the audio
- device provided by the plugin.
-
- \ingroup multimedia
- \inmodule QtMultimedia
-
- QAudioDeviceInput keeps an instance of QPlatformAudioSource and
- routes calls to functions of the same name to QPlatformAudioSource.
- This means that it is QPlatformAudioSource that implements the
- audio functionality. For a description of the functionality, see
- the QAudioSource class description.
-
- \sa QAudioSource
-*/
-
-/*!
- \fn void QPlatformAudioSource::start(QIODevice* device)
- Uses the \a device as the QIODevice to transfer data.
-*/
-
-/*!
- \fn QIODevice* QPlatformAudioSource::start()
- Returns a pointer to the QIODevice being used to handle
- the data transfer. This QIODevice can be used to read() audio data directly.
-*/
-
-/*!
- \fn void QPlatformAudioSource::stop()
- Stops the audio input.
-*/
-
-/*!
- \fn void QPlatformAudioSource::reset()
- Drops all audio data in the buffers, resets buffers to zero.
-*/
-
-/*!
- \fn void QPlatformAudioSource::suspend()
- Stops processing audio data, preserving buffered audio data.
-*/
-
-/*!
- \fn void QPlatformAudioSource::resume()
- Resumes processing audio data after a suspend().
-*/
-
-/*!
- \fn qsizetype QPlatformAudioSource::bytesReady() const
- Returns the amount of audio data available to read in bytes.
-*/
-
-/*!
- \fn void QPlatformAudioSource::setBufferSize(qsizetype value)
- Sets the audio buffer size to \a value in milliseconds.
-*/
-
-/*!
- \fn qsizetype QPlatformAudioSource::bufferSize() const
- Returns the audio buffer size in milliseconds.
-*/
-
-/*!
- \fn qint64 QPlatformAudioSource::processedUSecs() const
- Returns the amount of audio data processed since start() was called in milliseconds.
-*/
-
-/*!
- \fn QAudio::Error QPlatformAudioSource::error() const
- Returns the error state.
-*/
-
-/*!
- \fn QAudio::State QPlatformAudioSource::state() const
- Returns the state of audio processing.
-*/
+QT_BEGIN_NAMESPACE
-/*!
- \fn void QPlatformAudioSource::setFormat(const QAudioFormat& fmt)
- Set the QAudioFormat to use to \a fmt.
- Setting the format is only allowable while in QAudio::StoppedState.
-*/
+QAudioStateChangeNotifier::QAudioStateChangeNotifier(QObject *parent) : QObject(parent) { }
-/*!
- \fn QAudioFormat QPlatformAudioSource::format() const
- Returns the QAudioFormat being used
-*/
+QPlatformAudioSink::QPlatformAudioSink(QObject *parent) : QAudioStateChangeNotifier(parent) { }
-/*!
- \fn QPlatformAudioSource::errorChanged(QAudio::Error error)
- This signal is emitted when the \a error state has changed.
-*/
+qreal QPlatformAudioSink::volume() const
+{
+ return 1.0;
+}
-/*!
- \fn QPlatformAudioSource::stateChanged(QAudio::State state)
- This signal is emitted when the device \a state has changed.
-*/
+QPlatformAudioSource::QPlatformAudioSource(QObject *parent) : QAudioStateChangeNotifier(parent) { }
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiosystem_p.h b/src/multimedia/audio/qaudiosystem_p.h
index ae1c54dde..4a0650e80 100644
--- a/src/multimedia/audio/qaudiosystem_p.h
+++ b/src/multimedia/audio/qaudiosystem_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 QAUDIOSYSTEM_H
#define QAUDIOSYSTEM_H
@@ -58,16 +22,29 @@
#include <QtMultimedia/qaudiodevice.h>
#include <QtCore/qelapsedtimer.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
class QIODevice;
-class QPlatformAudioSink : public QObject
+class Q_MULTIMEDIA_EXPORT QAudioStateChangeNotifier : public QObject
+{
+ Q_OBJECT
+public:
+ QAudioStateChangeNotifier(QObject *parent = nullptr);
+
+signals:
+ void errorChanged(QAudio::Error error);
+ void stateChanged(QAudio::State state);
+};
+
+class Q_MULTIMEDIA_EXPORT QPlatformAudioSink : public QAudioStateChangeNotifier
{
Q_OBJECT
public:
+ QPlatformAudioSink(QObject *parent);
virtual void start(QIODevice *device) = 0;
virtual QIODevice* start() = 0;
virtual void stop() = 0;
@@ -83,20 +60,17 @@ public:
virtual void setFormat(const QAudioFormat& fmt) = 0;
virtual QAudioFormat format() const = 0;
virtual void setVolume(qreal) {}
- virtual qreal volume() const { return 1.0; }
+ virtual qreal volume() const;
QElapsedTimer elapsedTime;
-
-Q_SIGNALS:
- void errorChanged(QAudio::Error error);
- void stateChanged(QAudio::State state);
};
-class QPlatformAudioSource : public QObject
+class Q_MULTIMEDIA_EXPORT QPlatformAudioSource : public QAudioStateChangeNotifier
{
Q_OBJECT
public:
+ QPlatformAudioSource(QObject *parent);
virtual void start(QIODevice *device) = 0;
virtual QIODevice* start() = 0;
virtual void stop() = 0;
@@ -115,10 +89,6 @@ public:
virtual qreal volume() const = 0;
QElapsedTimer elapsedTime;
-
-Q_SIGNALS:
- void errorChanged(QAudio::Error error);
- void stateChanged(QAudio::State state);
};
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qsamplecache_p.cpp b/src/multimedia/audio/qsamplecache_p.cpp
index 6c4163080..825c79685 100644
--- a/src/multimedia/audio/qsamplecache_p.cpp
+++ b/src/multimedia/audio/qsamplecache_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qsamplecache_p.h"
#include "qwavedecoder.h"
@@ -47,7 +11,7 @@
#include <QtCore/QDebug>
#include <QtCore/qloggingcategory.h>
-Q_LOGGING_CATEGORY(qLcSampleCache, "qt.multimedia.samplecache")
+static Q_LOGGING_CATEGORY(qLcSampleCache, "qt.multimedia.samplecache")
#include <mutex>
@@ -166,6 +130,7 @@ QSample* QSampleCache::requestSample(const QUrl& url)
{
//lock and add first to make sure live loadingThread will not be killed during this function call
m_loadingMutex.lock();
+ const bool needsThreadStart = m_loadingRefCount == 0;
m_loadingRefCount++;
m_loadingMutex.unlock();
@@ -174,11 +139,16 @@ QSample* QSampleCache::requestSample(const QUrl& url)
QMap<QUrl, QSample*>::iterator it = m_samples.find(url);
QSample* sample;
if (it == m_samples.end()) {
- if (!m_loadingThread.isRunning())
+ if (needsThreadStart) {
+ // Previous thread might be finishing, need to wait for it. If not, this is a no-op.
+ m_loadingThread.wait();
m_loadingThread.start();
+ }
sample = new QSample(url, this);
m_samples.insert(url, sample);
+#if QT_CONFIG(thread)
sample->moveToThread(&m_loadingThread);
+#endif
} else {
sample = *it;
}
@@ -314,10 +284,14 @@ void QSample::release()
void QSample::cleanup()
{
qCDebug(qLcSampleCache) << "QSample: cleanup";
- if (m_waveDecoder)
+ if (m_waveDecoder) {
+ m_waveDecoder->disconnect(this);
m_waveDecoder->deleteLater();
- if (m_stream)
+ }
+ if (m_stream) {
+ m_stream->disconnect(this);
m_stream->deleteLater();
+ }
m_waveDecoder = nullptr;
m_stream = nullptr;
@@ -332,7 +306,9 @@ void QSample::addRef()
// Called in loading thread
void QSample::readSample()
{
+#if QT_CONFIG(thread)
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
+#endif
QMutexLocker m(&m_mutex);
qint64 read = m_waveDecoder->read(m_soundData.data() + m_sampleReadLength,
qMin(m_waveDecoder->bytesAvailable(),
@@ -349,7 +325,9 @@ void QSample::readSample()
// Called in loading thread
void QSample::decoderReady()
{
+#if QT_CONFIG(thread)
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
+#endif
QMutexLocker m(&m_mutex);
qCDebug(qLcSampleCache) << "QSample: decoder ready";
m_parent->refresh(m_waveDecoder->size());
@@ -375,10 +353,12 @@ QSample::State QSample::state() const
// Essentially a second ctor, doesn't need locks (?)
void QSample::load()
{
+#if QT_CONFIG(thread)
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
+#endif
qCDebug(qLcSampleCache) << "QSample: load [" << m_url << "]";
m_stream = m_parent->networkAccessManager().get(QNetworkRequest(m_url));
- connect(m_stream, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(decoderError()));
+ connect(m_stream, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(loadingError(QNetworkReply::NetworkError)));
m_waveDecoder = new QWaveDecoder(m_stream);
connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
connect(m_waveDecoder, SIGNAL(parsingError()), SLOT(decoderError()));
@@ -387,10 +367,25 @@ void QSample::load()
m_waveDecoder->open(QIODevice::ReadOnly);
}
+void QSample::loadingError(QNetworkReply::NetworkError errorCode)
+{
+#if QT_CONFIG(thread)
+ Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
+#endif
+ QMutexLocker m(&m_mutex);
+ qCDebug(qLcSampleCache) << "QSample: loading error" << errorCode;
+ cleanup();
+ m_state = QSample::Error;
+ qobject_cast<QSampleCache*>(m_parent)->loadingRelease();
+ emit error();
+}
+
// Called in loading thread
void QSample::decoderError()
{
+#if QT_CONFIG(thread)
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
+#endif
QMutexLocker m(&m_mutex);
qCDebug(qLcSampleCache) << "QSample: decoder error";
cleanup();
@@ -402,7 +397,9 @@ void QSample::decoderError()
// Called in loading thread from decoder when sample is done. Locked already.
void QSample::onReady()
{
+#if QT_CONFIG(thread)
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
+#endif
m_audioFormat = m_waveDecoder->audioFormat();
qCDebug(qLcSampleCache) << "QSample: load ready format:" << m_audioFormat;
cleanup();
diff --git a/src/multimedia/audio/qsamplecache_p.h b/src/multimedia/audio/qsamplecache_p.h
index d9e84c947..3ba0c420c 100644
--- a/src/multimedia/audio/qsamplecache_p.h
+++ b/src/multimedia/audio/qsamplecache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSAMPLECACHE_P_H
#define QSAMPLECACHE_P_H
@@ -58,7 +22,8 @@
#include <QtCore/qmap.h>
#include <QtCore/qset.h>
#include <qaudioformat.h>
-
+#include <qnetworkreply.h>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -97,6 +62,7 @@ protected:
private Q_SLOTS:
void load();
+ void loadingError(QNetworkReply::NetworkError);
void decoderError();
void readSample();
void decoderReady();
diff --git a/src/multimedia/audio/qsoundeffect.cpp b/src/multimedia/audio/qsoundeffect.cpp
index 5c6a8feeb..c12114672 100644
--- a/src/multimedia/audio/qsoundeffect.cpp
+++ b/src/multimedia/audio/qsoundeffect.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 <QtMultimedia/private/qtmultimediaglobal_p.h>
#include "qsoundeffect.h"
@@ -43,14 +7,39 @@
#include "qaudiodevice.h"
#include "qaudiosink.h"
#include "qmediadevices.h"
+#include "qaudiobuffer.h"
#include <QtCore/qloggingcategory.h>
+#include <private/qplatformmediadevices_p.h>
+#include <private/qplatformmediaintegration_p.h>
+#include <private/qplatformaudioresampler_p.h>
-Q_LOGGING_CATEGORY(qLcSoundEffect, "qt.multimedia.soundeffect")
+static Q_LOGGING_CATEGORY(qLcSoundEffect, "qt.multimedia.soundeffect")
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QSampleCache, sampleCache)
+namespace
+{
+struct AudioSinkDeleter
+{
+ void operator ()(QAudioSink* sink) const
+ {
+ sink->stop();
+ // Investigate:should we just delete?
+ sink->deleteLater();
+ }
+};
+
+struct SampleDeleter
+{
+ void operator ()(QSample* sample) const
+ {
+ sample->release();
+ }
+};
+}
+
class QSoundEffectPrivate : public QIODevice
{
public:
@@ -62,13 +51,14 @@ public:
qint64 size() const override {
if (m_sample->state() != QSample::Ready)
return 0;
- return m_loopCount == QSoundEffect::Infinite ? 0 : m_loopCount * m_sample->data().size();
+ return m_loopCount == QSoundEffect::Infinite ? 0 : m_loopCount * m_audioBuffer.byteCount();
}
qint64 bytesAvailable() const override {
if (m_sample->state() != QSample::Ready)
return 0;
- return m_loopCount == QSoundEffect::Infinite
- ? std::numeric_limits<qint64>::max() : m_runningCount * m_sample->data().size() - m_offset;
+ if (m_loopCount == QSoundEffect::Infinite)
+ return std::numeric_limits<qint64>::max();
+ return m_runningCount * m_audioBuffer.byteCount() - m_offset;
}
bool isSequential() const override {
return m_loopCount == QSoundEffect::Infinite;
@@ -92,9 +82,10 @@ public:
int m_loopCount = 1;
int m_runningCount = 0;
bool m_playing = false;
- QSoundEffect::Status m_status = QSoundEffect::Null;
- QAudioSink *m_audioOutput = nullptr;
- QSample *m_sample = nullptr;
+ QSoundEffect::Status m_status = QSoundEffect::Null;
+ std::unique_ptr<QAudioSink, AudioSinkDeleter> m_audioSink;
+ std::unique_ptr<QSample, SampleDeleter> m_sample;
+ QAudioBuffer m_audioBuffer;
bool m_muted = false;
float m_volume = 1.0;
bool m_sampleReady = false;
@@ -108,6 +99,8 @@ QSoundEffectPrivate::QSoundEffectPrivate(QSoundEffect *q, const QAudioDevice &au
, m_audioDevice(audioDevice)
{
open(QIODevice::ReadOnly);
+
+ QPlatformMediaIntegration::instance()->mediaDevices()->prepareAudio();
}
void QSoundEffectPrivate::sampleReady()
@@ -116,30 +109,67 @@ void QSoundEffectPrivate::sampleReady()
return;
qCDebug(qLcSoundEffect) << this << "sampleReady: sample size:" << m_sample->data().size();
- disconnect(m_sample, &QSample::error, this, &QSoundEffectPrivate::decoderError);
- disconnect(m_sample, &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
- if (!m_audioOutput) {
- m_audioOutput = new QAudioSink(m_audioDevice, m_sample->format());
- connect(m_audioOutput, &QAudioSink::stateChanged, this, &QSoundEffectPrivate::stateChanged);
+ disconnect(m_sample.get(), &QSample::error, this, &QSoundEffectPrivate::decoderError);
+ disconnect(m_sample.get(), &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
+ if (!m_audioSink) {
+ const auto audioDevice =
+ m_audioDevice.isNull() ? QMediaDevices::defaultAudioOutput() : m_audioDevice;
+
+ if (audioDevice.isNull()) {
+ // We are likely on a virtual machine, for example in CI
+ qCCritical(qLcSoundEffect) << "Failed to play sound. No audio devices present.";
+ setStatus(QSoundEffect::Error);
+ return;
+ }
+
+ const auto &sampleFormat = m_sample->format();
+ const auto sampleChannelConfig =
+ sampleFormat.channelConfig() == QAudioFormat::ChannelConfigUnknown
+ ? QAudioFormat::defaultChannelConfigForChannelCount(sampleFormat.channelCount())
+ : sampleFormat.channelConfig();
+
+ if (sampleChannelConfig != audioDevice.channelConfiguration()
+ && audioDevice.channelConfiguration() != QAudioFormat::ChannelConfigUnknown) {
+ qCDebug(qLcSoundEffect) << "Create resampler for channels mapping: config"
+ << sampleFormat.channelConfig() << "=> config"
+ << audioDevice.channelConfiguration();
+ auto outputFormat = sampleFormat;
+ outputFormat.setChannelConfig(audioDevice.channelConfiguration());
+
+ const auto resampler = QPlatformMediaIntegration::instance()->createAudioResampler(
+ m_sample->format(), outputFormat);
+ if (resampler)
+ m_audioBuffer = resampler.value()->resample(m_sample->data().constData(),
+ m_sample->data().size());
+ else
+ qCDebug(qLcSoundEffect) << "Cannot create resampler for channels mapping";
+ }
+
+ if (!m_audioBuffer.isValid())
+ m_audioBuffer = QAudioBuffer(m_sample->data(), m_sample->format());
+
+ m_audioSink.reset(new QAudioSink(audioDevice, m_audioBuffer.format()));
+
+ connect(m_audioSink.get(), &QAudioSink::stateChanged, this, &QSoundEffectPrivate::stateChanged);
if (!m_muted)
- m_audioOutput->setVolume(m_volume);
+ m_audioSink->setVolume(m_volume);
else
- m_audioOutput->setVolume(0);
+ m_audioSink->setVolume(0);
}
m_sampleReady = true;
setStatus(QSoundEffect::Ready);
- if (m_playing && m_audioOutput->state() == QAudio::StoppedState) {
+ if (m_playing && m_audioSink->state() == QAudio::StoppedState) {
qCDebug(qLcSoundEffect) << this << "starting playback on audiooutput";
- m_audioOutput->start(this);
+ m_audioSink->start(this);
}
}
void QSoundEffectPrivate::decoderError()
{
qWarning("QSoundEffect(qaudio): Error decoding source %ls", qUtf16Printable(m_url.toString()));
- disconnect(m_sample, &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
- disconnect(m_sample, &QSample::error, this, &QSoundEffectPrivate::decoderError);
+ disconnect(m_sample.get(), &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
+ disconnect(m_sample.get(), &QSample::error, this, &QSoundEffectPrivate::decoderError);
m_playing = false;
setStatus(QSoundEffect::Error);
}
@@ -148,7 +178,7 @@ void QSoundEffectPrivate::stateChanged(QAudio::State state)
{
qCDebug(qLcSoundEffect) << this << "stateChanged " << state;
if ((state == QAudio::IdleState && m_runningCount == 0) || state == QAudio::StoppedState)
- emit q_ptr->stop();
+ q_ptr->stop();
}
qint64 QSoundEffectPrivate::readData(char *data, qint64 len)
@@ -163,8 +193,8 @@ qint64 QSoundEffectPrivate::readData(char *data, qint64 len)
qint64 bytesWritten = 0;
- const int sampleSize = m_sample->data().size();
- const char* sampleData = m_sample->data().constData();
+ const int sampleSize = m_audioBuffer.byteCount();
+ const char *sampleData = m_audioBuffer.constData<char>();
while (len && m_runningCount) {
int toWrite = qMin(sampleSize - m_offset, len);
@@ -214,15 +244,18 @@ void QSoundEffectPrivate::setStatus(QSoundEffect::Status status)
void QSoundEffectPrivate::setPlaying(bool playing)
{
qCDebug(qLcSoundEffect) << this << "setPlaying(" << playing << ")" << m_playing;
+ if (m_audioSink) {
+ m_audioSink->stop();
+ if (playing && !m_sampleReady)
+ return;
+ }
+
if (m_playing == playing)
return;
m_playing = playing;
- if (m_audioOutput) {
- if (!m_playing)
- m_audioOutput->stop();
- else if (m_audioOutput->state() == QAudio::StoppedState && m_sampleReady)
- m_audioOutput->start(this);
- }
+
+ if (m_audioSink && playing)
+ m_audioSink->start(this);
emit q_ptr->playingChanged();
}
@@ -313,11 +346,8 @@ QSoundEffect::QSoundEffect(const QAudioDevice &audioDevice, QObject *parent)
QSoundEffect::~QSoundEffect()
{
stop();
- if (d->m_audioOutput) {
- d->m_audioOutput->stop();
- d->m_audioOutput->deleteLater();
- d->m_sample->release();
- }
+ d->m_audioSink.reset();
+ d->m_sample.reset();
delete d;
}
@@ -388,24 +418,22 @@ void QSoundEffect::setSource(const QUrl &url)
if (d->m_sample) {
if (!d->m_sampleReady) {
- QObject::disconnect(d->m_sample, &QSample::error, d, &QSoundEffectPrivate::decoderError);
- QObject::disconnect(d->m_sample, &QSample::ready, d, &QSoundEffectPrivate::sampleReady);
+ disconnect(d->m_sample.get(), &QSample::error, d, &QSoundEffectPrivate::decoderError);
+ disconnect(d->m_sample.get(), &QSample::ready, d, &QSoundEffectPrivate::sampleReady);
}
d->m_sample->release();
d->m_sample = nullptr;
}
- if (d->m_audioOutput) {
- QObject::disconnect(d->m_audioOutput, &QAudioSink::stateChanged, d, &QSoundEffectPrivate::stateChanged);
- d->m_audioOutput->stop();
- d->m_audioOutput->deleteLater();
- d->m_audioOutput = nullptr;
+ if (d->m_audioSink) {
+ disconnect(d->m_audioSink.get(), &QAudioSink::stateChanged, d, &QSoundEffectPrivate::stateChanged);
+ d->m_audioSink.reset();
}
d->setStatus(QSoundEffect::Loading);
- d->m_sample = sampleCache()->requestSample(url);
- QObject::connect(d->m_sample, &QSample::error, d, &QSoundEffectPrivate::decoderError);
- QObject::connect(d->m_sample, &QSample::ready, d, &QSoundEffectPrivate::sampleReady);
+ d->m_sample.reset(sampleCache()->requestSample(url));
+ connect(d->m_sample.get(), &QSample::error, d, &QSoundEffectPrivate::decoderError);
+ connect(d->m_sample.get(), &QSample::ready, d, &QSoundEffectPrivate::sampleReady);
switch (d->m_sample->state()) {
case QSample::Ready:
@@ -483,6 +511,11 @@ void QSoundEffect::setLoopCount(int loopCount)
emit loopCountChanged();
}
+/*!
+ \property QSoundEffect::audioDevice
+
+ Returns the QAudioDevice instance.
+*/
QAudioDevice QSoundEffect::audioDevice()
{
return d->m_audioDevice;
@@ -527,7 +560,7 @@ int QSoundEffect::loopsRemaining() const
UI volume controls should usually be scaled non-linearly. For example, using a logarithmic scale
will produce linear changes in perceived loudness, which is what a user would normally expect
- from a volume control. See \l {QAudio::convertVolume()}{convertVolume()}
+ from a volume control. See \l {QtAudio::convertVolume()}{convertVolume()}
for more details.
*/
/*!
@@ -541,8 +574,8 @@ int QSoundEffect::loopsRemaining() const
*/
float QSoundEffect::volume() const
{
- if (d->m_audioOutput && !d->m_muted)
- return d->m_audioOutput->volume();
+ if (d->m_audioSink && !d->m_muted)
+ return d->m_audioSink->volume();
return d->m_volume;
}
@@ -557,7 +590,7 @@ float QSoundEffect::volume() const
UI volume controls should usually be scaled non-linearly. For example, using a logarithmic scale
will produce linear changes in perceived loudness, which is what a user would normally expect
- from a volume control. See QAudio::convertVolume() for more details.
+ from a volume control. See QtAudio::convertVolume() for more details.
*/
void QSoundEffect::setVolume(float volume)
{
@@ -567,8 +600,8 @@ void QSoundEffect::setVolume(float volume)
d->m_volume = volume;
- if (d->m_audioOutput && !d->m_muted)
- d->m_audioOutput->setVolume(volume);
+ if (d->m_audioSink && !d->m_muted)
+ d->m_audioSink->setVolume(volume);
emit volumeChanged();
}
@@ -603,10 +636,10 @@ void QSoundEffect::setMuted(bool muted)
if (d->m_muted == muted)
return;
- if (muted && d->m_audioOutput)
- d->m_audioOutput->setVolume(0);
- else if (!muted && d->m_audioOutput && d->m_muted)
- d->m_audioOutput->setVolume(d->m_volume);
+ if (muted && d->m_audioSink)
+ d->m_audioSink->setVolume(0);
+ else if (!muted && d->m_audioSink && d->m_muted)
+ d->m_audioSink->setVolume(d->m_volume);
d->m_muted = muted;
emit mutedChanged();
diff --git a/src/multimedia/audio/qsoundeffect.h b/src/multimedia/audio/qsoundeffect.h
index 5b806b382..eeafc4c9f 100644
--- a/src/multimedia/audio/qsoundeffect.h
+++ b/src/multimedia/audio/qsoundeffect.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QSOUNDEFFECT_H
#define QSOUNDEFFECT_H
diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qtaudio.cpp
index f38ff0628..fb14e5093 100644
--- a/src/multimedia/audio/qaudio.cpp
+++ b/src/multimedia/audio/qtaudio.cpp
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 <qaudio.h>
+#include <qtaudio.h>
#include <qmath.h>
#include <QDebug>
@@ -47,16 +11,16 @@ QT_BEGIN_NAMESPACE
#define LOG100 4.60517018599
/*!
- \namespace QAudio
+ \namespace QtAudio
\ingroup multimedia-namespaces
- \brief The QAudio namespace contains enums used by the audio classes.
+ \brief The QtAudio namespace contains enums used by the audio classes.
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_audio
*/
/*!
- \enum QAudio::Error
+ \enum QtAudio::Error
\value NoError No errors have occurred
\value OpenError An error occurred opening the audio device
@@ -66,7 +30,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \enum QAudio::State
+ \enum QtAudio::State
\value ActiveState Audio data is being processed, this state is set after start() is called
and while audio data is available to be processed.
@@ -80,15 +44,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \enum QAudioDevice::Mode
-
- \value Output Audio output device
- \value Input Audio input device
- \omitvalue Null
-*/
-
-/*!
- \enum QAudio::VolumeScale
+ \enum QtAudio::VolumeScale
This enum defines the different audio volume scales.
@@ -103,11 +59,14 @@ QT_BEGIN_NAMESPACE
\value DecibelVolumeScale Decibel (dB, amplitude) logarithmic scale. \c -200 is silence
and \c 0 is full volume.
- \since 5.8
- \sa QAudio::convertVolume()
+ \sa QtAudio::convertVolume()
*/
+#if defined(Q_QDOC)
+namespace QtAudio
+#else
namespace QAudio
+#endif
{
/*!
@@ -128,7 +87,6 @@ namespace QAudio
\snippet multimedia-snippets/audio.cpp Volume conversion
- \since 5.8
\sa VolumeScale, QAudioSink::setVolume(), QAudioSource::setVolume(),
QSoundEffect::setVolume()
*/
diff --git a/src/multimedia/audio/qtaudio.h b/src/multimedia/audio/qtaudio.h
new file mode 100644
index 000000000..6f6e0e668
--- /dev/null
+++ b/src/multimedia/audio/qtaudio.h
@@ -0,0 +1,18 @@
+// 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 QTAUDIO_H
+#define QTAUDIO_H
+
+#if 0
+#pragma qt_class(QtAudio)
+#endif
+
+#include <QtMultimedia/qaudio.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#endif // QTAUDIO_H
diff --git a/src/multimedia/audio/qwavedecoder.cpp b/src/multimedia/audio/qwavedecoder.cpp
index 534e66d79..36ac3c779 100644
--- a/src/multimedia/audio/qwavedecoder.cpp
+++ b/src/multimedia/audio/qwavedecoder.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwavedecoder.h"
@@ -57,15 +21,6 @@ void bswap2(char *data, qsizetype count) noexcept
}
}
-void bswap3(char *data, qsizetype count) noexcept
-{
- for (qsizetype i = 0; i < count; ++i) {
- qSwap(data[0], data[2]);
- ++count;
- data += 3;
- }
-}
-
void bswap4(char *data, qsizetype count) noexcept
{
for (qsizetype i = 0; i < count; ++i) {
@@ -136,6 +91,10 @@ qint64 QWaveDecoder::pos() const
return device->pos();
}
+void QWaveDecoder::setIODevice(QIODevice * /* device */)
+{
+}
+
QAudioFormat QWaveDecoder::audioFormat() const
{
return format;
@@ -150,15 +109,21 @@ int QWaveDecoder::duration() const
{
if (openMode() & QIODevice::WriteOnly)
return 0;
- return dataSize * 1000 / (format.bytesPerFrame() * format.sampleRate());
+ int bytesPerSec = format.bytesPerFrame() * format.sampleRate();
+ return bytesPerSec ? size() * 1000 / bytesPerSec : 0;
}
qint64 QWaveDecoder::size() const
{
- if (openMode() & QIODevice::ReadOnly)
- return haveFormat ? dataSize : 0;
- else
+ if (openMode() & QIODevice::ReadOnly) {
+ if (!haveFormat)
+ return 0;
+ if (bps == 24)
+ return dataSize*2/3;
+ return dataSize;
+ } else {
return device->size();
+ }
}
bool QWaveDecoder::isSequential() const
@@ -178,28 +143,50 @@ qint64 QWaveDecoder::headerLength()
qint64 QWaveDecoder::readData(char *data, qint64 maxlen)
{
- if (!haveFormat || format.bytesPerSample() == 0)
+ const int bytesPerSample = format.bytesPerSample();
+ if (!haveFormat || bytesPerSample == 0)
return 0;
- qint64 nSamples = maxlen / format.bytesPerSample();
- maxlen = nSamples * format.bytesPerSample();
- device->read(data, maxlen);
+ if (bps == 24) {
+ // 24 bit WAV, read in as 16 bit
+ qint64 l = 0;
+ while (l < maxlen - 1) {
+ char tmp[3];
+ device->read(tmp, 3);
+ if (byteSwap)
+ qSwap(tmp[0], tmp[2]);
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ data[0] = tmp[0];
+ data[1] = tmp[1];
+#else
+ data[0] = tmp[1];
+ data[1] = tmp[2];
+#endif
+ data += 2;
+ l += 2;
+ }
+ return l;
+ }
+
+ qint64 nSamples = maxlen / bytesPerSample;
+ maxlen = nSamples * bytesPerSample;
+ int read = device->read(data, maxlen);
if (!byteSwap || format.bytesPerFrame() == 1)
- return maxlen;
+ return read;
- switch (format.bytesPerSample()) {
+ nSamples = read / bytesPerSample;
+ switch (bytesPerSample) {
case 2:
bswap2(data, nSamples);
break;
- case 3:
- bswap3(data, nSamples);
- break;
case 4:
bswap4(data, nSamples);
break;
+ default:
+ Q_UNREACHABLE();
}
- return maxlen;
+ return read;
}
@@ -357,7 +344,6 @@ void QWaveDecoder::handleData()
return;
}
- int bps;
int rate;
int channels;
if (bigEndian) {
@@ -379,7 +365,7 @@ void QWaveDecoder::handleData()
fmt = QAudioFormat::Int16;
break;
case 24:
- fmt = QAudioFormat::Unknown;
+ fmt = QAudioFormat::Int16;
break;
case 32:
fmt = QAudioFormat::Int32;
@@ -391,8 +377,8 @@ void QWaveDecoder::handleData()
}
format.setSampleFormat(fmt);
- format.setSampleRate(/*qFromBigEndian<quint32>*/(wave.sampleRate));
- format.setChannelCount(/*qFromBigEndian<quint16>*/(wave.numChannels));
+ format.setSampleRate(rate);
+ format.setChannelCount(channels);
state = QWaveDecoder::WaitingForDataState;
}
@@ -457,9 +443,15 @@ bool QWaveDecoder::findChunk(const char *chunkId)
if (qstrncmp(descriptor.id, chunkId, 4) == 0)
return true;
+ // A program reading a RIFF file can skip over any chunk whose chunk
+ // ID it doesn't recognize; it simply skips the number of bytes specified
+ // by ckSize plus the pad byte, if present. See Multimedia Programming
+ // Interface and Data Specifications 1.0. IBM / Microsoft. August 1991. pp. 10-11.
+ const quint32 sizeWithPad = descriptor.size + (descriptor.size & 1);
+
// It's possible that bytes->available() is less than the chunk size
// if it's corrupt.
- junkToSkip = qint64(sizeof(chunk) + descriptor.size);
+ junkToSkip = qint64(sizeof(chunk) + sizeWithPad);
// Skip the current amount
if (junkToSkip > 0)
diff --git a/src/multimedia/audio/qwavedecoder.h b/src/multimedia/audio/qwavedecoder.h
index 8fb49ac8d..a96e731db 100644
--- a/src/multimedia/audio/qwavedecoder.h
+++ b/src/multimedia/audio/qwavedecoder.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 WAVEDECODER_H
#define WAVEDECODER_H
@@ -98,9 +62,11 @@ private:
struct chunk
{
- char id[4];
- quint32 size;
+ char id[4]; // A four-character code that identifies the representation of the chunk data
+ // padded on the right with blank characters (ASCII 32)
+ quint32 size; // Does not include the size of the id or size fields or the pad byte at the end of payload
};
+
bool peekChunk(chunk* pChunk, bool handleEndianness = true);
struct RIFFHeader
@@ -141,6 +107,7 @@ private:
quint32 junkToSkip = 0;
bool bigEndian = false;
bool byteSwap = false;
+ int bps = 0;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/camera/qcamera.cpp b/src/multimedia/camera/qcamera.cpp
index 22abc4f75..527b14c25 100644
--- a/src/multimedia/camera/qcamera.cpp
+++ b/src/multimedia/camera/qcamera.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qcamera_p.h"
@@ -69,59 +33,147 @@ QT_BEGIN_NAMESPACE
\snippet multimedia-snippets/camera.cpp Camera selection
On hardware that supports it, QCamera lets you adjust the focus
- and zoom. This also includes things
- like "Macro" mode for close up work (e.g. reading barcodes, or
+ and zoom. This also includes functionality such as a
+ "Macro" mode for close up work (e.g. reading barcodes, or
recognizing letters), or "touch to focus" - indicating an
- interesting area of the viewfinder for the hardware to attempt
+ interesting area of the image for the hardware to attempt
to focus on.
\snippet multimedia-snippets/camera.cpp Camera custom focus
- The \l minimumZoomFactor() and \l maximumZoomFactor() methods allows checking the
- range of allowed zoom factors. The \l zoomTo() method allows changing the zoom factor.
+ The \l minimumZoomFactor() and \l maximumZoomFactor() methods provide the
+ range of supported zoom factors. The \l zoomTo() method allows changing
+ the zoom factor.
\snippet multimedia-snippets/camera.cpp Camera zoom
- After capturing the data for a camera frame, the camera hardware and
- software performs various image processing tasks to produce a final
+ After capturing the raw data for a camera frame, the camera hardware and
+ software performs various image processing tasks to produce the final
image. This includes compensating for ambient light color, reducing
noise, as well as making some other adjustments to the image.
+ You can control many of these processing steps through the Camera properties.
For example, you can set the white balance (or color temperature) used
for processing images:
\snippet multimedia-snippets/camera.cpp Camera image whitebalance
- For more information on image processing of camera frames, see \l {camera_image_processing}{Camera Image Processing}.
+ For more information on image processing of camera frames, see
+ \l {camera_image_processing}{Camera Image Processing}.
See the \l{Camera Overview}{camera overview} for more information.
*/
+/*!
+ \qmltype Camera
+ \instantiates QCamera
+ \inqmlmodule QtMultimedia
+ \brief An interface for camera settings related to focus and zoom.
+ \ingroup multimedia_qml
+ \ingroup camera_qml
+
+ The Camera element can be used within a \l CaptureSession for video recording
+ and image taking.
+
+ You can use \l MediaDevices to list available cameras and choose which one to use.
+
+ \qml
+ MediaDevices {
+ id: mediaDevices
+ }
+ CaptureSession {
+ camera: Camera {
+ cameraDevice: mediaDevices.defaultVideoInput
+ }
+ }
+ \endqml
+
+ On hardware that supports it, QCamera lets you adjust the focus
+ and zoom. This also includes functionality such as a
+ "Macro" mode for close up work (e.g. reading barcodes, or
+ recognizing letters), or "touch to focus" - indicating an
+ interesting area of the image for the hardware to attempt
+ to focus on.
+
+ \qml
+
+ Item {
+ width: 640
+ height: 360
+
+ CaptureSession {
+ camera: Camera {
+ id: camera
+
+ focusMode: Camera.FocusModeAutoNear
+ customFocusPoint: Qt.point(0.2, 0.2) // Focus relative to top-left corner
+ }
+ videoOutput: videoOutput
+ }
+
+ VideoOutput {
+ id: videoOutput
+ anchors.fill: parent
+ }
+ }
+
+ \endqml
+
+ The \l minimumZoomFactor and \l maximumZoomFactor properties provide the
+ range of supported zoom factors. The \l zoomFactor property allows changing
+ the zoom factor.
+
+ \qml
+ Camera {
+ zoomFactor: maximumZoomFactor // zoom in as much as possible
+ }
+ \endqml
+
+ After capturing the raw data for a camera frame, the camera hardware and
+ software performs various image processing tasks to produce the final
+ image. This includes compensating for ambient light color, reducing
+ noise, as well as making some other adjustments to the image.
+
+ You can control many of these processing steps through the Camera properties.
+ For example, you can set the white balance (or color temperature) used
+ for processing images:
+
+ \qml
+ Camera {
+ whiteBalanceMode: Camera.WhiteBalanceManual
+ colorTemperature: 5600
+ }
+ \endqml
+
+ For more information on image processing of camera frames, see
+ \l {camera_image_processing}{Camera Image Processing}.
+
+ See the \l{Camera Overview}{camera overview} for more information.
+*/
+
+
void QCameraPrivate::_q_error(int error, const QString &errorString)
{
Q_Q(QCamera);
- this->error = QCamera::Error(error);
- this->errorString = errorString;
-
- emit q->errorChanged();
- emit q->errorOccurred(this->error, errorString);
+ this->error.setAndNotify(QCamera::Error(error), errorString, *q);
}
void QCameraPrivate::init(const QCameraDevice &device)
{
Q_Q(QCamera);
- control = QPlatformMediaIntegration::instance()->createCamera(q);
- if (!control) {
- _q_error(QCamera::CameraError, QString::fromUtf8("Camera not supported"));
+ 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, QString::fromUtf8("No camera detected"));
+ _q_error(QCamera::CameraError, QStringLiteral("No camera detected"));
control->setCamera(cameraDevice);
q->connect(control, SIGNAL(activeChanged(bool)), q, SIGNAL(activeChanged(bool)));
q->connect(control, SIGNAL(error(int,QString)), q, SLOT(_q_error(int,QString)));
@@ -186,11 +238,8 @@ QCamera::QCamera(QCameraDevice::Position position, QObject *parent)
QCamera::~QCamera()
{
Q_D(QCamera);
- if (d->captureSession) {
- d->captureInterface->setCamera(nullptr);
+ if (d->captureSession)
d->captureSession->setCamera(nullptr);
- }
- Q_ASSERT(!d->captureSession);
}
/*!
@@ -202,6 +251,16 @@ bool QCamera::isAvailable() const
return d->control && !d->cameraDevice.isNull();
}
+/*! \qmlproperty bool QtMultimedia::Camera::active
+
+ Describes whether the camera is currently active.
+*/
+
+/*! \property QCamera::active
+
+ Describes whether the camera is currently active.
+*/
+
/*!
Returns true if the camera is currently active.
*/
@@ -222,28 +281,88 @@ void QCamera::setActive(bool active)
}
/*!
- Returns the error state of the object.
+ \qmlproperty enumeration QtMultimedia::Camera::error
+
+ Returns the error state of the camera.
+
+ \sa QCamera::Error
+*/
+
+/*!
+ \property QCamera::error
+
+ Returns the error state of the camera.
*/
QCamera::Error QCamera::error() const
{
- return d_func()->error;
+ return d_func()->error.code();
}
/*!
+ \qmlproperty string QtMultimedia::Camera::errorString
+
+ Returns a human readable string describing a camera's error state.
+*/
+
+/*!
+ \property QCamera::errorString
+
Returns a human readable string describing a camera's error state.
*/
QString QCamera::errorString() const
{
- return d_func()->errorString;
+ return d_func()->error.description();
}
+/*! \enum QCamera::Feature
+
+ Describes a set of features supported by the camera. The returned value can be a
+ combination of:
+
+ \value ColorTemperature
+ The Camera supports setting a custom \l{colorTemperature}.
+ \value ExposureCompensation
+ The Camera supports setting a custom \l{exposureCompensation}.
+ \value IsoSensitivity
+ The Camera supports setting a custom \l{isoSensitivity}.
+ \value ManualExposureTime
+ The Camera supports setting a \l{QCamera::manualExposureTime}{manual exposure Time}.
+ \value CustomFocusPoint
+ The Camera supports setting a \l{QCamera::customFocusPoint}{custom focus point}.
+ \value FocusDistance
+ The Camera supports setting the \l{focusDistance} property.
+*/
+
+/*!
+ \qmlproperty Features QtMultimedia::Camera::supportedFeatures
+ Returns the features supported by this camera.
+
+ \sa QCamera::Feature
+*/
+
+/*!
+ \property QCamera::supportedFeatures
+
+ Returns the features supported by this camera.
+
+ \sa QCamera::Feature
+*/
QCamera::Features QCamera::supportedFeatures() const
{
Q_D(const QCamera);
return d->control ? d->control->supportedFeatures() : QCamera::Features{};
}
+/*! \qmlmethod void Camera::start()
+
+ Starts the camera.
+
+ Same as setting the active property to true.
+
+ If the camera can't be started for some reason, the errorOccurred() signal is emitted.
+*/
+
/*! \fn void QCamera::start()
Starts the camera.
@@ -253,11 +372,16 @@ QCamera::Features QCamera::supportedFeatures() const
If the camera can't be started for some reason, the errorOccurred() signal is emitted.
*/
+/*! \qmlmethod void Camera::stop()
+
+ Stops the camera.
+ Same as setting the active property to false.
+*/
+
/*! \fn void QCamera::stop()
Stops the camera.
Same as setActive(false).
-
*/
/*!
@@ -279,20 +403,26 @@ QMediaCaptureSession *QCamera::captureSession() const
void QCamera::setCaptureSession(QMediaCaptureSession *session)
{
Q_D(QCamera);
+ d->captureSession = session;
+}
- if (d->captureSession == session)
- return;
+/*!
+ \internal
+*/
+QPlatformCamera *QCamera::platformCamera()
+{
+ Q_D(const QCamera);
+ return d->control;
+}
- if (d->captureInterface)
- d->captureInterface->setCamera(nullptr);
+/*! \qmlproperty cameraDevice QtMultimedia::Camera::cameraDevice
- d->captureSession = session;
- d->captureInterface = session ? session->platformSession() : nullptr;
- if (d->captureInterface && d->control)
- d->captureInterface->setCamera(d->control);
-}
+ Gets or sets the currently active camera device.
+*/
/*!
+ \property QCamera::cameraDevice
+
Returns the QCameraDevice object associated with this camera.
*/
QCameraDevice QCamera::cameraDevice() const
@@ -303,8 +433,8 @@ QCameraDevice QCamera::cameraDevice() const
/*!
Connects the camera object to the physical camera device described by
- \a device. Using a default constructed QCameraDevice object as \a device
- will connect the camera to the system default camera device.
+ \a cameraDevice. Using a default constructed QCameraDevice object as
+ \a cameraDevice will connect the camera to the system default camera device.
*/
void QCamera::setCameraDevice(const QCameraDevice &cameraDevice)
{
@@ -321,8 +451,29 @@ void QCamera::setCameraDevice(const QCameraDevice &cameraDevice)
setCameraFormat({});
}
+/*! \qmlproperty cameraFormat QtMultimedia::Camera::cameraFormat
+
+ Gets or sets the currently active camera format.
+
+ \note When using the FFMPEG backend on an Android target device if you request
+ \b YUV420P format, you will receive either a fully planar 4:2:0 YUV420P or a
+ semi-planar NV12/NV21. This depends on the codec implemented by the device
+ OEM.
+
+ \sa cameraDevice::videoFormats
+*/
+
/*!
+ \property QCamera::cameraFormat
+
Returns the camera format currently used by the camera.
+
+ \note When using the FFMPEG backend on an Android target device if you request
+ \b YUV420P format, you will receive either a fully planar 4:2:0 YUV420P or a
+ semi-planar NV12/NV21. This depends on the codec implemented by the device
+ OEM.
+
+ \sa QCameraDevice::videoFormats
*/
QCameraFormat QCamera::cameraFormat() const
{
@@ -331,8 +482,13 @@ QCameraFormat QCamera::cameraFormat() const
}
/*!
- Tells the camera to use the format desribed by \a format. This can be used to define
- as specific resolution and frame rate to be used for recording and image capture.
+ Tells the camera to use the format described by \a format. This can be used to define
+ a specific resolution and frame rate to be used for recording and image capture.
+
+ \note When using the FFMPEG backend on an Android target device if you request
+ \b YUV420P format, you will receive either a fully planar 4:2:0 YUV420P or a
+ semi-planar NV12/NV21. This depends on the codec implemented by the device
+ OEM.
*/
void QCamera::setCameraFormat(const QCameraFormat &format)
{
@@ -354,6 +510,13 @@ void QCamera::setCameraFormat(const QCameraFormat &format)
*/
/*!
+ \qmlsignal void Camera::errorOccurred(Camera::Error error, string errorString)
+
+ This signal is emitted when error state changes to \a error. A description
+ of the error is provided as \a errorString.
+*/
+
+/*!
\fn void QCamera::errorOccurred(QCamera::Error error, const QString &errorString)
This signal is emitted when error state changes to \a error. A description
@@ -361,22 +524,27 @@ void QCamera::setCameraFormat(const QCameraFormat &format)
*/
/*!
- \enum QCameraDevice::Position
- \since 5.3
+ \qmlproperty enumeration Camera::focusMode
- This enum specifies the physical position of the camera on the system hardware.
+ This property holds the current camera focus mode.
- \value UnspecifiedPosition The camera position is unspecified or unknown.
+ \note In automatic focusing modes and where supported, the \l focusPoint property provides
+ information and control over the area of the image that is being focused.
- \value BackFace The camera is on the back face of the system hardware. For example on a
- mobile device, it means it is on the opposite side to that of the screen.
+ \value Camera.FocusModeAuto Continuous auto focus mode.
+ \value Camera.FocusModeAutoNear Continuous auto focus, preferring objects near to
+ the camera.
+ \value Camera.FocusModeAutoFar Continuous auto focus, preferring objects far away
+ from the camera.
+ \value Camera.FocusModeHyperfocal Focus to hyperfocal distance, with the maximum
+ depth of field achieved. All objects at distances from half of this
+ distance out to infinity will be acceptably sharp.
+ \value Camera.FocusModeInfinity Focus strictly to infinity.
+ \value Camera.FocusModeManual Manual or fixed focus mode.
- \value FrontFace The camera is on the front face of the system hardware. For example on a
- mobile device, it means it is on the same side as that of the screen. Viewfinder frames of
- front-facing cameras are mirrored horizontally, so the users can see themselves as looking
- into a mirror. Captured images or videos are not mirrored.
+ If a certain focus mode is not supported, setting it will have no effect.
- \sa QCameraDevice::position()
+ \sa isFocusModeSupported
*/
/*!
@@ -387,15 +555,19 @@ void QCamera::setCameraFormat(const QCameraFormat &format)
Locking the focus is possible by setting the focus mode to \l FocusModeManual. This will keep
the current focus and stop any automatic focusing.
- \sa QCamera::isFocusModeSupported()
+ \sa isFocusModeSupported
*/
-
QCamera::FocusMode QCamera::focusMode() const
{
Q_D(const QCamera);
return d->control ? d->control->focusMode() : QCamera::FocusModeAuto;
}
+/*!
+ \fn void QCamera::focusModeChanged()
+
+ Signals when the focusMode changes.
+*/
void QCamera::setFocusMode(QCamera::FocusMode mode)
{
Q_D(QCamera);
@@ -406,9 +578,14 @@ void QCamera::setFocusMode(QCamera::FocusMode mode)
}
/*!
- Returns true if the focus \a mode is supported by camera.
+ \qmlmethod bool Camera::isFocusModeSupported(FocusMode mode)
+
+ Returns true if the focus \a mode is supported by the camera.
*/
+/*!
+ Returns true if the focus \a mode is supported by the camera.
+*/
bool QCamera::isFocusModeSupported(FocusMode mode) const
{
Q_D(const QCamera);
@@ -416,6 +593,13 @@ bool QCamera::isFocusModeSupported(FocusMode mode) const
}
/*!
+ \qmlproperty point QtMultimedia::Camera::focusPoint
+ Returns the point currently used by the auto focus system to focus onto.
+*/
+
+/*!
+ \property QCamera::focusPoint
+
Returns the point currently used by the auto focus system to focus onto.
*/
QPointF QCamera::focusPoint() const
@@ -426,14 +610,29 @@ QPointF QCamera::focusPoint() const
}
/*!
- \property QCamera::customFocusPoint
+ \qmlproperty point QtMultimedia::Camera::customFocusPoint
- This property represents the position of the custom focus point, in relative frame coordinates:
- QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center.
+ This property holds the position of custom focus point, in relative frame
+ coordinates. This means that QPointF(0,0) points to the top-left corner
+ of the frame, and QPointF(0.5,0.5) points to the center of the frame.
- The custom focus point property is used only in \c FocusPointCustom focus mode.
- */
+ Custom focus point is used only in \c FocusPointCustom focus mode.
+
+ You can check whether custom focus points are supported by querying
+ supportedFeatures() with the Feature.CustomFocusPoint flag.
+*/
+
+/*!
+ \property QCamera::customFocusPoint
+
+ This property represents the position of the custom focus point, in relative frame coordinates:
+ QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center.
+ The custom focus point property is used only in \c FocusPointCustom focus mode.
+
+ You can check whether custom focus points are supported by querying
+ supportedFeatures() with the Feature.CustomFocusPoint flag.
+*/
QPointF QCamera::customFocusPoint() const
{
Q_D(const QCamera);
@@ -443,19 +642,31 @@ QPointF QCamera::customFocusPoint() const
void QCamera::setCustomFocusPoint(const QPointF &point)
{
Q_D(QCamera);
- if (!d->control)
- return;
- d->control->setCustomFocusPoint(point);
+ if (d->control)
+ d->control->setCustomFocusPoint(point);
}
/*!
+ \qmlproperty float QtMultimedia::Camera::focusDistance
+
+ This property return an approximate focus distance of the camera. The value reported
+ is between 0 and 1, 0 being the closest possible focus distance, 1 being as far away
+ as possible. Note that 1 is often, but not always infinity.
+
+ Setting the focus distance will be ignored unless the focus mode is set to
+ \l {focusMode}{FocusModeManual}.
+*/
+
+/*!
\property QCamera::focusDistance
- This property return an approximate focus distance of the camera. The value reported is between 0 and 1, 0 being the closest
- possible focus distance, 1 being as far away as possible. Note that 1 is often, but not always infinity.
+ This property return an approximate focus distance of the camera. The value reported
+ is between 0 and 1, 0 being the closest possible focus distance, 1 being as far away
+ as possible. Note that 1 is often, but not always infinity.
- Setting the focus distance will be ignored unless the focus mode is set to \l FocusModeManual.
- */
+ Setting the focus distance will be ignored unless the focus mode is set to
+ \l FocusModeManual.
+*/
void QCamera::setFocusDistance(float d)
{
if (!d_func()->control || focusMode() != FocusModeManual)
@@ -471,6 +682,17 @@ float QCamera::focusDistance() const
}
/*!
+ \qmlproperty real QtMultimedia::Camera::maximumZoomFactor
+
+ This property holds the maximum zoom factor supported.
+
+ This will be \c 1.0 on cameras that do not support zooming.
+*/
+
+
+/*!
+ \property QCamera::maximumZoomFactor
+
Returns the maximum zoom factor.
This will be \c 1.0 on cameras that do not support zooming.
@@ -479,10 +701,20 @@ float QCamera::focusDistance() const
float QCamera::maximumZoomFactor() const
{
Q_D(const QCamera);
- return d->control ? d->control->maxZoomFactor() : 1.;
+ return d->control ? d->control->maxZoomFactor() : 1.f;
}
/*!
+ \qmlproperty real QtMultimedia::Camera::minimumZoomFactor
+
+ This property holds the minimum zoom factor supported.
+
+ This will be \c 1.0 on cameras that do not support zooming.
+*/
+
+/*!
+ \property QCamera::minimumZoomFactor
+
Returns the minimum zoom factor.
This will be \c 1.0 on cameras that do not support zooming.
@@ -491,37 +723,62 @@ float QCamera::maximumZoomFactor() const
float QCamera::minimumZoomFactor() const
{
Q_D(const QCamera);
- return d->control ? d->control->minZoomFactor() : 1.;
+ return d->control ? d->control->minZoomFactor() : 1.f;
}
/*!
- \property QCamera::zoomFactor
- \brief The current zoom factor.
+ \qmlproperty real QtMultimedia::Camera::zoomFactor
+
+ Gets or sets the current zoom factor. Values will be clamped between
+ \l minimumZoomFactor and \l maximumZoomFactor.
+*/
+
+/*!
+ \property QCamera::zoomFactor
+ \brief The current zoom factor.
+
+ Gets or sets the current zoom factor. Values will be clamped between
+ \l minimumZoomFactor and \l maximumZoomFactor.
*/
float QCamera::zoomFactor() const
{
Q_D(const QCamera);
- return d->control ? d->control->zoomFactor() : 1.;
+ return d->control ? d->control->zoomFactor() : 1.f;
}
/*!
Zooms to a zoom factor \a factor at a rate of 1 factor per second.
*/
void QCamera::setZoomFactor(float factor)
{
- zoomTo(factor, 0.);
+ zoomTo(factor, 0.f);
}
/*!
+ \qmlmethod void QtMultimedia::Camera::zoomTo(factor, rate)
+
Zooms to a zoom factor \a factor using \a rate.
The \a rate is specified in powers of two per second. At a rate of 1
it would take 2 seconds to go from a zoom factor of 1 to 4.
- */
+
+ \note Using a specific rate is not supported on all cameras. If not supported,
+ zooming will happen as fast as possible.
+*/
+
+/*!
+ Zooms to a zoom factor \a factor using \a rate.
+
+ The \a rate is specified in powers of two per second. At a rate of 1
+ it would take 2 seconds to go from a zoom factor of 1 to 4.
+
+ \note Using a specific rate is not supported on all cameras. If not supported,
+ zooming will happen as fast as possible.
+*/
void QCamera::zoomTo(float factor, float rate)
{
- Q_ASSERT(rate >= 0.);
- if (rate < 0.)
- rate = 0.;
+ Q_ASSERT(rate >= 0.f);
+ if (rate < 0.f)
+ rate = 0.f;
Q_D(QCamera);
if (!d->control)
@@ -544,12 +801,24 @@ void QCamera::zoomTo(float factor, float rate)
*/
/*!
+ \qmlproperty enumeration QtMultimedia::Camera::flashMode
+
+ Gets or sets a certain flash mode if the camera has a flash.
+
+ \value Camera.FlashOff Flash is Off.
+ \value Camera.FlashOn Flash is On.
+ \value Camera.FlashAuto Automatic flash.
+
+ \sa isFlashModeSupported, isFlashReady
+*/
+
+/*!
\property QCamera::flashMode
\brief The flash mode being used.
Enables a certain flash mode if the camera has a flash.
- \sa QCamera::isFlashModeSupported(), QCamera::isFlashReady()
+ \sa QCamera::FlashMode, QCamera::isFlashModeSupported, QCamera::isFlashReady
*/
QCamera::FlashMode QCamera::flashMode() const
{
@@ -565,9 +834,14 @@ void QCamera::setFlashMode(QCamera::FlashMode mode)
}
/*!
+ \qmlmethod bool QtMultimedia::Camera::isFlashModeSupported(FlashMode mode)
+
Returns true if the flash \a mode is supported.
*/
+/*!
+ Returns true if the flash \a mode is supported.
+*/
bool QCamera::isFlashModeSupported(QCamera::FlashMode mode) const
{
Q_D(const QCamera);
@@ -575,9 +849,14 @@ bool QCamera::isFlashModeSupported(QCamera::FlashMode mode) const
}
/*!
+ \qmlmethod bool QtMultimedia::Camera::isFlashReady()
+
Returns true if flash is charged.
*/
+/*!
+ Returns true if flash is charged.
+*/
bool QCamera::isFlashReady() const
{
Q_D(const QCamera);
@@ -585,13 +864,26 @@ bool QCamera::isFlashReady() const
}
/*!
+ \qmlproperty Camera::TorchMode Camera::torchMode
+
+ Gets or sets the torch mode being used.
+
+ A torch is a continuous source of light. It can be used during video recording in
+ low light conditions. Enabling torch mode will usually override any currently set
+ flash mode.
+
+ \sa QCamera::TorchMode, Camera::isTorchModeSupported(), Camera::flashMode
+*/
+
+/*!
\property QCamera::torchMode
\brief The torch mode being used.
- A torch is a continuous light source used for low light video recording. Enabling torch mode
- will usually override any currently set flash mode.
+ A torch is a continuous source of light. It can be used during video recording in
+ low light conditions. Enabling torch mode will usually override any currently set
+ flash mode.
- \sa QCamera::isTorchModeSupported(), QCamera::flashMode
+ \sa QCamera::TorchMode, QCamera::isTorchModeSupported, QCamera::flashMode
*/
QCamera::TorchMode QCamera::torchMode() const
{
@@ -607,6 +899,12 @@ void QCamera::setTorchMode(QCamera::TorchMode mode)
}
/*!
+ \qmlmethod bool QtMultimedia::Camera::isTorchModeSupported(TorchMode mode)
+
+ Returns true if the torch \a mode is supported.
+*/
+
+/*!
Returns true if the torch \a mode is supported.
*/
bool QCamera::isTorchModeSupported(QCamera::TorchMode mode) const
@@ -616,12 +914,18 @@ bool QCamera::isTorchModeSupported(QCamera::TorchMode mode) const
}
/*!
+ \qmlproperty ExposureMode QtMultimedia::Camera::exposureMode
+ \brief The exposure mode being used.
+
+ \sa QCamera::ExposureMode, Camera::isExposureModeSupported()
+*/
+
+/*!
\property QCamera::exposureMode
\brief The exposure mode being used.
- \sa QCamera::isExposureModeSupported()
+ \sa QCamera::isExposureModeSupported
*/
-
QCamera::ExposureMode QCamera::exposureMode() const
{
Q_D(const QCamera);
@@ -636,39 +940,64 @@ void QCamera::setExposureMode(QCamera::ExposureMode mode)
}
/*!
+ \qmlmethod bool QtMultimedia::Camera::isExposureModeSupported(ExposureMode mode)
+
Returns true if the exposure \a mode is supported.
*/
+/*!
+ Returns true if the exposure \a mode is supported.
+*/
bool QCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
{
Q_D(const QCamera);
- if (!d->control)
- return false;
-
- return d->control->isExposureModeSupported(mode);
+ return d->control && d->control->isExposureModeSupported(mode);
}
/*!
+ \qmlproperty real QtMultimedia::Camera::exposureCompensation
+
+ Gets or sets the exposure compensation in EV units.
+
+ Exposure compensation property allows to adjust the automatically calculated
+ exposure.
+*/
+
+/*!
\property QCamera::exposureCompensation
\brief Exposure compensation in EV units.
Exposure compensation property allows to adjust the automatically calculated
exposure.
*/
-
-qreal QCamera::exposureCompensation() const
+float QCamera::exposureCompensation() const
{
Q_D(const QCamera);
- return d->control ? d->control->exposureCompensation() : 0.;
+ return d->control ? d->control->exposureCompensation() : 0.f;
}
-void QCamera::setExposureCompensation(qreal ev)
+void QCamera::setExposureCompensation(float ev)
{
Q_D(QCamera);
if (d->control)
d->control->setExposureCompensation(ev);
}
+/*!
+ \qmlproperty int QtMultimedia::Camera::isoSensitivity
+
+ Describes the ISO sensitivity currently used by the camera.
+
+*/
+
+/*!
+ \property QCamera::isoSensitivity
+ \brief The sensor ISO sensitivity.
+
+ Describes the ISO sensitivity currently used by the camera.
+
+ \sa setAutoIsoSensitivity(), setManualIsoSensitivity()
+*/
int QCamera::isoSensitivity() const
{
Q_D(const QCamera);
@@ -676,10 +1005,21 @@ int QCamera::isoSensitivity() const
}
/*!
- \fn QCamera::setManualIsoSensitivity(int iso)
- Sets the manual sensitivity to \a iso
+ \qmlproperty int QtMultimedia::Camera::manualIsoSensitivity
+
+ Describes a manually set ISO sensitivity
+
+ Setting this property to -1 (the default), implies that the camera
+ automatically adjusts the ISO sensitivity.
*/
+/*!
+ \property QCamera::manualIsoSensitivity
+ \brief Describes a manually set ISO sensitivity
+
+ Setting this property to -1 (the default), implies that the camera
+ automatically adjusts the ISO sensitivity.
+*/
void QCamera::setManualIsoSensitivity(int iso)
{
Q_D(QCamera);
@@ -707,12 +1047,18 @@ void QCamera::setAutoIsoSensitivity()
d->control->setManualIsoSensitivity(-1);
}
+/*!
+ Returns the minimum ISO sensitivity supported by the camera.
+*/
int QCamera::minimumIsoSensitivity() const
{
Q_D(const QCamera);
return d->control ? d->control->minIso() : -1;
}
+/*!
+ Returns the maximum ISO sensitivity supported by the camera.
+*/
int QCamera::maximumIsoSensitivity() const
{
Q_D(const QCamera);
@@ -725,7 +1071,7 @@ int QCamera::maximumIsoSensitivity() const
float QCamera::minimumExposureTime() const
{
Q_D(const QCamera);
- return d->control ? d->control->minExposureTime() : -1.;
+ return d->control ? d->control->minExposureTime() : -1.f;
}
/*!
@@ -734,10 +1080,17 @@ float QCamera::minimumExposureTime() const
float QCamera::maximumExposureTime() const
{
Q_D(const QCamera);
- return d->control ? d->control->maxExposureTime() : -1.;
+ return d->control ? d->control->maxExposureTime() : -1.f;
}
/*!
+ \qmlproperty float QtMultimedia::Camera::exposureTime
+ Returns the Camera's exposure time in seconds.
+
+ \sa manualExposureTime
+*/
+
+/*!
\property QCamera::exposureTime
\brief Camera's exposure time in seconds.
@@ -751,13 +1104,6 @@ float QCamera::maximumExposureTime() const
*/
/*!
- \property QCamera::isoSensitivity
- \brief The sensor ISO sensitivity.
-
- \sa setAutoIsoSensitivity(), setManualIsoSensitivity()
-*/
-
-/*!
Returns the current exposure time in seconds.
*/
@@ -768,6 +1114,17 @@ float QCamera::exposureTime() const
}
/*!
+ \qmlproperty real QtMultimedia::Camera::manualExposureTime
+
+ Gets or sets a manual exposure time.
+
+ Setting this property to -1 (the default) means that the camera
+ automatically determines the exposure time.
+*/
+
+/*!
+ \property QCamera::manualExposureTime
+
Set the manual exposure time to \a seconds
*/
@@ -838,6 +1195,12 @@ void QCamera::setAutoExposureTime()
*/
/*!
+ \qmlproperty bool QtMultimedia::Camera::flashReady
+
+ Indicates if the flash is charged and ready to use.
+*/
+
+/*!
\property QCamera::flashReady
\brief Indicates if the flash is charged and ready to use.
*/
@@ -855,17 +1218,25 @@ void QCamera::setAutoExposureTime()
*/
/*!
- \fn void QCamera::exposureCompensationChanged(qreal value)
+ \fn void QCamera::exposureCompensationChanged(float value)
Signal emitted when the exposure compensation changes to \a value.
*/
+/*!
+ \qmlproperty WhiteBalanceMode QtMultimedia::Camera::whiteBalanceMode
+
+ Gets or sets the white balance mode being used.
+
+ \sa QCamera::WhiteBalanceMode
+*/
/*!
+ \property QCamera::whiteBalanceMode
+
Returns the white balance mode being used.
*/
-
QCamera::WhiteBalanceMode QCamera::whiteBalanceMode() const
{
Q_D(const QCamera);
@@ -875,7 +1246,6 @@ QCamera::WhiteBalanceMode QCamera::whiteBalanceMode() const
/*!
Sets the white balance to \a mode.
*/
-
void QCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
{
Q_D(QCamera);
@@ -889,23 +1259,38 @@ void QCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
}
/*!
+ \qmlmethod bool QtMultimedia::Camera::isWhiteBalanceModeSupported(WhiteBalanceMode mode)
+
Returns true if the white balance \a mode is supported.
*/
+/*!
+ Returns true if the white balance \a mode is supported.
+*/
bool QCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
{
Q_D(const QCamera);
- if (!d->control)
- return false;
- return d->control->isWhiteBalanceModeSupported(mode);
+ return d->control && d->control->isWhiteBalanceModeSupported(mode);
}
/*!
+ \qmlmethod QtMultimedia::Camera::colorTemperature
+
+ Gets or sets the current color temperature.
+
+ Setting a color temperature will only have an effect if WhiteBalanceManual is
+ supported. In this case, setting a temperature greater 0 will automatically set the
+ white balance mode to WhiteBalanceManual. Setting the temperature to 0 will reset
+ the white balance mode to WhiteBalanceAuto.
+*/
+
+/*!
+ \property QCamera::colorTemperature
+
Returns the current color temperature if the
- current white balance mode is \c WhiteBalanceManual. For other modes the
+ current white balance mode is \c WhiteBalanceManual. For other modes the
return value is undefined.
*/
-
int QCamera::colorTemperature() const
{
Q_D(const QCamera);
@@ -954,6 +1339,22 @@ void QCamera::setColorTemperature(int colorTemperature)
\value WhiteBalanceSunset Sunset white balance mode.
*/
+/*!
+ \fn void QCamera::brightnessChanged()
+ \internal
+*/
+/*!
+ \fn void QCamera::contrastChanged()
+ \internal
+*/
+/*!
+ \fn void QCamera::hueChanged()
+ \internal
+*/
+/*!
+ \fn void QCamera::saturationChanged()
+ \internal
+*/
QT_END_NAMESPACE
#include "moc_qcamera.cpp"
diff --git a/src/multimedia/camera/qcamera.h b/src/multimedia/camera/qcamera.h
index 51e9d4e25..09d9521ff 100644
--- a/src/multimedia/camera/qcamera.h
+++ b/src/multimedia/camera/qcamera.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QCAMERA_H
#define QCAMERA_H
@@ -64,21 +28,25 @@ class Q_MULTIMEDIA_EXPORT QCamera : public QObject
{
Q_OBJECT
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
+ // Qt 7: rename to device
Q_PROPERTY(QCameraDevice cameraDevice READ cameraDevice WRITE setCameraDevice NOTIFY cameraDeviceChanged)
Q_PROPERTY(Error error READ error NOTIFY errorChanged)
Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
Q_PROPERTY(QCameraFormat cameraFormat READ cameraFormat WRITE setCameraFormat NOTIFY cameraFormatChanged)
- Q_PROPERTY(FocusMode focusMode READ focusMode WRITE setFocusMode)
+ Q_PROPERTY(FocusMode focusMode READ focusMode WRITE setFocusMode NOTIFY focusModeChanged)
+ Q_PROPERTY(QPointF focusPoint READ focusPoint NOTIFY focusPointChanged)
Q_PROPERTY(QPointF customFocusPoint READ customFocusPoint WRITE setCustomFocusPoint NOTIFY customFocusPointChanged)
Q_PROPERTY(float focusDistance READ focusDistance WRITE setFocusDistance NOTIFY focusDistanceChanged)
Q_PROPERTY(float minimumZoomFactor READ minimumZoomFactor NOTIFY minimumZoomFactorChanged)
Q_PROPERTY(float maximumZoomFactor READ maximumZoomFactor NOTIFY maximumZoomFactorChanged)
Q_PROPERTY(float zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged)
- Q_PROPERTY(qreal exposureTime READ exposureTime NOTIFY exposureTimeChanged)
+ Q_PROPERTY(float exposureTime READ exposureTime NOTIFY exposureTimeChanged)
+ Q_PROPERTY(int manualExposureTime READ manualExposureTime WRITE setManualExposureTime NOTIFY manualExposureTimeChanged)
Q_PROPERTY(int isoSensitivity READ isoSensitivity NOTIFY isoSensitivityChanged)
- Q_PROPERTY(qreal exposureCompensation READ exposureCompensation WRITE setExposureCompensation NOTIFY exposureCompensationChanged)
+ Q_PROPERTY(int manualIsoSensitivity READ manualIsoSensitivity WRITE setManualIsoSensitivity NOTIFY manualIsoSensitivityChanged)
+ Q_PROPERTY(float exposureCompensation READ exposureCompensation WRITE setExposureCompensation NOTIFY exposureCompensationChanged)
Q_PROPERTY(QCamera::ExposureMode exposureMode READ exposureMode WRITE setExposureMode NOTIFY exposureModeChanged)
Q_PROPERTY(bool flashReady READ isFlashReady NOTIFY flashReady)
Q_PROPERTY(QCamera::FlashMode flashMode READ flashMode WRITE setFlashMode NOTIFY flashModeChanged)
@@ -187,7 +155,7 @@ public:
FocusMode focusMode() const;
void setFocusMode(FocusMode mode);
- bool isFocusModeSupported(FocusMode mode) const;
+ Q_INVOKABLE bool isFocusModeSupported(FocusMode mode) const;
QPointF focusPoint() const;
@@ -203,16 +171,16 @@ public:
void setZoomFactor(float factor);
FlashMode flashMode() const;
- bool isFlashModeSupported(FlashMode mode) const;
- bool isFlashReady() const;
+ Q_INVOKABLE bool isFlashModeSupported(FlashMode mode) const;
+ Q_INVOKABLE bool isFlashReady() const;
TorchMode torchMode() const;
- bool isTorchModeSupported(TorchMode mode) const;
+ Q_INVOKABLE bool isTorchModeSupported(TorchMode mode) const;
ExposureMode exposureMode() const;
- bool isExposureModeSupported(ExposureMode mode) const;
+ Q_INVOKABLE bool isExposureModeSupported(ExposureMode mode) const;
- qreal exposureCompensation() const;
+ float exposureCompensation() const;
int isoSensitivity() const;
int manualIsoSensitivity() const;
@@ -242,7 +210,7 @@ public Q_SLOTS:
void setTorchMode(TorchMode mode);
void setExposureMode(ExposureMode mode);
- void setExposureCompensation(qreal ev);
+ void setExposureCompensation(float ev);
void setManualIsoSensitivity(int iso);
void setAutoIsoSensitivity();
@@ -266,6 +234,7 @@ Q_SIGNALS:
void minimumZoomFactorChanged(float);
void maximumZoomFactorChanged(float);
void focusDistanceChanged(float);
+ void focusPointChanged();
void customFocusPointChanged();
void flashReady(bool);
@@ -273,19 +242,21 @@ Q_SIGNALS:
void torchModeChanged();
void exposureTimeChanged(float speed);
+ void manualExposureTimeChanged(float speed);
void isoSensitivityChanged(int);
- void exposureCompensationChanged(qreal);
+ void manualIsoSensitivityChanged(int);
+ void exposureCompensationChanged(float);
void exposureModeChanged();
- void whiteBalanceModeChanged() const;
- void colorTemperatureChanged() const;
-
+ void whiteBalanceModeChanged() QT6_ONLY(const);
+ void colorTemperatureChanged() QT6_ONLY(const);
void brightnessChanged();
void contrastChanged();
void saturationChanged();
void hueChanged();
private:
+ class QPlatformCamera *platformCamera();
void setCaptureSession(QMediaCaptureSession *session);
friend class QMediaCaptureSession;
Q_DISABLE_COPY(QCamera)
diff --git a/src/multimedia/camera/qcamera_p.h b/src/multimedia/camera/qcamera_p.h
index c0d457649..c0477c242 100644
--- a/src/multimedia/camera/qcamera_p.h
+++ b/src/multimedia/camera/qcamera_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QCAMERA_P_H
#define QCAMERA_P_H
@@ -52,6 +16,7 @@
//
#include "private/qobject_p.h"
+#include "private/qerrorinfo_p.h"
#include "qcamera.h"
#include "qcameradevice.h"
@@ -64,26 +29,18 @@ class QCameraPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QCamera)
public:
- QCameraPrivate()
- : QObjectPrivate(),
- error(QCamera::NoError)
- {
- }
-
void init(const QCameraDevice &device);
QMediaCaptureSession *captureSession = nullptr;
- QPlatformMediaCaptureSession *captureInterface = nullptr;
QPlatformCamera *control = nullptr;
- QCamera::Error error;
- QString errorString;
+ QErrorInfo<QCamera::Error> error;
QCameraDevice cameraDevice;
QCameraFormat cameraFormat;
void _q_error(int error, const QString &errorString);
- void unsetError() { error = QCamera::NoError; errorString.clear(); }
+ void unsetError() { error = {}; }
};
QT_END_NAMESPACE
diff --git a/src/multimedia/camera/qcameradevice.cpp b/src/multimedia/camera/qcameradevice.cpp
index 5d030b27a..50727d49c 100644
--- a/src/multimedia/camera/qcameradevice.cpp
+++ b/src/multimedia/camera/qcameradevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qcameradevice_p.h"
@@ -43,40 +7,167 @@
QT_BEGIN_NAMESPACE
+
+/*!
+ \class QCameraFormat
+ \since 6.2
+ \brief The QCameraFormat class describes a video format supported by a camera device.
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_camera
+
+ QCameraFormat represents a certain video format supported by a camera device.
+
+ The format is a combination of a
+ \l{QVideoFrameFormat::PixelFormat}{pixel format}, resolution and a range of frame
+ rates.
+
+ QCameraFormat objects can be queried from QCameraDevice to inspect the set of
+ supported video formats.
+
+ \sa QCameraDevice, QCamera
+*/
+
+/*!
+ \qmlvaluetype cameraFormat
+ \ingroup qmlvaluetypes
+ \inqmlmodule QtMultimedia
+ \since 6.2
+ //! \instantiates QCameraFormat
+ \brief Describes a video format supported by a camera device.
+ \ingroup multimedia_qml
+ \ingroup multimedia_video_qml
+
+ cameraFormat represents a certain video format supported by a camera device.
+
+ The format is a combination of a
+ \l{pixel format}{QVideoFrameFormat::PixelFormat}, resolution and a range of frame
+ rates.
+
+ cameraFormat objects can be queried from \l cameraDevice to inspect the set of
+ supported video formats.
+
+ \sa cameraDevice, Camera
+*/
+
+/*!
+ Constructs a null camera format.
+
+ \sa isNull()
+*/
QCameraFormat::QCameraFormat() noexcept = default;
+/*!
+ Copy constructs a camera format from the \a other format.
+*/
QCameraFormat::QCameraFormat(const QCameraFormat &other) noexcept = default;
+/*!
+ Assign \a other to this.
+*/
QCameraFormat &QCameraFormat::operator=(const QCameraFormat &other) noexcept = default;
+/*!
+ Destructs the camera format object.
+*/
QCameraFormat::~QCameraFormat() = default;
+/*! \fn bool QCameraFormat::isNull() const noexcept
+
+ Returns true if this is a default constructed QCameraFormat.
+*/
+
+/*!
+ \qmlproperty enumeration QtMultimedia::cameraFormat::pixelFormat
+
+ Holds the pixel format.
+
+ Most commonly this is either QVideoFrameFormat::Format_Jpeg or QVideoFrameFormat::Format_YUVY
+ but other formats could also be supported by the camera.
+
+ \sa QVideoFrameFormat::PixelFormat
+*/
+
+/*!
+ \property QCameraFormat::pixelFormat
+
+ Returns the pixel format.
+
+ Most commonly this is either QVideoFrameFormat::Format_Jpeg or QVideoFrameFormat::Format_YUVY
+ but other formats could also be supported by the camera.
+
+ \sa QVideoFrameFormat::PixelFormat
+*/
QVideoFrameFormat::PixelFormat QCameraFormat::pixelFormat() const noexcept
{
return d ? d->pixelFormat : QVideoFrameFormat::Format_Invalid;
}
+/*!
+ \qmlproperty size QtMultimedia::cameraFormat::resolution
+
+ Returns the resolution.
+*/
+
+/*!
+ \property QCameraFormat::resolution
+
+ Returns the resolution.
+*/
QSize QCameraFormat::resolution() const noexcept
{
return d ? d->resolution : QSize();
}
+/*!
+ \qmlproperty real QtMultimedia::cameraFormat::minFrameRate
+
+ Returns the lowest frame rate defined by this format.
+*/
+
+/*!
+ \property QCameraFormat::minFrameRate
+
+ Returns the lowest frame rate defined by this format.
+*/
float QCameraFormat::minFrameRate() const noexcept
{
return d ? d->minFrameRate : 0;
}
+/*!
+ \qmlproperty real QtMultimedia::cameraFormat::maxFrameRate
+
+ Returns the highest frame rate defined by this format.
+
+ The camera will always try to use the maximum frame rate supported by a
+ certain video format.
+*/
+
+/*!
+ \property QCameraFormat::maxFrameRate
+
+ Returns the highest frame rate defined by this format.
+
+ The camera will always try to use the highest frame rate supported by a
+ certain video format.
+*/
float QCameraFormat::maxFrameRate() const noexcept
{
return d ? d->maxFrameRate : 0;
}
-
+/*!
+ \internal
+*/
QCameraFormat::QCameraFormat(QCameraFormatPrivate *p)
: d(p)
{
}
+/*!
+ Returns \c true if the \a other format is equal to this camera format, otherwise \c false.
+*/
bool QCameraFormat::operator==(const QCameraFormat &other) const
{
if (d == other.d)
@@ -90,9 +181,14 @@ bool QCameraFormat::operator==(const QCameraFormat &other) const
}
/*!
+ \fn bool QCameraFormat::operator!=(const QCameraFormat &other) const
+
+ Returns \c false if the \a other format is equal to this camera format, otherwise \c true.
+*/
+
+/*!
\class QCameraDevice
\brief The QCameraDevice class provides general information about camera devices.
- \since 5.3
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_camera
@@ -113,8 +209,7 @@ bool QCameraFormat::operator==(const QCameraFormat &other) const
\snippet multimedia-snippets/camera.cpp Camera selection
You can also use QCameraDevice to get general information about a camera
- device such as description, physical position on the system, or camera sensor
- orientation.
+ device such as description and physical position on the system.
\snippet multimedia-snippets/camera.cpp Camera info
@@ -122,6 +217,35 @@ bool QCameraFormat::operator==(const QCameraFormat &other) const
*/
/*!
+ \qmlvaluetype cameraDevice
+ \ingroup qmlvaluetypes
+ \inqmlmodule QtMultimedia
+ \since 6.2
+ //! \instantiates QCameraDevice
+ \brief Describes a camera device.
+ \ingroup multimedia_qml
+ \ingroup multimedia_video_qml
+
+ The cameraDevice value type describes the properties of a camera device that
+ is connected to the system.
+
+ The list of camera devices can be queried from the \l{MediaDevices}
+ type. To select a certain camera device set it as the device
+ on \l{Camera}.
+
+ \qml
+ CaptureSession {
+ camera: Camera {
+ cameraDevice: mediaDevices.defaultVideoInput
+ }
+ }
+ MediaDevices {
+ id: mediaDevices
+ }
+ \endqml
+*/
+
+/*!
Constructs a null camera device
*/
QCameraDevice::QCameraDevice() = default;
@@ -161,6 +285,16 @@ bool QCameraDevice::isNull() const
}
/*!
+ \qmlproperty string QtMultimedia::cameraDevice::id
+
+ Holds he device id of the camera
+
+ This is a unique ID to identify the camera and may not be human-readable.
+*/
+
+/*!
+ \property QCameraDevice::id
+
Returns the device id of the camera
This is a unique ID to identify the camera and may not be human-readable.
@@ -170,13 +304,68 @@ QByteArray QCameraDevice::id() const
return d ? d->id : QByteArray();
}
+/*!
+ \qmlproperty bool QtMultimedia::cameraDevice::isDefault
+
+ Is true if this is the default camera device.
+*/
+
+/*!
+ \property QCameraDevice::isDefault
+
+ Returns true if this is the default camera device.
+*/
bool QCameraDevice::isDefault() const
{
return d ? d->isDefault : false;
}
/*!
+ \since 6.7
+ \qmlproperty QtVideo::Rotation QtMultimedia::cameraDevice::correctionAngle
+
+ Returns the rotation angle needed to compensate for the physical camera rotation of the camera
+ compared to its native orientation. In other words, the property represents the clockwise angle
+ through which the output image needs to be rotated to be upright on the device screen in its
+ native orientation. Since \a correctionAngle is relative to the native orientation, this value
+ does not change with altering the device orientation (portrait/landscape). The correction angle
+ may be non-zero mostly on Android, where native and camera orientations are defined by the manufacturer.
+
+ \image camera_correctionAngle_90.png Example with 90 degrees \a correctionAngle
+*/
+
+/*!
+ \since 6.7
+ \property QCameraDevice::correctionAngle
+
+ Returns the rotation angle needed to compensate for the physical camera rotation of the camera
+ compared to its native orientation. In other words, the property represents the clockwise angle
+ through which the output image needs to be rotated to be upright on the device screen in its
+ native orientation. Since \a correctionAngle is relative to the native orientation, this value
+ does not change with altering the device orientation (portrait/landscape). The correction angle
+ may be non-zero mostly on Android, where native and camera orientations are defined by the manufacturer.
+
+ \image camera_correctionAngle_90.png Example with 90 degrees \a correctionAngle
+*/
+QtVideo::Rotation QCameraDevice::correctionAngle() const
+{
+ return d ? QtVideo::Rotation(d->orientation) : QtVideo::Rotation::None;
+}
+
+/*!
+ \qmlproperty string QtMultimedia::cameraDevice::description
+
+ Holds a human readable name of the camera.
+
+ Use this string to present the device to the user.
+*/
+
+/*!
+ \property QCameraDevice::description
+
Returns the human-readable description of the camera.
+
+ Use this string to present the device to the user.
*/
QString QCameraDevice::description() const
{
@@ -184,6 +373,36 @@ QString QCameraDevice::description() const
}
/*!
+ \enum QCameraDevice::Position
+
+ This enum specifies the physical position of the camera on the system hardware.
+
+ \value UnspecifiedPosition The camera position is unspecified or unknown.
+ \value BackFace The camera is on the back face of the system hardware. For example on a
+ mobile device, it means it is on the opposite side to that of the screen.
+ \value FrontFace The camera is on the front face of the system hardware. For example on a
+ mobile device, it means it is on the same side as that of the screen.
+
+ \sa position()
+*/
+
+/*!
+ \qmlproperty enumeration QtMultimedia::cameraDevice::position
+
+ Returns the physical position of the camera on the hardware system.
+
+ The returned value can be one of the following:
+
+ \value cameraDevice.UnspecifiedPosition The camera position is unspecified or unknown.
+ \value cameraDevice.BackFace The camera is on the back face of the system hardware. For example on a
+ mobile device, it means it is on the opposite side to that of the screen.
+ \value cameraDevice.FrontFace The camera is on the front face of the system hardware. For example on a
+ mobile device, it means it is on the same side as that of the screen.
+*/
+
+/*!
+ \property QCameraDevice::position
+
Returns the physical position of the camera on the hardware system.
*/
QCameraDevice::Position QCameraDevice::position() const
@@ -191,12 +410,26 @@ QCameraDevice::Position QCameraDevice::position() const
return d ? d->position : QCameraDevice::UnspecifiedPosition;
}
+/*!
+ Returns a list of resolutions that the camera can use to
+ capture still images.
+
+ \sa QImageCapture
+ */
QList<QSize> QCameraDevice::photoResolutions() const
{
return d ? d->photoResolutions : QList<QSize>{};
}
/*!
+ \qmlproperty CameraFormat QtMultimedia::cameraDevice::videoFormats
+
+ Holds the video formats supported by the camera.
+*/
+
+/*!
+ \property QCameraDevice::videoFormats
+
Returns the video formats supported by the camera.
*/
QList<QCameraFormat> QCameraDevice::videoFormats() const
@@ -231,3 +464,5 @@ QDebug operator<<(QDebug d, const QCameraDevice &camera)
#endif
QT_END_NAMESPACE
+
+#include "moc_qcameradevice.cpp"
diff --git a/src/multimedia/camera/qcameradevice.h b/src/multimedia/camera/qcameradevice.h
index d2a97d927..2a9fac659 100644
--- a/src/multimedia/camera/qcameradevice.h
+++ b/src/multimedia/camera/qcameradevice.h
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QCAMERAINFO_H
#define QCAMERAINFO_H
+#include <QtMultimedia/qtvideo.h>
#include <QtMultimedia/qvideoframe.h>
#include <QtCore/qsharedpointer.h>
@@ -48,6 +13,11 @@ QT_BEGIN_NAMESPACE
class QCameraFormatPrivate;
class Q_MULTIMEDIA_EXPORT QCameraFormat
{
+ Q_GADGET
+ Q_PROPERTY(QSize resolution READ resolution CONSTANT)
+ Q_PROPERTY(QVideoFrameFormat::PixelFormat pixelFormat READ pixelFormat CONSTANT)
+ Q_PROPERTY(float minFrameRate READ minFrameRate CONSTANT)
+ Q_PROPERTY(float maxFrameRate READ maxFrameRate CONSTANT)
public:
QCameraFormat() noexcept;
QCameraFormat(const QCameraFormat &other) noexcept;
@@ -79,6 +49,8 @@ class Q_MULTIMEDIA_EXPORT QCameraDevice
Q_PROPERTY(QString description READ description CONSTANT)
Q_PROPERTY(bool isDefault READ isDefault CONSTANT)
Q_PROPERTY(Position position READ position CONSTANT)
+ Q_PROPERTY(QList<QCameraFormat> videoFormats READ videoFormats CONSTANT)
+ Q_PROPERTY(QtVideo::Rotation correctionAngle READ correctionAngle CONSTANT)
public:
QCameraDevice();
QCameraDevice(const QCameraDevice& other);
@@ -112,6 +84,7 @@ public:
QList<QSize> photoResolutions() const;
QList<QCameraFormat> videoFormats() const;
+ QtVideo::Rotation correctionAngle() const;
// ### Add zoom and other camera information
private:
diff --git a/src/multimedia/camera/qcameradevice_p.h b/src/multimedia/camera/qcameradevice_p.h
index ede736244..638cc0cae 100644
--- a/src/multimedia/camera/qcameradevice_p.h
+++ b/src/multimedia/camera/qcameradevice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCAMERAINFO_P_H
#define QCAMERAINFO_P_H
@@ -53,16 +17,29 @@
#include <QtMultimedia/qcameradevice.h>
#include <QtCore/qsharedpointer.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
class QCameraFormatPrivate : public QSharedData
{
public:
- QVideoFrameFormat::PixelFormat pixelFormat;
+ QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
QSize resolution;
float minFrameRate = 0;
float maxFrameRate = 0;
+ QVideoFrameFormat::ColorRange colorRange = QVideoFrameFormat::ColorRange_Unknown;
+
+ static QVideoFrameFormat::ColorRange getColorRange(const QCameraFormat &format)
+ {
+ auto d = handle(format);
+ return d ? d->colorRange : QVideoFrameFormat::ColorRange_Unknown;
+ }
+
+ static const QCameraFormatPrivate *handle(const QCameraFormat &format)
+ {
+ return format.d.get();
+ }
QCameraFormat create() { return QCameraFormat(this); }
};
@@ -78,6 +55,18 @@ public:
QList<QSize> photoResolutions;
QList<QCameraFormat> videoFormats;
+ static const QCameraDevicePrivate *handle(const QCameraDevice &device)
+ {
+ return device.d.data();
+ }
+
+ bool operator==(const QCameraDevicePrivate &other) const
+ {
+ return id == other.id && description == other.description && isDefault == other.isDefault
+ && position == other.position && orientation == other.orientation
+ && photoResolutions == other.photoResolutions && videoFormats == other.videoFormats;
+ }
+
QCameraDevice create() { return QCameraDevice(this); }
};
diff --git a/src/multimedia/camera/qimagecapture.cpp b/src/multimedia/camera/qimagecapture.cpp
index 7b8473c7a..9b92ce743 100644
--- a/src/multimedia/camera/qimagecapture.cpp
+++ b/src/multimedia/camera/qimagecapture.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qimagecapture.h>
#include <private/qplatformimagecapture_p.h>
#include <qmediametadata.h>
@@ -118,28 +82,22 @@ QImageCapture::QImageCapture(QObject *parent)
{
Q_D(QImageCapture);
d->q_ptr = this;
- d->control = QPlatformMediaIntegration::instance()->createImageCapture(this);
-}
-void QImageCapture::setCaptureSession(QMediaCaptureSession *session)
-{
- Q_D(QImageCapture);
- d->captureSession = session;
-
- QPlatformMediaCaptureSession *platformSession = session ? session->platformSession() : nullptr;
-
- if (platformSession && d->control) {
- platformSession->setImageCapture(d->control);
- } else {
+ auto maybeControl = QPlatformMediaIntegration::instance()->createImageCapture(this);
+ if (!maybeControl) {
+ qWarning() << "Failed to initialize QImageCapture" << maybeControl.error();
+ d->errorString = maybeControl.error();
+ d->error = NotReadyError;
return;
}
+ d->control = maybeControl.value();
connect(d->control, SIGNAL(imageExposed(int)),
this, SIGNAL(imageExposed(int)));
connect(d->control, SIGNAL(imageCaptured(int,QImage)),
this, SIGNAL(imageCaptured(int,QImage)));
- connect(d->control, SIGNAL(imageMetadataAvailable(int,const QMediaMetaData&)),
- this, SIGNAL(imageMetadataAvailable(int,const QMediaMetaData&)));
+ connect(d->control, SIGNAL(imageMetadataAvailable(int,QMediaMetaData)),
+ this, SIGNAL(imageMetadataAvailable(int,QMediaMetaData)));
connect(d->control, SIGNAL(imageAvailable(int,QVideoFrame)),
this, SIGNAL(imageAvailable(int,QVideoFrame)));
connect(d->control, SIGNAL(imageSaved(int,QString)),
@@ -151,15 +109,28 @@ void QImageCapture::setCaptureSession(QMediaCaptureSession *session)
}
/*!
+ \fn void QImageCapture::imageMetadataAvailable(int id, const QMediaMetaData &metaData)
+
+ Signals that an image identified by \a id has \a metaData.
+*/
+
+/*!
+ \internal
+*/
+void QImageCapture::setCaptureSession(QMediaCaptureSession *session)
+{
+ Q_D(QImageCapture);
+ d->captureSession = session;
+}
+
+/*!
Destroys images capture object.
*/
QImageCapture::~QImageCapture()
{
- if (d_ptr->captureSession) {
- d_ptr->captureSession->platformSession()->setImageCapture(nullptr);
+ if (d_ptr->captureSession)
d_ptr->captureSession->setImageCapture(nullptr);
- }
delete d_ptr;
}
@@ -168,7 +139,7 @@ QImageCapture::~QImageCapture()
*/
bool QImageCapture::isAvailable() const
{
- return d_func()->captureSession && d_func()->captureSession->camera();
+ return d_func()->control && d_func()->captureSession && d_func()->captureSession->camera();
}
/*!
@@ -184,6 +155,8 @@ QMediaCaptureSession *QImageCapture::captureSession() const
}
/*!
+ \property QImageCapture::error
+
Returns the current error state.
\sa errorString()
@@ -195,6 +168,8 @@ QImageCapture::Error QImageCapture::error() const
}
/*!
+ \property QImageCapture::errorString
+
Returns a string describing the current error state.
\sa error()
@@ -226,7 +201,8 @@ void QImageCapture::setMetaData(const QMediaMetaData &metaData)
{
Q_D(QImageCapture);
d->metaData = metaData;
- d->control->setMetaData(d->metaData);
+ if (d->control)
+ d->control->setMetaData(d->metaData);
emit metaDataChanged();
}
@@ -292,14 +268,13 @@ bool QImageCapture::isReadyForCapture() const
int QImageCapture::captureToFile(const QString &file)
{
Q_D(QImageCapture);
-
- d->unsetError();
-
if (!d->control) {
- d->_q_error(-1, NotSupportedFeatureError, QPlatformImageCapture::msgCameraNotReady());
+ d->_q_error(-1, d->error, d->errorString);
return -1;
}
+ d->unsetError();
+
if (!isReadyForCapture()) {
d->_q_error(-1, NotReadyError, tr("Could not capture in stopped state"));
return -1;
@@ -323,18 +298,13 @@ int QImageCapture::captureToFile(const QString &file)
int QImageCapture::capture()
{
Q_D(QImageCapture);
-
- d->unsetError();
-
- if (d->control)
+ if (!d->control) {
+ d->_q_error(-1, d->error, d->errorString);
+ return -1;
+ } else {
+ d->unsetError();
return d->control->captureToBuffer();
-
- d->error = NotSupportedFeatureError;
- d->errorString = tr("Device does not support images capture.");
-
- d->_q_error(-1, d->error, d->errorString);
-
- return -1;
+ }
}
/*!
@@ -371,8 +341,7 @@ int QImageCapture::capture()
/*!
\fn QImageCapture::imageAvailable(int id, const QVideoFrame &frame)
- Signal emitted when QImageCapture::CaptureToBuffer is set and
- the \a frame with request \a id is available.
+ Signal emitted when the \a frame with request \a id is available.
*/
/*!
@@ -383,6 +352,20 @@ int QImageCapture::capture()
*/
/*!
+ \enum QImageCapture::FileFormat
+
+ Choose one of the following image formats:
+
+ \value UnspecifiedFormat No format specified
+ \value JPEG \c .jpg or \c .jpeg format
+ \value PNG \c .png format
+ \value WebP \c .webp format
+ \value Tiff \c .tiff format
+ \omitvalue LastFileFormat
+*/
+
+
+/*!
\property QImageCapture::fileFormat
\brief The image format.
*/
@@ -390,9 +373,7 @@ int QImageCapture::capture()
QImageCapture::FileFormat QImageCapture::fileFormat() const
{
Q_D(const QImageCapture);
- if (!d->control)
- return UnspecifiedFormat;
- return d->control->imageSettings().format();
+ return d->control ? d->control->imageSettings().format() : UnspecifiedFormat;
}
/*!
@@ -411,11 +392,19 @@ void QImageCapture::setFileFormat(QImageCapture::FileFormat format)
emit fileFormatChanged();
}
+/*!
+ Returns a list of supported file formats.
+
+ \sa {QImageCapture::}{FileFormat}
+*/
QList<QImageCapture::FileFormat> QImageCapture::supportedFormats()
{
return QPlatformMediaIntegration::instance()->formatInfo()->imageFormats;
}
+/*!
+ Returns the name of the given format, \a f.
+*/
QString QImageCapture::fileFormatName(QImageCapture::FileFormat f)
{
const char *name = nullptr;
@@ -439,6 +428,9 @@ QString QImageCapture::fileFormatName(QImageCapture::FileFormat f)
return QString::fromUtf8(name);
}
+/*!
+ Returns the description of the given file format, \a f.
+*/
QString QImageCapture::fileFormatDescription(QImageCapture::FileFormat f)
{
const char *name = nullptr;
@@ -469,12 +461,16 @@ QString QImageCapture::fileFormatDescription(QImageCapture::FileFormat f)
QSize QImageCapture::resolution() const
{
Q_D(const QImageCapture);
- if (!d->control)
- return QSize();
- return d->control->imageSettings().resolution();
+ return d->control ? d->control->imageSettings().resolution() : QSize{};
}
/*!
+ \fn void QImageCapture::resolutionChanged()
+
+ Signals when the image resolution changes.
+*/
+
+/*!
Sets the \a resolution of the encoded image.
An empty QSize indicates the encoder should make an optimal choice based on
@@ -522,9 +518,7 @@ void QImageCapture::setResolution(int width, int height)
QImageCapture::Quality QImageCapture::quality() const
{
Q_D(const QImageCapture);
- if (!d->control)
- return NormalQuality;
- return d->control->imageSettings().quality();
+ return d->control ? d->control->imageSettings().quality() : NormalQuality;
}
/*!
@@ -543,6 +537,15 @@ void QImageCapture::setQuality(Quality quality)
emit resolutionChanged();
}
+/*!
+ \internal
+*/
+QPlatformImageCapture *QImageCapture::platformImageCapture()
+{
+ Q_D(QImageCapture);
+ return d->control;
+}
+
QT_END_NAMESPACE
#include "moc_qimagecapture.cpp"
diff --git a/src/multimedia/camera/qimagecapture.h b/src/multimedia/camera/qimagecapture.h
index ec52fd818..48608792a 100644
--- a/src/multimedia/camera/qimagecapture.h
+++ b/src/multimedia/camera/qimagecapture.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QCAMERAIMAGECAPTURE_H
#define QCAMERAIMAGECAPTURE_H
@@ -155,6 +119,7 @@ private:
QImageCapture(QCamera *) = delete;
friend class QMediaCaptureSession;
+ class QPlatformImageCapture *platformImageCapture();
void setCaptureSession(QMediaCaptureSession *session);
QImageCapturePrivate *d_ptr;
Q_DISABLE_COPY(QImageCapture)
diff --git a/src/multimedia/compat/removed_api.cpp b/src/multimedia/compat/removed_api.cpp
new file mode 100644
index 000000000..567024c8e
--- /dev/null
+++ b/src/multimedia/compat/removed_api.cpp
@@ -0,0 +1,16 @@
+// 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
+
+#define QT_MULTIMEDIA_BUILD_REMOVED_API
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+QT_USE_NAMESPACE
+
+#if QT_MULTIMEDIA_REMOVED_SINCE(6, 7)
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_MULTIMEDIA_REMOVED_SINCE(6, 7)
diff --git a/src/multimedia/configure.cmake b/src/multimedia/configure.cmake
index 3f41d215c..7c3092a47 100644
--- a/src/multimedia/configure.cmake
+++ b/src/multimedia/configure.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#### Inputs
@@ -15,12 +18,14 @@ qt_find_package(GStreamer OPTIONAL_COMPONENTS Photography PROVIDED_TARGETS GStre
qt_add_qmake_lib_dependency(gstreamer_photography_1_0 gstreamer_1_0)
qt_find_package(GStreamer OPTIONAL_COMPONENTS Gl PROVIDED_TARGETS GStreamer::Gl MODULE_NAME multimedia QMAKE_LIB gstreamer_gl_1_0) # special case
qt_add_qmake_lib_dependency(gstreamer_gl_1_0 gstreamer_1_0)
-if((QNX) OR QT_FIND_ALL_PACKAGES_ALWAYS)
- qt_find_package(MMRenderer PROVIDED_TARGETS MMRenderer::MMRenderer MODULE_NAME multimedia QMAKE_LIB mmrenderer)
-endif()
+qt_find_package(MMRendererCore PROVIDED_TARGETS MMRendererCore::MMRendererCore MODULE_NAME multimedia QMAKE_LIB mmrndcore)
+qt_find_package(MMRenderer PROVIDED_TARGETS MMRenderer::MMRenderer MODULE_NAME multimedia QMAKE_LIB mmrndclient)
qt_find_package(WrapPulseAudio PROVIDED_TARGETS WrapPulseAudio::WrapPulseAudio MODULE_NAME multimedia QMAKE_LIB pulseaudio)
qt_find_package(WMF PROVIDED_TARGETS WMF::WMF MODULE_NAME multimedia QMAKE_LIB wmf)
+qt_find_package(EGL)
+qt_find_package(FFmpeg OPTIONAL_COMPONENTS AVCODEC AVFORMAT AVUTIL SWRESAMPLE SWSCALE PROVIDED_TARGETS FFmpeg::avcodec FFmpeg::avformat FFmpeg::avutil FFmpeg::swresample FFmpeg::swscale MODULE_NAME multimedia QMAKE_LIB ffmpeg)
+qt_find_package(VAAPI COMPONENTS VA DRM PROVIDED_TARGETS VAAPI::VAAPI MODULE_NAME multimedia QMAKE_LIB vaapi)
#### Tests
@@ -44,33 +49,59 @@ qt_config_compile_test("wmsdk"
LABEL "wmsdk.h"
PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/wmsdk"
)
-
+qt_config_compile_test(linux_dmabuf
+ LABEL "Linux DMA buffer support"
+ LIBRARIES
+ EGL::EGL
+ CODE
+"#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+int main(int, char **)
+{
+ /* BEGIN TEST: */
+ eglCreateImage(nullptr,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ nullptr,
+ nullptr);
+ /* END TEST: */
+ return 0;
+}
+")
#### Features
+qt_feature("ffmpeg" PRIVATE
+ LABEL "FFmpeg"
+ ENABLE INPUT_ffmpeg STREQUAL 'yes'
+ DISABLE INPUT_ffmpeg STREQUAL 'no'
+ CONDITION FFmpeg_FOUND AND (APPLE OR WIN32 OR ANDROID OR QNX OR QT_FEATURE_pulseaudio)
+)
qt_feature("alsa" PUBLIC PRIVATE
- LABEL "ALSA"
- CONDITION UNIX AND NOT QNX AND ALSA_FOUND AND NOT QT_FEATURE_gstreamer AND NOT QT_FEATURE_pulseaudio
+ LABEL "ALSA (experimental)"
+ AUTODETECT false
+ CONDITION UNIX AND NOT QNX AND ALSA_FOUND AND NOT QT_FEATURE_pulseaudio
)
-qt_feature_definition("alsa" "QT_NO_ALSA" NEGATE VALUE "1")
qt_feature("avfoundation" PUBLIC PRIVATE
LABEL "AVFoundation"
CONDITION AVFoundation_FOUND
)
-qt_feature_definition("avfoundation" "QT_NO_AVFOUNDATION" NEGATE VALUE "1")
+qt_feature("coreaudio" PUBLIC PRIVATE
+ LABEL "CoreAudio"
+ CONDITION AVFoundation_FOUND
+)
+qt_feature("videotoolbox" PUBLIC PRIVATE
+ LABEL "VideoToolbox"
+ CONDITION AVFoundation_FOUND
+)
qt_feature("evr" PUBLIC PRIVATE
LABEL "evr.h"
CONDITION WIN32 AND TEST_evr
)
-qt_feature_definition("evr" "QT_NO_EVR" NEGATE VALUE "1")
qt_feature("gstreamer_1_0" PRIVATE
LABEL "GStreamer 1.0"
CONDITION GStreamer_FOUND
- ENABLE INPUT_gstreamer STREQUAL 'yes'
- DISABLE INPUT_gstreamer STREQUAL 'no'
-)
-qt_feature("gstreamer" PRIVATE
- CONDITION QT_FEATURE_gstreamer_1_0
)
qt_feature("gstreamer_app" PRIVATE
LABEL "GStreamer App"
@@ -82,8 +113,15 @@ qt_feature("gstreamer_photography" PRIVATE
)
qt_feature("gstreamer_gl" PRIVATE
LABEL "GStreamer OpenGL"
- CONDITION QT_FEATURE_opengl AND QT_FEATURE_gstreamer_1_0 AND GStreamer_Gl_FOUND
+ CONDITION QT_FEATURE_opengl AND QT_FEATURE_gstreamer_1_0 AND GStreamer_Gl_FOUND AND EGL_FOUND
+)
+qt_feature("gstreamer" PRIVATE
+ LABEL "QtMM GStreamer plugin"
+ CONDITION (QT_FEATURE_gstreamer_1_0 AND QT_FEATURE_gstreamer_app)
+ ENABLE INPUT_gstreamer STREQUAL 'yes'
+ DISABLE INPUT_gstreamer STREQUAL 'no'
)
+
qt_feature("gpu_vivante" PRIVATE
LABEL "Vivante GPU"
CONDITION QT_FEATURE_gui AND QT_FEATURE_opengles2 AND TEST_gpu_vivante
@@ -92,32 +130,79 @@ qt_feature("linux_v4l" PRIVATE
LABEL "Video for Linux"
CONDITION UNIX AND TEST_linux_v4l
)
+qt_feature("linux_dmabuf" PRIVATE
+ LABEL "Linux DMA buffer support"
+ CONDITION UNIX AND TEST_linux_dmabuf
+)
+qt_feature("vaapi" PRIVATE
+ LABEL "VAAPI support"
+ CONDITION UNIX AND VAAPI_FOUND AND QT_FEATURE_linux_dmabuf
+)
qt_feature("mmrenderer" PUBLIC PRIVATE
LABEL "MMRenderer"
- CONDITION MMRenderer_FOUND AND false
+ CONDITION MMRenderer_FOUND AND MMRendererCore_FOUND
EMIT_IF QNX
)
-qt_feature_definition("mmrenderer" "QT_NO_MMRENDERER" NEGATE VALUE "1")
qt_feature("pulseaudio" PUBLIC PRIVATE
LABEL "PulseAudio"
- AUTODETECT UNIX
- CONDITION WrapPulseAudio_FOUND AND NOT QT_FEATURE_gstreamer
+ DISABLE INPUT_pulseaudio STREQUAL 'no'
+ CONDITION WrapPulseAudio_FOUND
)
-qt_feature_definition("pulseaudio" "QT_NO_PULSEAUDIO" NEGATE VALUE "1")
qt_feature("wmsdk" PRIVATE
- LABEL "wmsdk.h"
+ LABEL "Windows Media SDK"
CONDITION WIN32 AND TEST_wmsdk
)
+qt_feature("opensles" PRIVATE
+ LABEL "Open SLES (Android)"
+ CONDITION ANDROID
+)
+qt_feature("wasm" PRIVATE
+ LABEL "Web Assembly"
+ CONDITION WASM
+)
+
qt_feature("wmf" PRIVATE
LABEL "Windows Media Foundation"
CONDITION WIN32 AND WMF_FOUND AND QT_FEATURE_wmsdk
)
+
+qt_feature("spatialaudio" PRIVATE
+ LABEL "Spatial Audio"
+)
+qt_feature("spatialaudio_quick3d" PRIVATE
+ LABEL "Spatial Audio (Quick3D)"
+ CONDITION TARGET Qt::Quick3D AND QT_FEATURE_spatialaudio
+)
+
qt_configure_add_summary_section(NAME "Qt Multimedia")
+qt_configure_add_summary_entry(ARGS "spatialaudio")
+qt_configure_add_summary_entry(ARGS "spatialaudio_quick3d")
+qt_configure_add_summary_section(NAME "Low level Audio Backend")
qt_configure_add_summary_entry(ARGS "alsa")
-qt_configure_add_summary_entry(ARGS "gstreamer_1_0")
-qt_configure_add_summary_entry(ARGS "linux_v4l")
qt_configure_add_summary_entry(ARGS "pulseaudio")
qt_configure_add_summary_entry(ARGS "mmrenderer")
+qt_configure_add_summary_entry(ARGS "coreaudio")
+qt_configure_add_summary_entry(ARGS "wmsdk")
+qt_configure_add_summary_entry(ARGS "opensles")
+qt_configure_add_summary_entry(ARGS "wasm")
+qt_configure_end_summary_section()
+qt_configure_add_summary_section(NAME "Plugin")
+qt_configure_add_summary_entry(ARGS "gstreamer_1_0")
+qt_configure_add_summary_entry(ARGS "ffmpeg")
+qt_configure_add_summary_entry(ARGS "mmrenderer")
qt_configure_add_summary_entry(ARGS "avfoundation")
qt_configure_add_summary_entry(ARGS "wmf")
+qt_configure_end_summary_section()
+qt_configure_add_summary_section(NAME "Hardware acceleration and features")
+qt_configure_add_summary_entry(ARGS "linux_v4l")
+qt_configure_add_summary_entry(ARGS "vaapi")
+qt_configure_add_summary_entry(ARGS "linux_dmabuf")
+qt_configure_add_summary_entry(ARGS "videotoolbox")
+qt_configure_end_summary_section()
qt_configure_end_summary_section() # end of "Qt Multimedia" section
+
+qt_configure_add_report_entry(
+ TYPE WARNING
+ MESSAGE "No backend for low level audio found."
+ CONDITION NOT QT_FEATURE_alsa AND NOT QT_FEATURE_pulseaudio AND NOT QT_FEATURE_mmrenderer AND NOT QT_FEATURE_coreaudio AND NOT QT_FEATURE_wmsdk AND NOT ANDROID AND NOT WASM
+)
diff --git a/src/multimedia/platform/darwin/audio/qcoreaudiosessionmanager.mm b/src/multimedia/darwin/qcoreaudiosessionmanager.mm
index 264935d74..cee955905 100644
--- a/src/multimedia/platform/darwin/audio/qcoreaudiosessionmanager.mm
+++ b/src/multimedia/darwin/qcoreaudiosessionmanager.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcoreaudiosessionmanager_p.h"
#import <AVFoundation/AVAudioSession.h>
diff --git a/src/multimedia/platform/darwin/audio/qcoreaudiosessionmanager_p.h b/src/multimedia/darwin/qcoreaudiosessionmanager_p.h
index 7b2a5294f..a6dfe88f4 100644
--- a/src/multimedia/platform/darwin/audio/qcoreaudiosessionmanager_p.h
+++ b/src/multimedia/darwin/qcoreaudiosessionmanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 IOSAUDIOSESSIONMANAGER_H
#define IOSAUDIOSESSIONMANAGER_H
diff --git a/src/multimedia/darwin/qcoreaudioutils.mm b/src/multimedia/darwin/qcoreaudioutils.mm
new file mode 100644
index 000000000..46f98dcc9
--- /dev/null
+++ b/src/multimedia/darwin/qcoreaudioutils.mm
@@ -0,0 +1,344 @@
+// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qcoreaudioutils_p.h"
+#include <qdebug.h>
+#include <mach/mach_time.h>
+
+QT_BEGIN_NAMESPACE
+
+double CoreAudioUtils::sFrequency = 0.0;
+bool CoreAudioUtils::sIsInitialized = false;
+
+void CoreAudioUtils::initialize()
+{
+ struct mach_timebase_info timeBaseInfo;
+ mach_timebase_info(&timeBaseInfo);
+ sFrequency = static_cast<double>(timeBaseInfo.denom) / static_cast<double>(timeBaseInfo.numer);
+ sFrequency *= 1000000000.0;
+
+ sIsInitialized = true;
+}
+
+
+quint64 CoreAudioUtils::currentTime()
+{
+ return mach_absolute_time();
+}
+
+double CoreAudioUtils::frequency()
+{
+ if (!sIsInitialized)
+ initialize();
+ return sFrequency;
+}
+
+QAudioFormat CoreAudioUtils::toQAudioFormat(AudioStreamBasicDescription const& sf)
+{
+ QAudioFormat audioFormat;
+ // all Darwin HW is little endian, we ignore those formats
+ if ((sf.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0 && QSysInfo::ByteOrder != QSysInfo::LittleEndian)
+ return audioFormat;
+
+ // filter out the formats we're interested in
+ QAudioFormat::SampleFormat format = QAudioFormat::Unknown;
+ switch (sf.mBitsPerChannel) {
+ case 8:
+ if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) == 0)
+ format = QAudioFormat::UInt8;
+ break;
+ case 16:
+ if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
+ format = QAudioFormat::Int16;
+ break;
+ case 32:
+ if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
+ format = QAudioFormat::Int32;
+ else if ((sf.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
+ format = QAudioFormat::Float;
+ break;
+ default:
+ break;
+ }
+
+ audioFormat.setSampleFormat(format);
+ audioFormat.setSampleRate(sf.mSampleRate);
+ audioFormat.setChannelCount(sf.mChannelsPerFrame);
+
+ return audioFormat;
+}
+
+AudioStreamBasicDescription CoreAudioUtils::toAudioStreamBasicDescription(QAudioFormat const& audioFormat)
+{
+ AudioStreamBasicDescription sf;
+
+ sf.mFormatFlags = kAudioFormatFlagIsPacked;
+ sf.mSampleRate = audioFormat.sampleRate();
+ sf.mFramesPerPacket = 1;
+ sf.mChannelsPerFrame = audioFormat.channelCount();
+ sf.mBitsPerChannel = audioFormat.bytesPerSample() * 8;
+ sf.mBytesPerFrame = audioFormat.bytesPerFrame();
+ sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame;
+ sf.mFormatID = kAudioFormatLinearPCM;
+
+ switch (audioFormat.sampleFormat()) {
+ case QAudioFormat::Int16:
+ case QAudioFormat::Int32:
+ sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
+ break;
+ case QAudioFormat::Float:
+ sf.mFormatFlags |= kAudioFormatFlagIsFloat;
+ break;
+ case QAudioFormat::UInt8:
+ /* default */
+ case QAudioFormat::Unknown:
+ case QAudioFormat::NSampleFormats:
+ break;
+ }
+
+ return sf;
+}
+
+
+static constexpr struct {
+ QAudioFormat::AudioChannelPosition pos;
+ AudioChannelLabel label;
+} channelMap[] = {
+ { QAudioFormat::FrontLeft, kAudioChannelLabel_Left },
+ { QAudioFormat::FrontRight, kAudioChannelLabel_Right },
+ { QAudioFormat::FrontCenter, kAudioChannelLabel_Center },
+ { QAudioFormat::LFE, kAudioChannelLabel_LFEScreen },
+ { QAudioFormat::BackLeft, kAudioChannelLabel_LeftSurround },
+ { QAudioFormat::BackRight, kAudioChannelLabel_RightSurround },
+ { QAudioFormat::FrontLeftOfCenter, kAudioChannelLabel_LeftCenter },
+ { QAudioFormat::FrontRightOfCenter, kAudioChannelLabel_RightCenter },
+ { QAudioFormat::BackCenter, kAudioChannelLabel_CenterSurround },
+ { QAudioFormat::LFE2, kAudioChannelLabel_LFE2 },
+ { QAudioFormat::SideLeft, kAudioChannelLabel_LeftSurroundDirect }, // ???
+ { QAudioFormat::SideRight, kAudioChannelLabel_RightSurroundDirect }, // ???
+ { QAudioFormat::TopFrontLeft, kAudioChannelLabel_VerticalHeightLeft },
+ { QAudioFormat::TopFrontRight, kAudioChannelLabel_VerticalHeightRight },
+ { QAudioFormat::TopFrontCenter, kAudioChannelLabel_VerticalHeightCenter },
+ { QAudioFormat::TopCenter, kAudioChannelLabel_CenterTopMiddle },
+ { QAudioFormat::TopBackLeft, kAudioChannelLabel_TopBackLeft },
+ { QAudioFormat::TopBackRight, kAudioChannelLabel_TopBackRight },
+ { QAudioFormat::TopSideLeft, kAudioChannelLabel_LeftTopMiddle },
+ { QAudioFormat::TopSideRight, kAudioChannelLabel_RightTopMiddle },
+ { QAudioFormat::TopBackCenter, kAudioChannelLabel_TopBackCenter },
+};
+
+std::unique_ptr<AudioChannelLayout> CoreAudioUtils::toAudioChannelLayout(const QAudioFormat &format, UInt32 *size)
+{
+ auto channelConfig = format.channelConfig();
+ if (channelConfig == QAudioFormat::ChannelConfigUnknown)
+ channelConfig = QAudioFormat::defaultChannelConfigForChannelCount(format.channelCount());
+
+ *size = sizeof(AudioChannelLayout) + int(QAudioFormat::NChannelPositions)*sizeof(AudioChannelDescription);
+ auto *layout = static_cast<AudioChannelLayout *>(malloc(*size));
+ memset(layout, 0, *size);
+ layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
+
+ for (const auto &m : channelMap) {
+ if (channelConfig & QAudioFormat::channelConfig(m.pos))
+ layout->mChannelDescriptions[layout->mNumberChannelDescriptions++].mChannelLabel = m.label;
+ }
+
+ if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter)) {
+ auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
+ desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
+ desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
+ desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 0.f;
+ desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
+ desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
+ }
+ if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft)) {
+ auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
+ desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
+ desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
+ desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = -45.f;
+ desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
+ desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
+ }
+ if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight)) {
+ auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
+ desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
+ desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
+ desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 45.f;
+ desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
+ desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
+ }
+
+ return std::unique_ptr<AudioChannelLayout>(layout);
+}
+
+static constexpr struct {
+ AudioChannelLayoutTag tag;
+ QAudioFormat::ChannelConfig channelConfig;
+} layoutTagMap[] = {
+ { kAudioChannelLayoutTag_Mono, QAudioFormat::ChannelConfigMono },
+ { kAudioChannelLayoutTag_Stereo, QAudioFormat::ChannelConfigStereo },
+ { kAudioChannelLayoutTag_StereoHeadphones, QAudioFormat::ChannelConfigStereo },
+ { kAudioChannelLayoutTag_MPEG_1_0, QAudioFormat::ChannelConfigMono },
+ { kAudioChannelLayoutTag_MPEG_2_0, QAudioFormat::ChannelConfigStereo },
+ { kAudioChannelLayoutTag_MPEG_3_0_A, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
+ QAudioFormat::FrontRight,
+ QAudioFormat::FrontCenter) },
+ { kAudioChannelLayoutTag_MPEG_4_0_A, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
+ QAudioFormat::FrontRight,
+ QAudioFormat::FrontCenter,
+ QAudioFormat::BackCenter) },
+ { kAudioChannelLayoutTag_MPEG_5_0_A, QAudioFormat::ChannelConfigSurround5Dot0 },
+ { kAudioChannelLayoutTag_MPEG_5_1_A, QAudioFormat::ChannelConfigSurround5Dot1 },
+ { kAudioChannelLayoutTag_MPEG_6_1_A, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
+ QAudioFormat::FrontRight,
+ QAudioFormat::FrontCenter,
+ QAudioFormat::LFE,
+ QAudioFormat::BackLeft,
+ QAudioFormat::BackRight,
+ QAudioFormat::BackCenter) },
+ { kAudioChannelLayoutTag_MPEG_7_1_A, QAudioFormat::ChannelConfigSurround7Dot1 },
+ { kAudioChannelLayoutTag_SMPTE_DTV, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
+ QAudioFormat::FrontRight,
+ QAudioFormat::FrontCenter,
+ QAudioFormat::LFE,
+ QAudioFormat::BackLeft,
+ QAudioFormat::BackRight,
+ QAudioFormat::TopFrontLeft,
+ QAudioFormat::TopFrontRight) },
+
+ { kAudioChannelLayoutTag_ITU_2_1, QAudioFormat::ChannelConfig2Dot1 },
+ { kAudioChannelLayoutTag_ITU_2_2, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
+ QAudioFormat::FrontRight,
+ QAudioFormat::BackLeft,
+ QAudioFormat::BackRight) }
+};
+
+
+QAudioFormat::ChannelConfig CoreAudioUtils::fromAudioChannelLayout(const AudioChannelLayout *layout)
+{
+ for (const auto &m : layoutTagMap) {
+ if (m.tag == layout->mChannelLayoutTag)
+ return m.channelConfig;
+ }
+
+ quint32 channels = 0;
+ if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
+ // special case 1 and 2 channel configs, as they are often reported without proper descriptions
+ if (layout->mNumberChannelDescriptions == 1
+ && (layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown
+ || layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Mono))
+ return QAudioFormat::ChannelConfigMono;
+ if (layout->mNumberChannelDescriptions == 2 &&
+ layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown &&
+ layout->mChannelDescriptions[1].mChannelLabel == kAudioChannelLabel_Unknown)
+ return QAudioFormat::ChannelConfigStereo;
+
+ for (uint i = 0; i < layout->mNumberChannelDescriptions; ++i) {
+ const auto channelLabel = layout->mChannelDescriptions[i].mChannelLabel;
+ if (channelLabel == kAudioChannelLabel_Unknown) {
+ // Any number of unknown channel labels occurs for loopback audio devices.
+ // E.g. the case is reproduced with installed software Soundflower.
+ continue;
+ }
+
+ const auto found = std::find_if(channelMap, std::end(channelMap),
+ [channelLabel](const auto &labelWithPos) {
+ return labelWithPos.label == channelLabel;
+ });
+
+ if (found == std::end(channelMap))
+ qWarning() << "audio device has unrecognized channel, index:" << i
+ << "label:" << channelLabel;
+ else
+ channels |= QAudioFormat::channelConfig(found->pos);
+ }
+ } else {
+ qWarning() << "Channel layout uses unimplemented format, channelLayoutTag:"
+ << layout->mChannelLayoutTag;
+ }
+ return QAudioFormat::ChannelConfig(channels);
+}
+
+// QAudioRingBuffer
+CoreAudioRingBuffer::CoreAudioRingBuffer(int bufferSize):
+ m_bufferSize(bufferSize)
+{
+ m_buffer = new char[m_bufferSize];
+ reset();
+}
+
+CoreAudioRingBuffer::~CoreAudioRingBuffer()
+{
+ delete[] m_buffer;
+}
+
+CoreAudioRingBuffer::Region CoreAudioRingBuffer::acquireReadRegion(int size)
+{
+ const int used = m_bufferUsed.fetchAndAddAcquire(0);
+
+ if (used > 0) {
+ const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used));
+
+ return readSize > 0 ? Region(m_buffer + m_readPos, readSize) : Region(0, 0);
+ }
+
+ return Region(0, 0);
+}
+
+void CoreAudioRingBuffer::releaseReadRegion(const CoreAudioRingBuffer::Region &region)
+{
+ m_readPos = (m_readPos + region.second) % m_bufferSize;
+
+ m_bufferUsed.fetchAndAddRelease(-region.second);
+}
+
+CoreAudioRingBuffer::Region CoreAudioRingBuffer::acquireWriteRegion(int size)
+{
+ const int free = m_bufferSize - m_bufferUsed.fetchAndAddAcquire(0);
+
+ Region output;
+
+ if (free > 0) {
+ const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free));
+ output = writeSize > 0 ? Region(m_buffer + m_writePos, writeSize) : Region(0, 0);
+ } else {
+ output = Region(0, 0);
+ }
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("acquireWriteRegion(%d) free: %d returning Region(%p, %d)", size, free, output.first, output.second);
+#endif
+ return output;
+}
+void CoreAudioRingBuffer::releaseWriteRegion(const CoreAudioRingBuffer::Region &region)
+{
+ m_writePos = (m_writePos + region.second) % m_bufferSize;
+
+ m_bufferUsed.fetchAndAddRelease(region.second);
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("releaseWriteRegion(%p,%d): m_writePos:%d", region.first, region.second, m_writePos);
+#endif
+}
+
+int CoreAudioRingBuffer::used() const
+{
+ return m_bufferUsed.loadRelaxed();
+}
+
+int CoreAudioRingBuffer::free() const
+{
+ return m_bufferSize - m_bufferUsed.loadRelaxed();
+}
+
+int CoreAudioRingBuffer::size() const
+{
+ return m_bufferSize;
+}
+
+void CoreAudioRingBuffer::reset()
+{
+ m_readPos = 0;
+ m_writePos = 0;
+ m_bufferUsed.storeRelaxed(0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/darwin/qcoreaudioutils_p.h b/src/multimedia/darwin/qcoreaudioutils_p.h
new file mode 100644
index 000000000..94b6298f3
--- /dev/null
+++ b/src/multimedia/darwin/qcoreaudioutils_p.h
@@ -0,0 +1,72 @@
+// 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 IOSAUDIOUTILS_H
+#define IOSAUDIOUTILS_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 <CoreAudio/CoreAudioTypes.h>
+
+#include <QtMultimedia/QAudioFormat>
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class CoreAudioUtils
+{
+public:
+ static quint64 currentTime();
+ static double frequency();
+ static Q_MULTIMEDIA_EXPORT QAudioFormat toQAudioFormat(const AudioStreamBasicDescription& streamFormat);
+ static AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat);
+
+ // ownership is transferred to caller, free with ::free()
+ static Q_MULTIMEDIA_EXPORT std::unique_ptr<AudioChannelLayout> toAudioChannelLayout(const QAudioFormat &format, UInt32 *size);
+ static QAudioFormat::ChannelConfig fromAudioChannelLayout(const AudioChannelLayout *layout);
+
+private:
+ static void initialize();
+ static double sFrequency;
+ static bool sIsInitialized;
+};
+
+class CoreAudioRingBuffer
+{
+public:
+ typedef QPair<char*, int> Region;
+
+ CoreAudioRingBuffer(int bufferSize);
+ ~CoreAudioRingBuffer();
+
+ Region acquireReadRegion(int size);
+ void releaseReadRegion(Region const& region);
+ Region acquireWriteRegion(int size);
+ void releaseWriteRegion(Region const& region);
+
+ int used() const;
+ int free() const;
+ int size() const;
+
+ void reset();
+
+private:
+ int m_bufferSize;
+ int m_readPos;
+ int m_writePos;
+ char* m_buffer;
+ QAtomicInt m_bufferUsed;
+};
+
+QT_END_NAMESPACE
+
+#endif // IOSAUDIOUTILS_H
diff --git a/src/multimedia/darwin/qdarwinaudiodevice.mm b/src/multimedia/darwin/qdarwinaudiodevice.mm
new file mode 100644
index 000000000..8374f4cea
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinaudiodevice.mm
@@ -0,0 +1,108 @@
+// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qdarwinaudiodevice_p.h"
+#include "qcoreaudioutils_p.h"
+#include <private/qcore_mac_p.h>
+
+#if defined(Q_OS_IOS)
+#include "qcoreaudiosessionmanager_p.h"
+#else
+#include "qmacosaudiodatautils_p.h"
+#endif
+
+#include <QtCore/QDataStream>
+#include <QtCore/QDebug>
+#include <QtCore/QSet>
+#include <QIODevice>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_MACOS)
+QCoreAudioDeviceInfo::QCoreAudioDeviceInfo(AudioDeviceID id, const QByteArray &device, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(device, mode),
+ m_deviceId(id)
+#else
+QCoreAudioDeviceInfo::QCoreAudioDeviceInfo(const QByteArray &device, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(device, mode)
+#endif
+{
+ description = getDescription();
+ getChannelLayout();
+ preferredFormat = determinePreferredFormat();
+ minimumSampleRate = 1;
+ maximumSampleRate = 96000;
+ minimumChannelCount = 1;
+ maximumChannelCount = 16;
+ supportedSampleFormats << QAudioFormat::UInt8 << QAudioFormat::Int16 << QAudioFormat::Int32 << QAudioFormat::Float;
+
+}
+
+QAudioFormat QCoreAudioDeviceInfo::determinePreferredFormat() const
+{
+ QAudioFormat format;
+
+#if defined(Q_OS_MACOS)
+ const auto audioDevicePropertyStreamsAddress =
+ makePropertyAddress(kAudioDevicePropertyStreams, mode);
+
+ if (auto streamIDs = getAudioData<AudioStreamID>(m_deviceId, audioDevicePropertyStreamsAddress,
+ "propertyStreams")) {
+ const auto audioDevicePhysicalFormatPropertyAddress =
+ makePropertyAddress(kAudioStreamPropertyPhysicalFormat, mode);
+
+ for (auto streamID : *streamIDs) {
+ if (auto streamDescription = getAudioObject<AudioStreamBasicDescription>(
+ streamID, audioDevicePhysicalFormatPropertyAddress,
+ "prefferedPhysicalFormat")) {
+ format = CoreAudioUtils::toQAudioFormat(*streamDescription);
+ break;
+ }
+ }
+ }
+
+ if (!format.isValid())
+#endif
+ {
+ format.setSampleRate(44100);
+ format.setSampleFormat(QAudioFormat::Int16);
+ format.setChannelCount(mode == QAudioDevice::Input ? 1 : 2);
+ }
+ format.setChannelConfig(channelConfiguration);
+
+ return format;
+}
+
+
+QString QCoreAudioDeviceInfo::getDescription() const
+{
+#ifdef Q_OS_MACOS
+ const auto propertyAddress = makePropertyAddress(kAudioObjectPropertyName, mode);
+ if (auto name =
+ getAudioObject<CFStringRef>(m_deviceId, propertyAddress, "Device Description")) {
+ auto deleter = qScopeGuard([&name]() { CFRelease(*name); });
+ return QString::fromCFString(*name);
+ }
+
+ return {};
+#else
+ return QString::fromUtf8(id);
+#endif
+}
+
+void QCoreAudioDeviceInfo::getChannelLayout()
+{
+#ifdef Q_OS_MACOS
+ const auto propertyAddress =
+ makePropertyAddress(kAudioDevicePropertyPreferredChannelLayout, mode);
+ if (auto data = getAudioData<char>(m_deviceId, propertyAddress, "prefferedChannelLayout",
+ sizeof(AudioChannelLayout))) {
+ const auto *layout = reinterpret_cast<const AudioChannelLayout *>(data->data());
+ channelConfiguration = CoreAudioUtils::fromAudioChannelLayout(layout);
+ }
+#else
+ channelConfiguration = (mode == QAudioDevice::Input) ? QAudioFormat::ChannelConfigMono : QAudioFormat::ChannelConfigStereo;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/darwin/qdarwinaudiodevice_p.h b/src/multimedia/darwin/qdarwinaudiodevice_p.h
new file mode 100644
index 000000000..637c5d197
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinaudiodevice_p.h
@@ -0,0 +1,52 @@
+// 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 IOSAUDIODEVICEINFO_H
+#define IOSAUDIODEVICEINFO_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qaudiosystem_p.h>
+#include <private/qaudiodevice_p.h>
+
+#if defined(Q_OS_MACOS)
+# include <CoreAudio/CoreAudio.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QCoreAudioDeviceInfo : public QAudioDevicePrivate
+{
+public:
+#if defined(Q_OS_MACOS)
+ QCoreAudioDeviceInfo(AudioDeviceID id, const QByteArray &device, QAudioDevice::Mode mode);
+#else
+ QCoreAudioDeviceInfo(const QByteArray &device, QAudioDevice::Mode mode);
+#endif
+ ~QCoreAudioDeviceInfo() {}
+
+ bool isFormatSupported(const QAudioFormat &format) const;
+
+#if defined(Q_OS_MACOS)
+ AudioDeviceID deviceID() const { return m_deviceId; }
+#endif
+private:
+ QAudioFormat determinePreferredFormat() const;
+ QString getDescription() const;
+ void getChannelLayout();
+#if defined(Q_OS_MACOS)
+ AudioDeviceID m_deviceId;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm b/src/multimedia/darwin/qdarwinaudiosink.mm
index 5fd5afbdf..9242bb2f0 100644
--- a/src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm
+++ b/src/multimedia/darwin/qdarwinaudiosink.mm
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdarwinaudiosink_p.h"
#include "qcoreaudiosessionmanager_p.h"
#include "qdarwinaudiodevice_p.h"
#include "qcoreaudioutils_p.h"
-#include <private/qdarwinmediadevices_p.h>
+#include "qdarwinmediadevices_p.h"
#include <qmediadevices.h>
#include <QtCore/QDataStream>
@@ -49,7 +13,7 @@
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
# include <AudioUnit/AudioComponent.h>
#endif
@@ -59,24 +23,29 @@
QT_BEGIN_NAMESPACE
-QDarwinAudioSinkBuffer::QDarwinAudioSinkBuffer(int bufferSize, int maxPeriodSize, const QAudioFormat &audioFormat)
- : m_deviceError(false)
- , m_maxPeriodSize(maxPeriodSize)
- , m_device(0)
+static int audioRingBufferSize(int bufferSize, int maxPeriodSize)
{
- m_buffer = new CoreAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
- m_bytesPerFrame = audioFormat.bytesPerFrame();
- m_periodTime = m_maxPeriodSize / m_bytesPerFrame * 1000 / audioFormat.sampleRate();
-
- m_fillTimer = new QTimer(this);
- connect(m_fillTimer, SIGNAL(timeout()), SLOT(fillBuffer()));
+ // TODO: review this code
+ return bufferSize
+ + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize));
}
-QDarwinAudioSinkBuffer::~QDarwinAudioSinkBuffer()
+QDarwinAudioSinkBuffer::QDarwinAudioSinkBuffer(int bufferSize, int maxPeriodSize,
+ const QAudioFormat &audioFormat)
+ : m_maxPeriodSize(maxPeriodSize),
+ m_bytesPerFrame(audioFormat.bytesPerFrame()),
+ m_periodTime(maxPeriodSize / m_bytesPerFrame * 1000 / audioFormat.sampleRate()),
+ m_buffer(
+ std::make_unique<CoreAudioRingBuffer>(audioRingBufferSize(bufferSize, maxPeriodSize)))
{
- delete m_buffer;
+ m_fillTimer = new QTimer(this);
+ m_fillTimer->setTimerType(Qt::PreciseTimer);
+ m_fillTimer->setInterval(m_buffer->size() / 2 / m_maxPeriodSize * m_periodTime);
+ connect(m_fillTimer, &QTimer::timeout, this, &QDarwinAudioSinkBuffer::fillBuffer);
}
+QDarwinAudioSinkBuffer::~QDarwinAudioSinkBuffer() = default;
+
qint64 QDarwinAudioSinkBuffer::readFrames(char *data, qint64 maxFrames)
{
bool wecan = true;
@@ -137,31 +106,46 @@ int QDarwinAudioSinkBuffer::available() const
return m_buffer->free();
}
+bool QDarwinAudioSinkBuffer::deviceAtEnd() const
+{
+ return m_deviceAtEnd;
+}
+
void QDarwinAudioSinkBuffer::reset()
{
m_buffer->reset();
- m_device = 0;
- m_deviceError = false;
+ setFillingEnabled(false);
+ setPrefetchDevice(nullptr);
}
void QDarwinAudioSinkBuffer::setPrefetchDevice(QIODevice *device)
{
- if (m_device != device) {
- m_device = device;
- if (m_device != 0)
- fillBuffer();
- }
+ if (std::exchange(m_device, device) == device)
+ return;
+
+ m_deviceError = false;
+ m_deviceAtEnd = device && device->atEnd();
+ const auto wasFillingEnabled = m_fillingEnabled;
+ setFillingEnabled(false);
+ setFillingEnabled(wasFillingEnabled);
}
-void QDarwinAudioSinkBuffer::startFillTimer()
+QIODevice *QDarwinAudioSinkBuffer::prefetchDevice() const
{
- if (m_device != 0)
- m_fillTimer->start(m_buffer->size() / 2 / m_maxPeriodSize * m_periodTime);
+ return m_device;
}
-void QDarwinAudioSinkBuffer::stopFillTimer()
+void QDarwinAudioSinkBuffer::setFillingEnabled(bool enabled)
{
- m_fillTimer->stop();
+ if (std::exchange(m_fillingEnabled, enabled) == enabled)
+ return;
+
+ if (!enabled)
+ m_fillTimer->stop();
+ else if (m_device) {
+ fillBuffer();
+ m_fillTimer->start();
+ }
}
void QDarwinAudioSinkBuffer::fillBuffer()
@@ -178,12 +162,13 @@ void QDarwinAudioSinkBuffer::fillBuffer()
if (region.second > 0) {
region.second = m_device->read(region.first, region.second);
+ m_deviceAtEnd = m_device->atEnd();
if (region.second > 0)
filled += region.second;
else if (region.second == 0)
wecan = false;
else if (region.second < 0) {
- m_fillTimer->stop();
+ setFillingEnabled(false);
region.second = 0;
m_deviceError = true;
}
@@ -219,8 +204,8 @@ qint64 QDarwinAudioSinkDevice::writeData(const char *data, qint64 len)
return m_audioBuffer->writeBytes(data, len);
}
-QDarwinAudioSink::QDarwinAudioSink(const QAudioDevice &device)
- : m_audioDeviceInfo(device)
+QDarwinAudioSink::QDarwinAudioSink(const QAudioDevice &device, QObject *parent)
+ : QPlatformAudioSink(parent), m_audioDeviceInfo(device), m_stateMachine(*this)
{
QAudioDevice di = device;
if (di.isNull())
@@ -233,7 +218,8 @@ QDarwinAudioSink::QDarwinAudioSink(const QAudioDevice &device)
m_device = di.id();
m_clockFrequency = CoreAudioUtils::frequency() / 1000;
- m_audioThreadState.storeRelaxed(Stopped);
+
+ connect(this, &QDarwinAudioSink::stateChanged, this, &QDarwinAudioSink::updateAudioDevice);
}
QDarwinAudioSink::~QDarwinAudioSink()
@@ -243,106 +229,77 @@ QDarwinAudioSink::~QDarwinAudioSink()
void QDarwinAudioSink::start(QIODevice *device)
{
- QIODevice* op = device;
+ reset();
if (!m_audioDeviceInfo.isFormatSupported(m_audioFormat) || !open()) {
- m_stateCode = QAudio::StoppedState;
- m_errorCode = QAudio::OpenError;
+ m_stateMachine.setError(QAudio::OpenError);
return;
}
- reset();
- m_audioBuffer->reset();
- m_audioBuffer->setPrefetchDevice(op);
-
- if (op == 0) {
- op = m_audioIO;
- m_stateCode = QAudio::IdleState;
+ if (!device) {
+ m_stateMachine.setError(QAudio::IOError);
+ return;
}
- else
- m_stateCode = QAudio::ActiveState;
- // Start
+ m_audioBuffer->setPrefetchDevice(device);
+
m_pullMode = true;
- m_errorCode = QAudio::NoError;
m_totalFrames = 0;
- if (m_stateCode == QAudio::ActiveState)
- audioThreadStart();
-
- emit stateChanged(m_stateCode);
+ m_stateMachine.start();
}
QIODevice *QDarwinAudioSink::start()
{
+ reset();
+
if (!m_audioDeviceInfo.isFormatSupported(m_audioFormat) || !open()) {
- m_stateCode = QAudio::StoppedState;
- m_errorCode = QAudio::OpenError;
+ m_stateMachine.setError(QAudio::OpenError);
return m_audioIO;
}
- reset();
- m_audioBuffer->reset();
- m_audioBuffer->setPrefetchDevice(0);
-
- m_stateCode = QAudio::IdleState;
-
- // Start
m_pullMode = false;
- m_errorCode = QAudio::NoError;
m_totalFrames = 0;
- emit stateChanged(m_stateCode);
+ m_stateMachine.start(false);
return m_audioIO;
}
void QDarwinAudioSink::stop()
{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode != QAudio::StoppedState) {
- audioThreadDrain();
+ if (m_audioBuffer)
+ m_audioBuffer->setFillingEnabled(false);
+
+ if (auto notifier = m_stateMachine.stop(QAudio::NoError, true)) {
+ Q_ASSERT((notifier.prevAudioState() == QAudio::ActiveState) == notifier.isDraining());
+ if (notifier.isDraining() && !m_drainSemaphore.tryAcquire(1, 500)) {
+ const bool wasDraining = m_stateMachine.onDrained();
- m_stateCode = QAudio::StoppedState;
- m_errorCode = QAudio::NoError;
- emit stateChanged(m_stateCode);
+ qWarning() << "Failed wait for getting sink drained; was draining:" << wasDraining;
+
+ // handle a rare corner case when the audio thread managed to release the semaphore in
+ // the time window between tryAcquire and onDrained
+ if (!wasDraining)
+ m_drainSemaphore.acquire();
+ }
}
}
void QDarwinAudioSink::reset()
{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode != QAudio::StoppedState) {
- audioThreadStop();
-
- m_stateCode = QAudio::StoppedState;
- m_errorCode = QAudio::NoError;
- emit stateChanged(m_stateCode);
- }
+ onAudioDeviceDrained();
+ m_stateMachine.stopOrUpdateError();
}
void QDarwinAudioSink::suspend()
{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode == QAudio::ActiveState || m_stateCode == QAudio::IdleState) {
- audioThreadStop();
-
- m_stateCode = QAudio::SuspendedState;
- m_errorCode = QAudio::NoError;
- emit stateChanged(m_stateCode);
- }
+ m_stateMachine.suspend();
}
void QDarwinAudioSink::resume()
{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode == QAudio::SuspendedState) {
- audioThreadStart();
-
- m_stateCode = m_pullMode ? QAudio::ActiveState : QAudio::IdleState;
- m_errorCode = QAudio::NoError;
- emit stateChanged(m_stateCode);
- }
+ m_stateMachine.resume();
}
qsizetype QDarwinAudioSink::bytesFree() const
@@ -352,7 +309,7 @@ qsizetype QDarwinAudioSink::bytesFree() const
void QDarwinAudioSink::setBufferSize(qsizetype value)
{
- if (m_stateCode == QAudio::StoppedState)
+ if (state() == QAudio::StoppedState)
m_internalBufferSize = value;
}
@@ -368,17 +325,17 @@ qint64 QDarwinAudioSink::processedUSecs() const
QAudio::Error QDarwinAudioSink::error() const
{
- return m_errorCode;
+ return m_stateMachine.error();
}
QAudio::State QDarwinAudioSink::state() const
{
- return m_stateCode;
+ return m_stateMachine.state();
}
void QDarwinAudioSink::setFormat(const QAudioFormat &format)
{
- if (m_stateCode == QAudio::StoppedState)
+ if (state() == QAudio::StoppedState)
m_audioFormat = format;
}
@@ -393,7 +350,7 @@ void QDarwinAudioSink::setVolume(qreal volume)
if (!m_isOpen)
return;
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
//on OS X the volume can be set directly on the AudioUnit
if (AudioUnitSetParameter(m_audioUnit,
kHALOutputParam_Volume,
@@ -410,22 +367,9 @@ qreal QDarwinAudioSink::volume() const
return m_cachedVolume;
}
-void QDarwinAudioSink::deviceStopped()
-{
- emit stateChanged(m_stateCode);
-}
-
void QDarwinAudioSink::inputReady()
{
- QMutexLocker lock(&m_mutex);
- if (m_stateCode == QAudio::IdleState) {
- audioThreadStart();
-
- m_stateCode = QAudio::ActiveState;
- m_errorCode = QAudio::NoError;
-
- emit stateChanged(m_stateCode);
- }
+ m_stateMachine.activateFromIdle();
}
OSStatus QDarwinAudioSink::renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
@@ -437,15 +381,15 @@ OSStatus QDarwinAudioSink::renderCallback(void *inRefCon, AudioUnitRenderActionF
QDarwinAudioSink* d = static_cast<QDarwinAudioSink*>(inRefCon);
- const int threadState = d->m_audioThreadState.fetchAndAddAcquire(0);
- if (threadState == Stopped) {
+ const auto [drained, stopped] = d->m_stateMachine.getDrainedAndStopped();
+
+ if (drained && stopped) {
ioData->mBuffers[0].mDataByteSize = 0;
- d->audioDeviceStop();
- }
- else {
+ } else {
const UInt32 bytesPerFrame = d->m_streamFormat.mBytesPerFrame;
qint64 framesRead;
+ Q_ASSERT(ioData->mBuffers[0].mDataByteSize / bytesPerFrame == inNumberFrames);
framesRead = d->m_audioBuffer->readFrames((char*)ioData->mBuffers[0].mData,
ioData->mBuffers[0].mDataByteSize / bytesPerFrame);
@@ -454,8 +398,7 @@ OSStatus QDarwinAudioSink::renderCallback(void *inRefCon, AudioUnitRenderActionF
d->m_totalFrames += framesRead;
#if defined(Q_OS_MACOS)
- // If playback is already stopped.
- if (threadState != Running) {
+ if (stopped) {
qreal oldVolume = d->m_cachedVolume;
// Decrease volume smoothly.
d->setVolume(d->m_volume / 2);
@@ -475,14 +418,10 @@ OSStatus QDarwinAudioSink::renderCallback(void *inRefCon, AudioUnitRenderActionF
}
else {
ioData->mBuffers[0].mDataByteSize = 0;
- if (framesRead == 0) {
- if (threadState == Draining)
- d->audioDeviceStop();
- else
- d->audioDeviceIdle();
- }
+ if (framesRead == 0)
+ d->onAudioDeviceIdle();
else
- d->audioDeviceError();
+ d->onAudioDeviceError();
}
}
@@ -498,7 +437,7 @@ bool QDarwinAudioSink::open()
CoreAudioSessionManager::instance().setActive(true);
#endif
- if (m_errorCode != QAudio::NoError)
+ if (error() != QAudio::NoError)
return false;
if (m_isOpen) {
@@ -508,7 +447,7 @@ bool QDarwinAudioSink::open()
AudioComponentDescription componentDescription;
componentDescription.componentType = kAudioUnitType_Output;
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
#else
componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
@@ -543,7 +482,7 @@ bool QDarwinAudioSink::open()
return false;
}
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
//Set Audio Device
if (AudioUnitSetProperty(m_audioUnit,
kAudioOutputUnitProperty_CurrentDevice,
@@ -555,11 +494,13 @@ bool QDarwinAudioSink::open()
return false;
}
#endif
+ UInt32 size;
+
// Set stream format
m_streamFormat = CoreAudioUtils::toAudioStreamBasicDescription(m_audioFormat);
+ size = sizeof(m_streamFormat);
- UInt32 size = sizeof(m_streamFormat);
if (AudioUnitSetProperty(m_audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
@@ -572,7 +513,7 @@ bool QDarwinAudioSink::open()
// Allocate buffer
UInt32 numberOfFrames = 0;
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
size = sizeof(UInt32);
if (AudioUnitGetProperty(m_audioUnit,
kAudioDevicePropertyBufferFrameSize,
@@ -595,10 +536,12 @@ bool QDarwinAudioSink::open()
else
m_internalBufferSize -= m_internalBufferSize % m_streamFormat.mBytesPerFrame;
- m_audioBuffer = new QDarwinAudioSinkBuffer(m_internalBufferSize, m_periodSizeBytes, m_audioFormat);
- connect(m_audioBuffer, SIGNAL(readyRead()), SLOT(inputReady())); //Pull
+ m_audioBuffer = std::make_unique<QDarwinAudioSinkBuffer>(m_internalBufferSize,
+ m_periodSizeBytes, m_audioFormat);
+ connect(m_audioBuffer.get(), &QDarwinAudioSinkBuffer::readyRead, this,
+ &QDarwinAudioSink::inputReady); // Pull
- m_audioIO = new QDarwinAudioSinkDevice(m_audioBuffer, this);
+ m_audioIO = new QDarwinAudioSinkDevice(m_audioBuffer.get(), this);
//Init
if (AudioUnitInitialize(m_audioUnit)) {
@@ -616,74 +559,49 @@ bool QDarwinAudioSink::open()
void QDarwinAudioSink::close()
{
if (m_audioUnit != 0) {
- AudioOutputUnitStop(m_audioUnit);
+ m_stateMachine.stop();
+
AudioUnitUninitialize(m_audioUnit);
AudioComponentInstanceDispose(m_audioUnit);
+ m_audioUnit = 0;
}
- delete m_audioBuffer;
-}
-
-void QDarwinAudioSink::audioThreadStart()
-{
- startTimers();
- m_audioThreadState.storeRelaxed(Running);
- AudioOutputUnitStart(m_audioUnit);
-}
-
-void QDarwinAudioSink::audioThreadStop()
-{
- stopTimers();
- if (m_audioThreadState.testAndSetAcquire(Running, Stopped))
- m_threadFinished.wait(&m_mutex, 500);
+ m_audioBuffer.reset();
}
-void QDarwinAudioSink::audioThreadDrain()
+void QDarwinAudioSink::onAudioDeviceIdle()
{
- stopTimers();
- if (m_audioThreadState.testAndSetAcquire(Running, Draining))
- m_threadFinished.wait(&m_mutex, 500);
+ const bool atEnd = m_audioBuffer->deviceAtEnd();
+ if (!m_stateMachine.updateActiveOrIdle(false, atEnd ? QAudio::NoError : QAudio::UnderrunError))
+ onAudioDeviceDrained();
}
-void QDarwinAudioSink::audioDeviceStop()
+void QDarwinAudioSink::onAudioDeviceDrained()
{
- AudioOutputUnitStop(m_audioUnit);
- m_audioThreadState.storeRelaxed(Stopped);
- m_threadFinished.wakeOne();
+ if (m_stateMachine.onDrained())
+ m_drainSemaphore.release();
}
-void QDarwinAudioSink::audioDeviceIdle()
+void QDarwinAudioSink::onAudioDeviceError()
{
- if (m_stateCode == QAudio::ActiveState) {
- QMutexLocker lock(&m_mutex);
- audioDeviceStop();
-
- m_errorCode = QAudio::UnderrunError;
- m_stateCode = QAudio::IdleState;
- QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
- }
+ m_stateMachine.stop(QAudio::IOError);
}
-void QDarwinAudioSink::audioDeviceError()
+void QDarwinAudioSink::updateAudioDevice()
{
- if (m_stateCode == QAudio::ActiveState) {
- QMutexLocker lock(&m_mutex);
- audioDeviceStop();
+ const auto state = m_stateMachine.state();
- m_errorCode = QAudio::IOError;
- m_stateCode = QAudio::StoppedState;
- QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
- }
-}
+ Q_ASSERT(m_audioBuffer);
+ Q_ASSERT(m_audioUnit);
-void QDarwinAudioSink::startTimers()
-{
- m_audioBuffer->startFillTimer();
-}
+ if (state == QAudio::StoppedState)
+ m_audioBuffer->reset();
+ else
+ m_audioBuffer->setFillingEnabled(state != QAudio::SuspendedState);
-void QDarwinAudioSink::stopTimers()
-{
- m_audioBuffer->stopFillTimer();
+ const bool unitStarted = state == QAudio::ActiveState;
+ if (std::exchange(m_audioUnitStarted, unitStarted) != unitStarted)
+ (unitStarted ? AudioOutputUnitStart : AudioOutputUnitStop)(m_audioUnit);
}
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/audio/qdarwinaudiosink_p.h b/src/multimedia/darwin/qdarwinaudiosink_p.h
index bb2c6507f..1fddcb205 100644
--- a/src/multimedia/platform/darwin/audio/qdarwinaudiosink_p.h
+++ b/src/multimedia/darwin/qdarwinaudiosink_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 IOSAUDIOOUTPUT_H
#define IOSAUDIOOUTPUT_H
@@ -50,18 +14,18 @@
// We mean it.
//
-#include <qaudiosystem_p.h>
+#include <private/qaudiosystem_p.h>
+#include <private/qaudiostatemachine_p.h>
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
# include <CoreAudio/CoreAudio.h>
#endif
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudioTypes.h>
#include <QtCore/QIODevice>
-#include <QtCore/QWaitCondition>
-#include <QtCore/QMutex>
-#include <private/qdarwinaudiodevice_p.h>
+#include <qdarwinaudiodevice_p.h>
+#include <qsemaphore.h>
QT_BEGIN_NAMESPACE
@@ -82,12 +46,16 @@ public:
qint64 writeBytes(const char *data, qint64 maxSize);
int available() const;
+
+ bool deviceAtEnd() const;
+
void reset();
void setPrefetchDevice(QIODevice *device);
- void startFillTimer();
- void stopFillTimer();
+ QIODevice *prefetchDevice() const;
+
+ void setFillingEnabled(bool enabled);
signals:
void readyRead();
@@ -96,13 +64,15 @@ private slots:
void fillBuffer();
private:
- bool m_deviceError;
- int m_maxPeriodSize;
- int m_bytesPerFrame;
- int m_periodTime;
- QIODevice *m_device;
- QTimer *m_fillTimer;
- CoreAudioRingBuffer *m_buffer;
+ bool m_deviceError = false;
+ bool m_fillingEnabled = false;
+ bool m_deviceAtEnd = false;
+ const int m_maxPeriodSize = 0;
+ const int m_bytesPerFrame = 0;
+ const int m_periodTime = 0;
+ QIODevice *m_device = nullptr;
+ QTimer *m_fillTimer = nullptr;
+ std::unique_ptr<CoreAudioRingBuffer> m_buffer;
};
class QDarwinAudioSinkDevice : public QIODevice
@@ -125,7 +95,7 @@ class QDarwinAudioSink : public QPlatformAudioSink
Q_OBJECT
public:
- QDarwinAudioSink(const QAudioDevice &device);
+ QDarwinAudioSink(const QAudioDevice &device, QObject *parent);
~QDarwinAudioSink();
void start(QIODevice *device);
@@ -147,15 +117,11 @@ public:
qreal volume() const;
private slots:
- void deviceStopped();
void inputReady();
+ void updateAudioDevice();
private:
- enum {
- Running,
- Draining,
- Stopped
- };
+ enum ThreadState { Running, Draining, Stopped };
static OSStatus renderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
@@ -166,15 +132,9 @@ private:
bool open();
void close();
- void audioThreadStart();
- void audioThreadStop();
- void audioThreadDrain();
- void audioDeviceStop();
- void audioDeviceIdle();
- void audioDeviceError();
-
- void startTimers();
- void stopTimers();
+ void onAudioDeviceIdle();
+ void onAudioDeviceError();
+ void onAudioDeviceDrained();
QAudioDevice m_audioDeviceInfo;
QByteArray m_device;
@@ -191,20 +151,18 @@ private:
AudioDeviceID m_audioDeviceId;
#endif
AudioUnit m_audioUnit = 0;
+ bool m_audioUnitStarted = false;
Float64 m_clockFrequency = 0;
AudioStreamBasicDescription m_streamFormat;
- QDarwinAudioSinkBuffer *m_audioBuffer = nullptr;
- QAtomicInt m_audioThreadState;
- QWaitCondition m_threadFinished;
- QMutex m_mutex;
+ std::unique_ptr<QDarwinAudioSinkBuffer> m_audioBuffer;
qreal m_cachedVolume = 1.;
#if defined(Q_OS_MACOS)
qreal m_volume = 1.;
#endif
bool m_pullMode = false;
- QAudio::Error m_errorCode = QAudio::NoError;
- QAudio::State m_stateCode = QAudio::StoppedState;
+ QAudioStateMachine m_stateMachine;
+ QSemaphore m_drainSemaphore;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/audio/qdarwinaudiosource.mm b/src/multimedia/darwin/qdarwinaudiosource.mm
index 17754518b..4c1345fb8 100644
--- a/src/multimedia/platform/darwin/audio/qdarwinaudiosource.mm
+++ b/src/multimedia/darwin/qdarwinaudiosource.mm
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdarwinaudiosource_p.h"
#include "qcoreaudiosessionmanager_p.h"
#include "qdarwinaudiodevice_p.h"
#include "qcoreaudioutils_p.h"
-#include "private/qdarwinmediadevices_p.h"
+#include "qdarwinmediadevices_p.h"
#include <qmediadevices.h>
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
# include <AudioUnit/AudioComponent.h>
#endif
@@ -205,7 +169,7 @@ QDarwinAudioSourceBuffer::QDarwinAudioSourceBuffer(int bufferSize, int maxPeriod
m_inputBufferList = new QCoreAudioBufferList(m_inputFormat);
m_flushTimer = new QTimer(this);
- connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer()));
+ connect(m_flushTimer, SIGNAL(timeout()), this, SLOT(flushBuffer()));
if (CoreAudioUtils::toQAudioFormat(inputFormat) != CoreAudioUtils::toQAudioFormat(outputFormat)) {
if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
@@ -432,7 +396,7 @@ QDarwinAudioSourceDevice::QDarwinAudioSourceDevice(QDarwinAudioSourceBuffer *aud
, m_audioBuffer(audioBuffer)
{
open(QIODevice::ReadOnly | QIODevice::Unbuffered);
- connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ connect(m_audioBuffer, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
}
qint64 QDarwinAudioSourceDevice::readData(char *data, qint64 len)
@@ -448,8 +412,9 @@ qint64 QDarwinAudioSourceDevice::writeData(const char *data, qint64 len)
return 0;
}
-QDarwinAudioSource::QDarwinAudioSource(const QAudioDevice &device)
- : m_audioDeviceInfo(device)
+QDarwinAudioSource::QDarwinAudioSource(const QAudioDevice &device, QObject *parent)
+ : QPlatformAudioSource(parent)
+ , m_audioDeviceInfo(device)
, m_isOpen(false)
, m_internalBufferSize(DEFAULT_BUFFER_SIZE)
, m_totalFrames(0)
@@ -487,11 +452,9 @@ bool QDarwinAudioSource::open()
if (m_isOpen)
return true;
- UInt32 size = 0;
-
AudioComponentDescription componentDescription;
componentDescription.componentType = kAudioUnitType_Output;
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
#else
componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
@@ -550,7 +513,7 @@ bool QDarwinAudioSource::open()
return false;
}
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
//Set Audio Device
if (AudioUnitSetProperty(m_audioUnit,
kAudioOutputUnitProperty_CurrentDevice,
@@ -566,7 +529,9 @@ bool QDarwinAudioSource::open()
//set format
m_streamFormat = CoreAudioUtils::toAudioStreamBasicDescription(m_audioFormat);
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
+ UInt32 size = 0;
+
if (m_audioFormat == m_audioDeviceInfo.preferredFormat()) {
#endif
@@ -577,7 +542,7 @@ bool QDarwinAudioSource::open()
1,
&m_deviceFormat,
sizeof(m_deviceFormat));
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
} else {
size = sizeof(m_deviceFormat);
if (AudioUnitGetProperty(m_audioUnit,
@@ -604,7 +569,7 @@ bool QDarwinAudioSource::open()
//setup buffers
UInt32 numberOfFrames;
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
size = sizeof(UInt32);
if (AudioUnitGetProperty(m_audioUnit,
kAudioDevicePropertyBufferFrameSize,
diff --git a/src/multimedia/platform/darwin/audio/qdarwinaudiosource_p.h b/src/multimedia/darwin/qdarwinaudiosource_p.h
index 6a14b6a55..87c3c1070 100644
--- a/src/multimedia/platform/darwin/audio/qdarwinaudiosource_p.h
+++ b/src/multimedia/darwin/qdarwinaudiosource_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 IOSAUDIOINPUT_H
#define IOSAUDIOINPUT_H
@@ -50,8 +14,8 @@
// We mean it.
//
-#include <qaudiosystem_p.h>
-#include <private/qdarwinaudiodevice_p.h>
+#include <private/qaudiosystem_p.h>
+#include <qdarwinaudiodevice_p.h>
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudioTypes.h>
@@ -201,7 +165,7 @@ class QDarwinAudioSource : public QPlatformAudioSource
Q_OBJECT
public:
- QDarwinAudioSource(const QAudioDevice &device);
+ QDarwinAudioSource(const QAudioDevice &device, QObject *parent);
~QDarwinAudioSource();
void start(QIODevice *device);
@@ -262,7 +226,7 @@ private:
QAudioFormat m_audioFormat;
QIODevice *m_audioIO;
AudioUnit m_audioUnit;
-#if defined(Q_OS_OSX)
+#if defined(Q_OS_MACOS)
AudioDeviceID m_audioDeviceId;
#endif
Float64 m_clockFrequency;
diff --git a/src/multimedia/darwin/qdarwinmediadevices.mm b/src/multimedia/darwin/qdarwinmediadevices.mm
new file mode 100644
index 000000000..b0a108935
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinmediadevices.mm
@@ -0,0 +1,269 @@
+// 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 "qdarwinmediadevices_p.h"
+#include "qmediadevices.h"
+#include "private/qaudiodevice_p.h"
+#include "qdarwinaudiodevice_p.h"
+#include "qdarwinaudiosource_p.h"
+#include "qdarwinaudiosink_p.h"
+
+#include <qloggingcategory.h>
+
+#include <qdebug.h>
+
+#if defined(Q_OS_IOS)
+#include "qcoreaudiosessionmanager_p.h"
+#import <AVFoundation/AVFoundation.h>
+#else
+#include "qmacosaudiodatautils_p.h"
+#endif
+
+#if defined(Q_OS_MACOS)
+static Q_LOGGING_CATEGORY(qLcDarwinMediaDevices, "qt.multimedia.darwin.mediaDevices")
+#endif
+
+QT_BEGIN_NAMESPACE
+
+template<typename... Args>
+QAudioDevice createAudioDevice(bool isDefault, Args &&...args)
+{
+ auto *dev = new QCoreAudioDeviceInfo(std::forward<Args>(args)...);
+ dev->isDefault = isDefault;
+ return dev->create();
+}
+
+#if defined(Q_OS_MACOS)
+
+static AudioDeviceID defaultAudioDevice(QAudioDevice::Mode mode)
+{
+ const AudioObjectPropertySelector selector = (mode == QAudioDevice::Output) ? kAudioHardwarePropertyDefaultOutputDevice
+ : kAudioHardwarePropertyDefaultInputDevice;
+ const AudioObjectPropertyAddress propertyAddress = {
+ selector,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain,
+ };
+
+ if (auto audioDevice = getAudioObject<AudioDeviceID>(kAudioObjectSystemObject, propertyAddress,
+ "Default Device")) {
+ return *audioDevice;
+ }
+
+ return 0;
+}
+
+static QByteArray uniqueId(AudioDeviceID device, QAudioDevice::Mode mode)
+{
+ const AudioObjectPropertyAddress propertyAddress =
+ makePropertyAddress(kAudioDevicePropertyDeviceUID, mode);
+
+ if (auto name = getAudioObject<CFStringRef>(device, propertyAddress, "Device UID")) {
+ QString s = QString::fromCFString(*name);
+ CFRelease(*name);
+ return s.toUtf8();
+ }
+
+ return QByteArray();
+}
+
+static QList<QAudioDevice> availableAudioDevices(QAudioDevice::Mode mode)
+{
+ QList<QAudioDevice> devices;
+
+ AudioDeviceID defaultDevice = defaultAudioDevice(mode);
+ if (defaultDevice != 0)
+ devices << createAudioDevice(true, defaultDevice, uniqueId(defaultDevice, mode), mode);
+
+ const AudioObjectPropertyAddress audioDevicesPropertyAddress = {
+ kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain
+ };
+
+ if (auto audioDevices = getAudioData<AudioDeviceID>(
+ kAudioObjectSystemObject, audioDevicesPropertyAddress, "Audio Devices")) {
+ const AudioObjectPropertyAddress audioDeviceStreamFormatPropertyAddress =
+ makePropertyAddress(kAudioDevicePropertyStreamFormat, mode);
+
+ for (const auto &device : *audioDevices) {
+ if (device == defaultDevice)
+ continue;
+
+ if (getAudioObject<AudioStreamBasicDescription>(device,
+ audioDeviceStreamFormatPropertyAddress,
+ nullptr /*don't print logs*/)) {
+ devices << createAudioDevice(false, device, uniqueId(device, mode), mode);
+ }
+ }
+ }
+
+ return devices;
+}
+
+static OSStatus audioDeviceChangeListener(AudioObjectID id, UInt32,
+ const AudioObjectPropertyAddress *address, void *ptr)
+{
+ Q_ASSERT(address);
+ Q_ASSERT(ptr);
+
+ QDarwinMediaDevices *instance = static_cast<QDarwinMediaDevices *>(ptr);
+
+ qCDebug(qLcDarwinMediaDevices)
+ << "audioDeviceChangeListener: id:" << id << "address: " << address->mSelector
+ << address->mScope << address->mElement;
+
+ switch (address->mSelector) {
+ case kAudioHardwarePropertyDefaultInputDevice:
+ instance->onInputsUpdated();
+ break;
+ case kAudioHardwarePropertyDefaultOutputDevice:
+ instance->onOutputsUpdated();
+ break;
+ default:
+ instance->onInputsUpdated();
+ instance->onOutputsUpdated();
+ break;
+ }
+
+ return 0;
+}
+
+static constexpr AudioObjectPropertyAddress listenerAddresses[] = {
+ { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain },
+ { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain },
+ { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMain }
+};
+
+static void setAudioListeners(QDarwinMediaDevices &instance)
+{
+ for (const auto &address : listenerAddresses) {
+ const auto err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &address,
+ audioDeviceChangeListener, &instance);
+
+ if (err)
+ qWarning() << "Fail to add listener. mSelector:" << address.mSelector
+ << "mScope:" << address.mScope << "mElement:" << address.mElement
+ << "err:" << err;
+ }
+}
+
+static void removeAudioListeners(QDarwinMediaDevices &instance)
+{
+ for (const auto &address : listenerAddresses) {
+ const auto err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &address,
+ audioDeviceChangeListener, &instance);
+
+ if (err)
+ qWarning() << "Fail to remove listener. mSelector:" << address.mSelector
+ << "mScope:" << address.mScope << "mElement:" << address.mElement
+ << "err:" << err;
+ }
+}
+
+#elif defined(Q_OS_IOS)
+
+static QList<QAudioDevice> availableAudioDevices(QAudioDevice::Mode mode)
+{
+ QList<QAudioDevice> devices;
+
+ if (mode == QAudioDevice::Output) {
+ devices.append(createAudioDevice(true, "default", QAudioDevice::Output));
+ } else {
+ AVCaptureDevice *defaultDevice =
+ [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
+
+ // TODO: Support Bluetooth and USB devices
+ AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession =
+ [AVCaptureDeviceDiscoverySession
+ discoverySessionWithDeviceTypes:@[ AVCaptureDeviceTypeBuiltInMicrophone ]
+ mediaType:AVMediaTypeAudio
+ position:AVCaptureDevicePositionUnspecified];
+
+ NSArray *captureDevices = [captureDeviceDiscoverySession devices];
+ for (AVCaptureDevice *device in captureDevices) {
+ const bool isDefault =
+ defaultDevice && [defaultDevice.uniqueID isEqualToString:device.uniqueID];
+ devices.append(createAudioDevice(isDefault,
+ QString::fromNSString(device.uniqueID).toUtf8(),
+ QAudioDevice::Input));
+ }
+ }
+
+ return devices;
+}
+
+static void setAudioListeners(QDarwinMediaDevices &)
+{
+ // ### This should use the audio session manager
+}
+
+static void removeAudioListeners(QDarwinMediaDevices &)
+{
+ // ### This should use the audio session manager
+}
+
+#endif
+
+
+QDarwinMediaDevices::QDarwinMediaDevices()
+ : QPlatformMediaDevices()
+{
+#ifdef Q_OS_MACOS // TODO: implement setAudioListeners, removeAudioListeners for Q_OS_IOS, after
+ // that - remove or modify the define
+ m_cachedAudioInputs = availableAudioDevices(QAudioDevice::Input);
+ m_cachedAudioOutputs = availableAudioDevices(QAudioDevice::Output);
+#endif
+
+ setAudioListeners(*this);
+}
+
+
+QDarwinMediaDevices::~QDarwinMediaDevices()
+{
+ removeAudioListeners(*this);
+}
+
+QList<QAudioDevice> QDarwinMediaDevices::audioInputs() const
+{
+ return availableAudioDevices(QAudioDevice::Input);
+}
+
+QList<QAudioDevice> QDarwinMediaDevices::audioOutputs() const
+{
+ return availableAudioDevices(QAudioDevice::Output);
+}
+
+void QDarwinMediaDevices::onInputsUpdated()
+{
+ auto inputs = availableAudioDevices(QAudioDevice::Input);
+ if (m_cachedAudioInputs != inputs) {
+ m_cachedAudioInputs = inputs;
+ emit audioInputsChanged();
+ }
+}
+
+void QDarwinMediaDevices::onOutputsUpdated()
+{
+ auto outputs = availableAudioDevices(QAudioDevice::Output);
+ if (m_cachedAudioOutputs != outputs) {
+ m_cachedAudioOutputs = outputs;
+ emit audioOutputsChanged();
+ }
+}
+
+QPlatformAudioSource *QDarwinMediaDevices::createAudioSource(const QAudioDevice &info,
+ QObject *parent)
+{
+ return new QDarwinAudioSource(info, parent);
+}
+
+QPlatformAudioSink *QDarwinMediaDevices::createAudioSink(const QAudioDevice &info,
+ QObject *parent)
+{
+ return new QDarwinAudioSink(info, parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/darwin/qdarwinmediadevices_p.h b/src/multimedia/darwin/qdarwinmediadevices_p.h
new file mode 100644
index 000000000..0c7a45433
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinmediadevices_p.h
@@ -0,0 +1,49 @@
+// 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
+
+#ifndef QDARWINMEDIADEVICES_H
+#define QDARWINMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+#include <qelapsedtimer.h>
+#include <qcameradevice.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCameraDevice;
+
+class QDarwinMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QDarwinMediaDevices();
+ ~QDarwinMediaDevices() override;
+
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &info,
+ QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &info,
+ QObject *parent) override;
+
+ void onInputsUpdated();
+ void onOutputsUpdated();
+
+private:
+ QList<QAudioDevice> m_cachedAudioInputs;
+ QList<QAudioDevice> m_cachedAudioOutputs;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/darwin/qmacosaudiodatautils_p.h b/src/multimedia/darwin/qmacosaudiodatautils_p.h
new file mode 100644
index 000000000..8cc2f8440
--- /dev/null
+++ b/src/multimedia/darwin/qmacosaudiodatautils_p.h
@@ -0,0 +1,112 @@
+// 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
+
+#ifndef QMACOSAUDIODATAUTILS_P_H
+#define QMACOSAUDIODATAUTILS_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 <CoreAudio/AudioHardware.h>
+
+#include "qaudiodevice.h"
+#include "qdebug.h"
+
+#include <optional>
+#include <vector>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+template<typename... Args>
+void printUnableToReadWarning(const char *logName, AudioObjectID objectID, const AudioObjectPropertyAddress &address, Args &&...args)
+{
+ if (!logName)
+ return;
+
+ char scope[5] = {0};
+ memcpy(&scope, &address.mScope, 4);
+ std::reverse(scope, scope + 4);
+
+ auto warn = qWarning();
+ warn << "Unable to read property" << logName << "for object" << objectID << ", scope" << scope << ";";
+ (warn << ... << args);
+ warn << "\n If the warning is unexpected use test_audio_config to get comprehensive audio info and report a bug";
+}
+
+inline static AudioObjectPropertyAddress
+makePropertyAddress(AudioObjectPropertySelector selector, QAudioDevice::Mode mode,
+ AudioObjectPropertyElement element = kAudioObjectPropertyElementMain)
+{
+ return { selector,
+ mode == QAudioDevice::Input ? kAudioDevicePropertyScopeInput
+ : kAudioDevicePropertyScopeOutput,
+ element };
+}
+
+inline static bool getAudioData(AudioObjectID objectID, const AudioObjectPropertyAddress &address,
+ void *dst, UInt32 dstSize, const char *logName)
+{
+ UInt32 readBytes = dstSize;
+ const auto res = AudioObjectGetPropertyData(objectID, &address, 0, nullptr, &readBytes, dst);
+
+ if (res != noErr)
+ printUnableToReadWarning(logName, objectID, address, "Err:", res);
+ else if (readBytes != dstSize)
+ printUnableToReadWarning(logName, objectID, address, "Data size", readBytes, "VS", dstSize,
+ "expected");
+ else
+ return true;
+
+ return false;
+}
+
+template<typename T>
+std::optional<std::vector<T>> getAudioData(AudioObjectID objectID,
+ const AudioObjectPropertyAddress &address,
+ const char *logName, size_t minDataSize = 0)
+{
+ static_assert(std::is_trivial_v<T>, "A trivial type is expected");
+
+ UInt32 size = 0;
+ const auto res = AudioObjectGetPropertyDataSize(objectID, &address, 0, nullptr, &size);
+
+ if (res != noErr) {
+ printUnableToReadWarning(logName, objectID, address,
+ "AudioObjectGetPropertyDataSize failed, Err:", res);
+ } else if (size / sizeof(T) < minDataSize) {
+ printUnableToReadWarning(logName, objectID, address, "Data size is too small:", size, "VS",
+ minDataSize * sizeof(T), "bytes");
+ } else {
+ std::vector<T> data(size / sizeof(T));
+ if (getAudioData(objectID, address, data.data(), data.size() * sizeof(T), logName))
+ return { std::move(data) };
+ }
+
+ return {};
+}
+
+template<typename T>
+std::optional<T> getAudioObject(AudioObjectID objectID, const AudioObjectPropertyAddress &address,
+ const char *logName)
+{
+ static_assert(std::is_trivial_v<T>, "A trivial type is expected");
+
+ T object{};
+ if (getAudioData(objectID, address, &object, sizeof(T), logName))
+ return { object };
+
+ return {};
+}
+
+QT_END_NAMESPACE
+
+#endif // QMACOSAUDIODATAUTILS_P_H
diff --git a/src/multimedia/doc/QtMultimediaDoc b/src/multimedia/doc/QtMultimediaDoc
index 262d39738..e57c3595b 100644
--- a/src/multimedia/doc/QtMultimediaDoc
+++ b/src/multimedia/doc/QtMultimediaDoc
@@ -1,9 +1,2 @@
#include <QtMultimedia/QtMultimedia>
#include <QtMultimediaWidgets/QtMultimediaWidgets>
-
-#include "../audio/qaudiosystem_p.h"
-#include "../platform/qplatformaudiodecoder_p.h"
-#include "../platform/qplatformcamera_p.h"
-#include "../platform/qplatformmediaencoder_p.h"
-#include "../platform/qplatformimagecapture_p.h"
-#include "../platform/qplatformvideosink_p.h"
diff --git a/src/multimedia/doc/qtmultimedia.qdocconf b/src/multimedia/doc/qtmultimedia.qdocconf
index 9032c1bb7..5a16bddec 100644
--- a/src/multimedia/doc/qtmultimedia.qdocconf
+++ b/src/multimedia/doc/qtmultimedia.qdocconf
@@ -1,5 +1,6 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
include($QT_INSTALL_DOCS/config/exampleurl-qtmultimedia.qdocconf)
+include(../../../examples/multimedia/video/mediaplayer/doc/qmlmediaplayer.qdocconf)
project = QtMultimedia
description = Qt Multimedia Documentation
@@ -8,6 +9,8 @@ version = $QT_VERSION
moduleheader = QtMultimediaDoc
includepaths += .
+examplesinstallpath = multimedia
+
# The following parameters are for creating a qhp file, the qhelpgenerator
# program can convert the qhp file into a qch file which can be opened in
# Qt Assistant and/or Qt Creator.
@@ -36,7 +39,7 @@ qhp.QtMultimedia.subprojects.widgetclasses.sortPages = true
qhp.QtMultimedia.subprojects.qmltypes.title = QML Types
qhp.QtMultimedia.subprojects.qmltypes.indexTitle = Qt Multimedia QML Types
-qhp.QtMultimedia.subprojects.qmltypes.selectors = qmlclass
+qhp.QtMultimedia.subprojects.qmltypes.selectors = qmltype
qhp.QtMultimedia.subprojects.qmltypes.sortPages = true
qhp.QtMultimedia.subprojects.examples.title = Examples
@@ -44,23 +47,37 @@ qhp.QtMultimedia.subprojects.examples.indexTitle = Qt Multimedia Examples
qhp.QtMultimedia.subprojects.examples.selectors = doc:example
qhp.QtMultimedia.subprojects.examples.sortPages = true
-exampledirs += ../../../examples \
+exampledirs += ../../../examples/multimedia \
+ ../../../examples/multimediawidgets \
snippets \
../../multimediawidgets/doc/snippets
-manifestmeta.highlighted.names = "QtMultimedia/QML Video Shader Effects Example" \
- "QtMultimedia/Media Player Example"
-
-headerdirs += ../..
+headerdirs += .. \
+ ../../multimediawidgets \
+ ../../multimediaquick
imagedirs += src/images \
-sourcedirs += ../..
+sourcedirs += .. \
+ ../../multimediawidgets \
+ ../../multimediaquick
-excludedirs += ../../gsttools
+depends += qtcore qtdoc qtgui qtquick qtqml qtwidgets qtnetwork qmake qtcmake qtquickcontrols qtspatialaudio
-depends += qtcore qtdoc qtgui qtquick qtqml qtwidgets qtnetwork qmake qtcmake
+# Ignore \since commands for versions earlier than 6.3
+ignoresince = 6.3
navigation.landingpage = "Qt Multimedia"
navigation.cppclassespage = "Qt Multimedia C++ Classes"
navigation.qmltypespage = "Qt Multimedia QML Types"
+
+# Highlighted examples in Graphics & Multimedia category
+manifestmeta.highlighted.names = \
+ "QtMultimedia/Screen Capture Example" \
+ "QtMultimedia/QML Video Recorder"
+
+# Highlighted examples in Mobile category
+manifestmeta.highlighted.names += "QtMultimedia/QML Camera Application"
+
+# Fail the documentation build if there are more warnings than the limit
+warninglimit = 0
diff --git a/src/multimedia/doc/snippets/CMakeLists.txt b/src/multimedia/doc/snippets/CMakeLists.txt
index 4df8fd9b1..c3937477b 100644
--- a/src/multimedia/doc/snippets/CMakeLists.txt
+++ b/src/multimedia/doc/snippets/CMakeLists.txt
@@ -1,4 +1,7 @@
-cmake_minimum_required(VERSION 3.1.0)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
project(multimedia_cppsnippets)
@@ -7,6 +10,6 @@ add_executable(mytarget
)
# ![0]
-find_package(Qt6 COMPONENTS Multimedia REQUIRED)
+find_package(Qt6 REQUIRED COMPONENTS Multimedia)
target_link_libraries(mytarget PRIVATE Qt6::Multimedia)
# ![0]
diff --git a/src/multimedia/doc/snippets/doc_src_qtmultimedia.cpp b/src/multimedia/doc/snippets/doc_src_qtmultimedia.cpp
deleted file mode 100644
index a56283474..000000000
--- a/src/multimedia/doc/snippets/doc_src_qtmultimedia.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [0]
-#include <QtMultimedia>
-//! [0]
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp b/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
index 24045adab..565f7b29b 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
/* Audio related snippets */
#include <QFile>
@@ -87,9 +51,9 @@ void AudioInputExample::setup()
}
audio = new QAudioSource(format, this);
- connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
+ connect(audio, &QAudioSource::stateChanged, this, &AudioInputExample::handleStateChanged);
- QTimer::singleShot(3000, this, SLOT(stopRecording()));
+ QTimer::singleShot(3000, this, &AudioInputExample::stopRecording);
audio->start(&destinationFile);
// Records audio for 3000ms
}
@@ -135,6 +99,7 @@ public:
public Q_SLOTS:
void handleStateChanged(QAudio::State newState);
+ void stopAudioOutput();
private:
//! [Audio output class members]
@@ -156,27 +121,34 @@ void AudioOutputExample::setup()
format.setChannelCount(1);
format.setSampleFormat(QAudioFormat::UInt8);
- QAudioDevice info(QAudioDevice::defaultOutputDevice());
+ QAudioDevice info(QMediaDevices::defaultAudioOutput());
if (!info.isFormatSupported(format)) {
qWarning() << "Raw audio format not supported by backend, cannot play audio.";
return;
}
audio = new QAudioSink(format, this);
- connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
+ connect(audio, QAudioSink::stateChanged, this, &AudioInputExample::handleStateChanged);
audio->start(&sourceFile);
}
//! [Audio output setup]
+//! [Audio output stop]
+void AudioOutputExample::stopAudioOutput()
+{
+ audio->stop();
+ sourceFile.close();
+ delete audio;
+}
+//! [Audio output stop]
+
//! [Audio output state changed]
void AudioOutputExample::handleStateChanged(QAudio::State newState)
{
switch (newState) {
case QAudio::IdleState:
// Finished playing (no more data)
- audio->stop();
- sourceFile.close();
- delete audio;
+ AudioOutputExample::stopAudioOutput();
break;
case QAudio::StoppedState:
@@ -203,9 +175,9 @@ void AudioDeviceInfo()
//! [Setting audio format]
//! [Dumping audio formats]
- const auto deviceInfos = QMediaDevices::availableDevices(QAudioDevice::Output);
- for (const QAudioDevice &deviceInfo : deviceInfos)
- qDebug() << "Device: " << deviceInfo.description();
+ const auto devices = QMediaDevices::audioOutputs();
+ for (const QAudioDevice &device : devices)
+ qDebug() << "Device: " << device.description();
//! [Dumping audio formats]
}
@@ -231,7 +203,7 @@ void AudioDecodingExample::decode()
decoder->setAudioFormat(desiredFormat);
decoder->setSource("level1.mp3");
- connect(decoder, SIGNAL(bufferReady()), this, SLOT(readBuffer()));
+ connect(decoder, &QAudioDecoder::bufferReady, this, &AudioDecodingExample::readBuffer);
decoder->start();
// Now wait for bufferReady() signal and call decoder->read()
@@ -245,9 +217,9 @@ void applyVolume(int volumeSliderValue)
{
// volumeSliderValue is in the range [0..100]
- qreal linearVolume = QAudio::convertVolume(volumeSliderValue / qreal(100.0),
- QAudio::LogarithmicVolumeScale,
- QAudio::LinearVolumeScale);
+ qreal linearVolume = QtAudio::convertVolume(volumeSliderValue / qreal(100.0),
+ QtAudio::LogarithmicVolumeScale,
+ QtAudio::LinearVolumeScale);
player.setVolume(qRound(linearVolume * 100));
}
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp b/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp
index 0abc4062f..053af088f 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
/* Camera snippets */
@@ -55,6 +19,7 @@
QCamera *camera = 0;
QMediaRecorder *recorder = 0;
QImageCapture *imageCapture = 0;
+QVideoWidget *viewfinder = 0;
//! [Camera overview check]
bool checkCameraAvailability()
@@ -72,11 +37,11 @@ void overview_viewfinder()
QMediaCaptureSession captureSession;
camera = new QCamera;
captureSession.setCamera(camera);
- QVideoWidget *preview = new QVideoWidget;
- camera->setVideoOutput(preview);
- preview->show();
+ viewfinder = new QVideoWidget;
+ captureSession.setVideoOutput(viewfinder);
+ viewfinder->show();
- camera->start(); // to start the viewfinder
+ camera->start(); // to start the camera
//! [Camera overview viewfinder]
}
@@ -96,7 +61,7 @@ void overview_surface()
camera = new QCamera;
captureSession.setCamera(camera);
mySink = new QVideoSink;
- camera->setVideoOutput(mySink);
+ captureSession.setVideoOutput(mySink);
camera->start();
// MyVideoSink::setVideoFrame(..) will be called with video frames
@@ -135,7 +100,7 @@ void overview_still()
QMediaCaptureSession captureSession;
camera = new QCamera;
captureSession.setCamera(camera);
- imageCapture = new QImageCapture(camera);
+ imageCapture = new QImageCapture;
captureSession.setImageCapture(imageCapture);
camera->start(); // Viewfinder frames start flowing
@@ -152,7 +117,7 @@ void overview_movie()
camera = new QCamera;
captureSession.setCamera(camera);
recorder = new QMediaRecorder(camera);
- captureSession.setMediaEncoder(recorder);
+ captureSession.setRecorder(recorder);
camera->start();
@@ -200,8 +165,6 @@ void camera_info()
qDebug() << "The camera is on the front face of the hardware system.";
else if (cameraDevice.position() == QCameraDevice::BackFace)
qDebug() << "The camera is on the back face of the hardware system.";
-
- qDebug() << "The camera sensor orientation is " << cameraDevice.orientation() << " degrees.";
//! [Camera info]
}
@@ -212,9 +175,9 @@ void camera_blah()
camera = new QCamera;
captureSession.setCamera(camera);
- QVideoWidget *preview = new QVideoWidget();
- preview->show();
- captureSession.setVideoOutput(preview);
+ viewfinder = new QVideoWidget();
+ viewfinder->show();
+ captureSession.setVideoOutput(viewfinder);
imageCapture = new QImageCapture(camera);
captureSession.setImageCapture(imageCapture);
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/devices.cpp b/src/multimedia/doc/snippets/multimedia-snippets/devices.cpp
new file mode 100644
index 000000000..652400364
--- /dev/null
+++ b/src/multimedia/doc/snippets/multimedia-snippets/devices.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QAudioDevice>
+#include <QCameraDevice>
+#include <QMediaDevices>
+#include <QString>
+#include <QTextStream>
+
+int main(int argc, char *argv[])
+{
+ Q_UNUSED(argc);
+ Q_UNUSED(argv);
+
+ QTextStream out(stdout);
+
+ //! [Media Audio Input Device Enumeration]
+ const QList<QAudioDevice> audioDevices = QMediaDevices::audioInputs();
+ for (const QAudioDevice &device : audioDevices)
+ {
+ out << "ID: " << device.id() << Qt::endl;
+ out << "Description: " << device.description() << Qt::endl;
+ out << "Is default: " << (device.isDefault() ? "Yes" : "No") << Qt::endl;
+ }
+ //! [Media Audio Input Device Enumeration]
+
+ //! [Media Video Input Device Enumeration]
+ const QList<QCameraDevice> videoDevices = QMediaDevices::videoInputs();
+ for (const QCameraDevice &device : videoDevices)
+ {
+ out << "ID: " << device.id() << Qt::endl;
+ out << "Description: " << device.description() << Qt::endl;
+ out << "Is default: " << (device.isDefault() ? "Yes" : "No") << Qt::endl;
+ }
+ //! [Media Video Input Device Enumeration]
+
+ return 0;
+}
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/media.cpp b/src/multimedia/doc/snippets/multimedia-snippets/media.cpp
index 770bdec44..a4b9a9fb5 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/media.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/media.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
/* Media related snippets */
#include <QFile>
@@ -68,6 +32,7 @@ private:
QVideoWidget *videoWidget;
QWidget *widget;
QMediaPlayer *player;
+ QAudioOutput *audioOutput;
QMediaPlaylist *playlist;
QMediaContent video;
QMediaRecorder *recorder;
@@ -109,17 +74,21 @@ void MediaExample::MediaPlayer()
{
//! [Player]
player = new QMediaPlayer;
- connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
+ audioOutput = new QAudioOutput;
+ player->setAudioOutput(audioOutput);
+ connect(player, &QMediaPlayer::positionChanged, this, &MediaExample::positionChanged);
player->setSource(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
- player->setVolume(50);
+ audioOutput->setVolume(50);
player->play();
//! [Player]
//! [Local playback]
player = new QMediaPlayer;
+ audioOutput = new QAudioOutput;
+ player->setAudioOutput(audioOutput);
// ...
player->setSource(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
- player->setVolume(50);
+ audioOutput->setVolume(50);
player->play();
//! [Local playback]
}
@@ -131,7 +100,7 @@ void MediaExample::MediaRecorder()
QAudioInput audioInput;
session.setAudioInput(&input);
QMediaRecorder recorder;
- session.setMediaRecorder(&recorder);
+ session.setRecorder(&recorder);
recorder.setQuality(QMediaRecorder::HighQuality);
recorder.setOutputLocation(QUrl::fromLocalFile("test.mp3"));
recorder.record();
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml b/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml
index 8484a5f28..0c673cc42 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml
+++ b/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick.Window
@@ -45,7 +9,6 @@ import QtMultimedia
Item {
MediaPlayer {
id: mediaplayer
- autoPlay: true
source: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
videoOutput: [v1, v2]
audioOutput: AudioOutput {
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp b/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp
index 246589767..644dcb228 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp
@@ -1,52 +1,5 @@
- /****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "qpushbutton.h"
#include "qsoundeffect.h"
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml b/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml
index 842b3138c..eeac9c28e 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml
+++ b/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtMultimedia
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml b/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml
index 501443d25..e91e54e3c 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml
+++ b/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtMultimedia
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/video.cpp b/src/multimedia/doc/snippets/multimedia-snippets/video.cpp
index ac920d858..8cc3b41b3 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/video.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/video.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
/* Video related snippets */
#include "qvideorenderercontrol.h"
@@ -43,7 +7,6 @@
#include "qvideosink.h"
#include "qvideowindowcontrol.h"
#include "qgraphicsvideoitem.h"
-#include "qmediaplaylist.h"
#include "qvideoframeformat.h"
#include <QFormLayout>
@@ -90,7 +53,6 @@ public:
private:
// Common naming
- QMediaPlaylist *playlist;
QVideoWidget *videoWidget;
QWidget *widget;
QFormLayout *layout;
@@ -104,16 +66,12 @@ void VideoExample::VideoWidget()
{
//! [Video widget]
player = new QMediaPlayer;
-
- playlist = new QMediaPlaylist(player);
- playlist->addMedia(QUrl("http://example.com/myclip1.mp4"));
- playlist->addMedia(QUrl("http://example.com/myclip2.mp4"));
+ player->setSource(QUrl("http://example.com/myclip1.mp4"));
videoWidget = new QVideoWidget;
player->setVideoOutput(videoWidget);
videoWidget->show();
- playlist->setCurrentIndex(1);
player->play();
//! [Video widget]
@@ -154,7 +112,7 @@ void VideoExample::VideoGraphicsItem()
graphicsView->scene()->addItem(item);
graphicsView->show();
- player->setMedia(QUrl("http://example.com/myclip4.ogv"));
+ player->setSource(QUrl("http://example.com/myclip4.ogv"));
player->play();
//! [Video graphics item]
}
diff --git a/src/multimedia/doc/src/audiooverview.qdoc b/src/multimedia/doc/src/audiooverview.qdoc
index d4c3116ba..40a6318a6 100644
--- a/src/multimedia/doc/src/audiooverview.qdoc
+++ b/src/multimedia/doc/src/audiooverview.qdoc
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt for Multimedia module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page audiooverview.html
\title Audio Overview
\inlineimage sound-wave-small.jpg
\brief Playback, recording and processing of Audio.
+\ingroup explanations-graphicsandmultimedia
\section1 Audio Features
@@ -51,28 +16,59 @@ high level approaches to: audio input, output and processing.
\section1 Audio Implementation Details
\section2 Playing Compressed Audio
+
For playing media or audio files that are not simple, uncompressed audio, you
can use the QMediaPlayer C++ class, or the \l{MediaPlayer} QML type.
The QMediaPlayer class and associated QML types are also capable of playing
-\l{multimedia-playing-video}{video}, if required. The compressed audio formats
-supported depends on:
-\list
- \li The operating system environment.
- \li Any decoder plugins the user may have installed.
-\endlist
+\l{multimedia-playing-video}{video}, if required.
+
+See \l{Supported Media Formats} for more detail.
+
+The media player needs to be connected to a QAudioOutput object (or the QML AudioOutput
+element) to play back audio.
Here is how you play a local file using C++:
\snippet multimedia-snippets/media.cpp Local playback
+The same functionality in QML:
+
+\qml
+MediaPlayer {
+ audioOutput: AudioOutput {}
+ source: "file:///path/to/my/music.mp3"
+ Component.onCompleted: { play() }
+}
+\endqml
+
\section2 Recording Audio to a File
-For recording audio to a file, the QMediaRecorder class allows you
-to compress audio data from an input device and record it.
+
+To record audio to a file, you need to create a capture session and connect to it an audio
+input and a recorder. These elements are implemented with the QMediaCaptureSession,
+QAudioInput, and QMediaRecorder classes. The default constructed QAudioInput selects the
+system default audio input. The recorder controls the recording process with a simple record()
+and stop() functions. Additionally, you can use it to select the output location, audio
+encoder, or file container format.
+
+A session recording audio from the default microphone would look as follows in C++:
\snippet multimedia-snippets/media.cpp Media recorder
-QMediaCaptureSession provides support for more complex use cases involving the
-capturing and recording of audio.
+In QML, the same can be achieved by:
+
+\qml
+CaptureSession {
+ audioInput: AudioInput {}
+ mediaRecorder: MediaRecorder {
+ id: recorder
+ outputLocation: "file:///path/to/test.mp3"
+ }
+ Component.onCompleted: { recorder.record() }
+}
+\endqml
+
+QMediaCaptureSession also provides support for more complex use cases such as image
+capturing or video recording.
\section2 Low Latency Sound Effects
@@ -92,7 +88,7 @@ You can adjust the:
\target raw access
\section2 Low Level Audio Playback and Recording
-Qt Multimedia offers classes for raw access to audio input and output
+The C++ API of Qt Multimedia offers classes for raw access to audio input and output
facilities, allowing applications to receive raw data from devices like
microphones, and to write raw data to speakers or other devices. Generally
these classes do not do any audio decoding, or other processing, but they
@@ -125,13 +121,10 @@ Here's an example of decoding a local file:
\snippet multimedia-snippets/audio.cpp Local audio decoding
-\section1 Examples
-
-There are both C++ and QML examples available.
+\section2 Spatial Audio
-\section2 C++ Examples
-
-\annotatedlist audio_examples
+The \l {Qt Spatial Audio} module provides an API for implementation sound
+fields in 3D space.
\section1 Reference Documentation
@@ -143,5 +136,8 @@ There are both C++ and QML examples available.
\annotatedlist multimedia_audio_qml
+\section2 Examples
+
+\annotatedlist audio_examples
*/
diff --git a/src/multimedia/doc/src/cameraoverview.qdoc b/src/multimedia/doc/src/cameraoverview.qdoc
index 87d513eed..b93954d6d 100644
--- a/src/multimedia/doc/src/cameraoverview.qdoc
+++ b/src/multimedia/doc/src/cameraoverview.qdoc
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt for Multimedia module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page cameraoverview.html
\title Camera Overview
\brief Camera viewfinder, still image capture, and video recording.
+\ingroup explanations-graphicsandmultimedia
The Qt Multimedia API provides a number of camera related classes, so you
can access images and videos from mobile device cameras or web cameras.
@@ -206,21 +171,18 @@ is useful for QGraphicsView.
For advanced usage (like processing preview frames as they come, which enables
detection of objects or patterns), you can also use your own QVideoSink and set
-that as the videoOutput for the QCamera object. In this case, you will need to
-render the viewfinder image yourself by processing the data received from the
+that as the videoOutput for the QMediaCaptureSession. In this case, you will need to
+render the preview image yourself by processing the data received from the
videoFrameChanged() signal.
\snippet multimedia-snippets/camera.cpp Camera overview surface
-On mobile devices, the preview image might not always be in the orientation you
-would expect. The camera sensors on these devices are often mounted in landscape
-while the natural orientation of the screen is portrait. This results in the
-image appearing sideways or inverted depending on the device orientation. In
-order to reflect on screen what the user actually sees, you should make sure
-the viewfinder frames are always rotated to the correct orientation, taking into
-account the camera sensor orientation and the current display orientation.
-
- \snippet multimedia-snippets/camera.cpp Camera overview viewfinder orientation
+On mobile devices, the preview image is by default oriented in the same way as the device.
+Thus, as the user rotates the device, the preview image will switch between portrait and
+landscape mode. Once you start recording, the orientation will be locked. To avoid a poor
+user experience, you should also lock the orientation of the applications user interface
+while recording. This can be achieved using the
+\l{QWindow::contentOrientation}{contentOrientation} property of QWindow.
\section2 Still Images
@@ -264,11 +226,12 @@ For camera hardware that supports it, \l QCamera::FocusModeAutoNear allows
imaging of things that are close to the sensor. This is useful in applications
like bar-code recognition, or business card scanning.
-In addition to focus, QCameraFocus allows you to control any available zoom
-functionality using \l QCamera::setZoomFactor() or \l QCamera::zoomTo(). The
+In addition to focus, QCamera allows you to control any available zoom
+functionality using \l{QCamera::setZoomFactor}{setZoomFactor()} or
+\l{QCamera::zoomTo}{zoomTo()}. The
available zoom range might be limited or entirely fixed to unity (1:1). The
-allowed range can be checked with \l QCamera::minimumZoomFactor() and
-\l QCamera::minimumZoomFactor().
+allowed range can be checked with \l{QCamera::minimumZoomFactor}{minimumZoomFactor()}
+and \l{QCamera::maximumZoomFactor}{maximumZoomFactor()}.
\section3 Exposure, Shutter Speed and Flash
diff --git a/src/multimedia/doc/src/examples/video-qml-paint-rate.qdocinc b/src/multimedia/doc/src/examples/video-qml-paint-rate.qdocinc
index f531e613a..34f7df319 100644
--- a/src/multimedia/doc/src/examples/video-qml-paint-rate.qdocinc
+++ b/src/multimedia/doc/src/examples/video-qml-paint-rate.qdocinc
@@ -2,7 +2,7 @@ The QML painting rate is calculated by the FrequencyMonitor class, which
turns a stream of events (received via the notify() slot), into an
instantaneous and an averaged frequency:
-\quotefromfile multimedia/video/qmlvideo/frequencymonitor.h
+\quotefromfile video/qmlvideo/frequencymonitor.h
\skipto class FrequencyMonitor : public QObject
\printuntil Q_OBJECT
\skipto Q_PROPERTY(qreal instantaneousFrequency
@@ -19,13 +19,13 @@ instantaneous and an averaged frequency:
The FrequencyMonitor class is exposed to QML like this
-\quotefromfile multimedia/video/qmlvideo/frequencymonitordeclarative.cpp
+\quotefromfile video/qmlvideo/frequencymonitordeclarative.cpp
\skipto FrequencyMonitor::qmlRegisterType
\printuntil }
and its data is displayed by defining a QML item called FrequencyItem, like this:
-\quotefromfile multimedia/video/qmlvideo/qml/frequencymonitor/FrequencyItem.qml
+\quotefromfile video/qmlvideo/frequencymonitor/FrequencyItem.qml
\skipto import FrequencyMonitor
\printuntil id: root
\dots
diff --git a/src/multimedia/doc/src/images/camera_correctionAngle_90.png b/src/multimedia/doc/src/images/camera_correctionAngle_90.png
new file mode 100644
index 000000000..7a3c169a5
--- /dev/null
+++ b/src/multimedia/doc/src/images/camera_correctionAngle_90.png
Binary files differ
diff --git a/src/multimedia/doc/src/multimedia-overview.qdoc b/src/multimedia/doc/src/multimedia-overview.qdoc
index b7e6c92dc..6da54a7e2 100644
--- a/src/multimedia/doc/src/multimedia-overview.qdoc
+++ b/src/multimedia/doc/src/multimedia-overview.qdoc
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt for Multimedia module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
@@ -43,6 +7,7 @@
\page multimediaoverview.html
\title Multimedia Overview
\brief A set of APIs for working with audio, video and camera devices.
+\ingroup explanations-graphicsandmultimedia
Multimedia support in Qt is provided by the \l{Qt Multimedia} module. The Qt
Multimedia module provides a rich feature set that enables you to easily take
@@ -56,6 +21,7 @@ Here are some things you can do with the Qt Multimedia APIs:
\list
\li Access raw audio devices for input and output.
\li Play low latency sound effects.
+\li Play 3D spatial audio.
\li Play media files in playlists (such as compressed audio or video files).
\li Record audio and compress it.
\li Use a camera, including viewfinder, image capture, and movie recording
@@ -72,6 +38,7 @@ can also take a look at some \l{Multimedia Recipes}{recipes}.
\li \l {Audio Overview}
\li \l {Video Overview}
\li \l {Camera Overview}
+\li \l {Spatial Audio Overview} (Technology Preview)
\endlist
\section1 Multimedia Recipes
@@ -87,20 +54,24 @@ For some quick recipes, see this table:
\row
\li Playing a sound effect
\li
- \li
+ \li \l{SoundEffect}
\li QSoundEffect
\row
- \li Playing low latency audio
- \li \l{Audio Source Example}{audiosource},
- \l{Spectrum Example}{spectrum}
- \li
- \li QAudioSink
+ \li Playing 3D sound
+ \li \l{Spatial Audio Panning Example}{audiopanning}
+ \li SpatialSound, AudioEngine
+ \li QSpatialSound, QAudioEngine
\row
\li Playing encoded audio (MP3, AAC etc)
\li \l{Media Player Example}{player}
- \li \l Audio, \l {MediaPlayer}
+ \li \l{MediaPlayer}
\li QMediaPlayer
\row
+ \li Playing raw audio data with low latency
+ \li \l{Audio Output Example}{audiooutput}
+ \li
+ \li QAudioSink
+ \row
\li Accessing raw audio input data
\li \l{Spectrum Example}{spectrum},
\l{Audio Source Example}{audiosource}
@@ -109,48 +80,37 @@ For some quick recipes, see this table:
\row
\li Recording encoded audio data
\li \l{Audio Recorder Example}{audiorecorder}
- \li
- \li QMediaCaptureSession
+ \li \l{CaptureSession}, \l{AudioInput}, \l{MediaRecorder}
+ \li QMediaCaptureSession, QAudioInput, QMediaRecorder
\row
- \li Discovering raw audio devices
+ \li Discovering audio and video devices
\li \l{Audio Devices Example}{audiodevices}
- \li
- \li QAudioDevice
+ \li \l{MediaDevices}, \l{audioDevice}, \l{cameraDevice}
+ \li QMediaDevices, QAudioDevice, QCameraDevice
\row
\li Video Playback
\li \l{Media Player Example}{player},
- \l{QML Video Example}{qmlvideo},
- \l{QML Video Shader Effects Example}{qmlvideofx}
+ \l{QML Media Player Example}{mediaplayer}
\li \l MediaPlayer, \l VideoOutput, \l Video
\li QMediaPlayer, QVideoWidget, QGraphicsVideoItem
\row
- \li Video Processing
- \li \l {QML Video Example}{qmlvideofx}
- \li \l {MediaPlayer}, \l VideoOutput
- \li QMediaPlayer, QVideoFrame
- \row
- \li Accessing camera viewfinder
+ \li Capturing audio and video
\li \l {Camera Example}{camera},
- \l {QML Camera Example}{declarative-camera}
- \li \l Camera, \l VideoOutput
- \li QCamera, QVideoWidget, QGraphicsVideoItem
- \row
- \li Viewfinder processing
- \li
- \li \l Camera, \l VideoOutput
- \li QCamera, QVideoFrame
+ \l {QML Video Recorder}{recorder}
+ \li \l CaptureSession, \l Camera, \l AudioInput \l VideoOutput
+ \li QMediaCaptureSession, QCamera, QAudioInput, QVideoWidget
\row
\li Capturing photos
\li \l {Camera Example}{camera},
- \l {QML Camera Example}{declarative-camera}
- \li \l Camera
- \li QCamera, QImageCapture
+ \l {QML Video Recorder}{recorder}
+ \li \l CaptureSession, \l Camera, \l ImageCapture
+ \li QMediaCaptureSession, QCamera, QImageCapture
\row
\li Capturing movies
\li \l {Camera Example}{camera},
- \l {QML Camera Example}{declarative-camera}
- \li \l Camera
- \li QCamera, QMediaRecorder
+ \l {QML Video Recorder}{recorder}
+ \li \l CaptureSession, \l Camera, \l MediaRecorder
+ \li QMediaCaptureSession, QCamera, QMediaRecorder
\endtable
\section1 Limitations
@@ -158,6 +118,14 @@ For some quick recipes, see this table:
The Qt Multimedia APIs build upon the multimedia framework of the underlying
platform. This can mean that support for various codecs, or containers will vary
between machines. This support depends on what the end user has installed.
+See \l{Supported Media Formats} for more detail.
+
+\note Qt Multimedia APIs depend on functionality provided by QCoreApplication,
+and multimedia objects created using the Qt Multimedia APIs can only be used
+during the lifetime of this application object. It is therefore important to
+create a QCoreApplication, QGuiApplication, or QApplication before accessing
+any of the Qt Multimedia APIs. If the application object is recreated, make
+sure that any Qt Multimedia objects are also recreated.
\section1 Changes from Previous Versions
@@ -167,14 +135,8 @@ you might need to change when porting code to Qt 6.
\section1 Reference Documentation
-\section2 QML Types
-The QML types are accessed by using:
-\code
-import QtMultimedia
-\endcode
-
-\section2 Multimedia Classes
-
-\annotatedlist multimedia
-
+\list
+ \li \l{Qt Multimedia C++ Classes}{C++ Classes}
+ \li \l{Qt Multimedia QML Types}{QML Types}
+\endlist
*/
diff --git a/src/multimedia/doc/src/platform-notes-apple.qdoc b/src/multimedia/doc/src/platform-notes-apple.qdoc
index bd8636ee4..a9bca07c2 100644
--- a/src/multimedia/doc/src/platform-notes-apple.qdoc
+++ b/src/multimedia/doc/src/platform-notes-apple.qdoc
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the FOO module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtmultimedia-apple.html
diff --git a/src/multimedia/doc/src/platform-notes-wasm.qdoc b/src/multimedia/doc/src/platform-notes-wasm.qdoc
new file mode 100644
index 000000000..d1a942c9f
--- /dev/null
+++ b/src/multimedia/doc/src/platform-notes-wasm.qdoc
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtmultimedia-wasm.html
+\title Qt Multimedia on WebAssembly
+\brief Platform notes for WebAssembly
+
+This page covers the availability of Qt Multimedia features on WebAssembly.
+
+\section1 Limitations
+
+Due to the asynchronous nature of javascript, some features such as getting the list of
+QMediaDevices, will not be readily available and may take some time to request permissions and
+gather the list of devices. The audioInputsChanged, audioOutputsChanged and
+videoInputChanged signals from QMediaDevices class will be emitted when they are available.
+
+Playing video currently works by using a html 2d context, so all operations are on the CPU.
+
+Performance is acceptable, although there is a copy on every frame, so it may be
+less performant than desktop platforms when playing hi-def video.
+
+Using and selecting different Codecs/video formats have not yet been tested, but whatever
+video formats the browser supports will most likely work.
+
+Playing data from a stream (using \c {setSourceDevice(QIODevice*)}), instead
+of fetching a URL, isn't supported.
+
+Some advanced features may or may not work at this time.
+
+Files can be served from the/any web server, respective
+of \l{https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS}{CORS}. Because of
+the limited size of local file storage, playing local files is discouraged.
+
+ */
diff --git a/src/multimedia/doc/src/qm-external-pages.qdoc b/src/multimedia/doc/src/qm-external-pages.qdoc
index 97964b059..8a28780c0 100644
--- a/src/multimedia/doc/src/qm-external-pages.qdoc
+++ b/src/multimedia/doc/src/qm-external-pages.qdoc
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the FOO module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\externalpage https://gstreamer.freedesktop.org
@@ -228,7 +192,7 @@
/*!
\externalpage https://en.wikipedia.org/wiki/Motion_JPEG
- \title Motion JPEG
+ \title MotionJPEG
*/
/*!
@@ -240,3 +204,29 @@
\externalpage https://en.wikipedia.org/wiki/Theora
\title Theora
*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Windows_Media_Player
+ \title Windows Media Player
+*/
+
+
+/*!
+ \externalpage https://support.microsoft.com/en-us/topic/file-types-supported-by-windows-media-player-32d9998e-dc8f-af54-7ba1-e996f74375d9
+ \title Windows Media Player documentation
+*/
+
+/*!
+ \externalpage https://www.codecguide.com/guides.htm
+ \title codec guide
+*/
+
+/*!
+ \externalpage https://developer.android.com/guide/topics/media/media-formats
+ \title Android supported media formats
+*/
+
+/*!
+ \externalpage https://gstreamer.freedesktop.org/
+ \title GStreamer
+*/
diff --git a/src/multimedia/doc/src/qt6-changes.qdoc b/src/multimedia/doc/src/qt6-changes.qdoc
index 1a9a9530b..ad5ebab74 100644
--- a/src/multimedia/doc/src/qt6-changes.qdoc
+++ b/src/multimedia/doc/src/qt6-changes.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtmultimedia-changes-qt6.html
@@ -49,10 +25,11 @@ Qt 5 can be ported with limited effort.
There are a number of new features in Qt Multimedia:
\list
\li QMediaCaptureSession class is the central object for media capture.
- \li QMediaRecorder class is now an abstract class for audio/video
- functionality. It handles encoding of data produced in a capture session.
+ \li QMediaRecorder class is now a class limited to recording audio and video.
+ It handles encoding of data produced in a capture session.
\li Using QMediaFormat and QMediaRecorder, setting up the desired encoding
when recording has changed significantly.
+ \li You can now also monitor the audio recorded by a capture session.
\li Support for selection of audio, video and subtitle tracks when playing
back media files has been added.
\li QAudioDecoder is now supported on all platforms.
@@ -92,8 +69,7 @@ There are a number of new features in Qt Multimedia:
resolution and frame rate the camera should be using.
\row
\li QMediaContent
- \li The class has been removed. Use QMediaPlayList for playlists and
- QUrl for individual media files instead.
+ \li The class has been removed. Use QUrl for individual media files instead.
\row
\li QSound
\li Use QSoundEffect instead.
@@ -120,7 +96,7 @@ There are a number of new features in Qt Multimedia:
\section1 Changed features
-A number of classes previously offered in Qt Multimedia or Qt Multimedia Kit have
+A number of classes previously offered in Qt Multimedia have
changed in ways that may affect previously written code. The following table
highlights these changes.
@@ -155,6 +131,15 @@ highlights these changes.
\row
\li QCameraImageCapture renamed QImageCapture
\li None
+ \row
+ \li Audio inputs and outputs
+ \li QMediaPlayer and QMediaCaptureSession (and the corresponding QML types MediaPlayer and
+ CaptureSession) are not connected to any audio devices by default. Explicitly connect them
+ to a QAudioInput/AudioInput or QAudioOutput/AudioOutput to capture or play back audio.
+ \row
+ \li Capturing video
+ \li A capture session is by default not connected to a Camera. Connect it to a QCamera object
+ (Camera item) to be able to capture video or still images.
\endtable
*/
diff --git a/src/multimedia/doc/src/qtmultimedia-building-from-source.qdoc b/src/multimedia/doc/src/qtmultimedia-building-from-source.qdoc
new file mode 100644
index 000000000..df434c699
--- /dev/null
+++ b/src/multimedia/doc/src/qtmultimedia-building-from-source.qdoc
@@ -0,0 +1,94 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtmultimedia-building-from-source.html
+\title Building Qt Multimedia from sources
+\brief This document describes how to build Qt Multimedia with full
+feature support from source code.
+
+This page describes the process of configuring and building \l{Qt
+Multimedia}. This description assumes familiarity with \l{Building Qt
+Sources} which specifies build requirements for your platform, as well
+as an overview of \l{Qt Configure Options}. For platform-specific
+considerations related to the Qt Multimedia module, see \l{Platform
+Notes} below.
+
+\section1 Building from source
+
+Building Qt Multimedia with full feature support depends on \l
+{https://ffmpeg.org/}{FFmpeg} headers and libraries on most platforms.
+It is possible to build Qt Multimedia without the Qt Multimedia FFmpeg
+media backend, but this is only recommended when building for platforms
+where the FFmpeg backend is not supported.
+
+FFmpeg developer libraries required to build Qt Multimedia can be built
+from sources or downloaded as binary packages. Qt Multimedia can use
+either static linking or dynamic linking to FFmpeg libraries. We
+recommend using the same major version of FFmpeg that is listed in
+\l{FFmpeg as the default backend}.
+
+To build Qt Multimedia with FFmpeg support, specify the \c{-DFFMPEG_DIR}
+CMake variable on the configure command line when building Qt. Note the
+\c{--} separator which separates ordinary configure arguments from CMake
+parameters.
+
+\badcode
+qt-source/configure -- -DFFMPEG_DIR=<FFMPEG_DIR>
+\endcode
+
+Here, \c{<FFMPEG_DIR>} is the directory containing the FFmpeg include,
+lib, and bin directories. To build Qt Multimedia without FFmpeg, omit
+the \c{<FFMPEG_DIR>} variable or specify the \c{-no-feature-ffmpeg}
+configure option.
+
+If you prefer not to build all Qt's submodules, you can reduce configure
+and build times using the \c{-submodules} configure option. This will
+configure a build that only builds Qt Multimedia and its dependencies.
+
+\badcode
+qt-source/configure -submodules qtmultimedia -- -DFFMPEG_DIR=<FFMPEG_DIR>
+\endcode
+
+If you configure Qt Multimedia against FFmpeg built with shared
+libraries (dynamic linking), the FFmpeg shared libraries must be in the
+module loader's search path to run tests or use examples.
+
+\note Qt Multimedia requires the FFmpeg avformat, avcodec, swresample,
+swscale, and avutil libraries during runtime to be able to use the
+FFmpeg media backend. If one or more of these dynamic libraries are not
+found during application startup, the FFmpeg media backend will fail to
+load, and the system will attempt to load the native backend. Qt
+Multimedia doesn't support as many features on native backends.
+
+If you don't already have these libraries in the \c{path}, specify the
+\c{-DQT_DEPLOY_FFMPEG=ON} configure option. With this option enabled,
+the necessary FFmpeg binaries will be copied to Qt's install directory
+during the build and install steps:
+
+\badcode
+qt-source/configure -submodules qtmultimedia -- -DFFMPEG_DIR=<FFMPEG_DIR> -DQT_DEPLOY_FFMPEG=ON
+\endcode
+
+After configuring Qt Multimedia, carefully review the configure summary
+(found in the config.summary file). You can verify that FFmpeg is found
+under the "Plugin" section. Then follow the regular build and install
+steps described in \l{Building Qt Sources}.
+
+\section1 Platform Notes
+
+\section2 Linux
+
+\list
+ \li When configuring Qt Multimedia with FFmpeg enabled, the
+ pulseaudio development package is required. Without this
+ package, FFmpeg will not be recognized.
+ \li When using a version of FFmpeg that is built with VAAPI support,
+ we recommend building Qt Multimedia with VAAPI support as well
+ to make hardware texture conversion possible. To configure Qt
+ Multimedia with VAAPI support, VAAPI developer libraries must be
+ installed on your system. Review the config.summary file to
+ verify that VAAPI support is enabled under the "Hardware
+ acceleration and features" section.
+\endlist
+*/
diff --git a/src/multimedia/doc/src/qtmultimedia-cpp.qdoc b/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
index 01d5579af..b0c4ea732 100644
--- a/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2015 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtMultimedia
@@ -35,13 +11,11 @@
\brief The \l {Qt Multimedia} module provides audio, video and camera
functionality.
- To enable Qt Multimedia in a project, add this directive into your
- C++ files:
-
- \snippet doc_src_qtmultimedia.cpp 0
-
\include module-use.qdocinc using qt module
- \snippet ../src/multimedia/doc/snippets/CMakeLists.txt 0
+ \code
+ find_package(Qt6 REQUIRED COMPONENTS Multimedia)
+ target_link_libraries(mytarget PRIVATE Qt6::Multimedia)
+ \endcode
*/
/*!
@@ -65,4 +39,7 @@
\section2 Qt Multimedia Widgets Module
\generatelist {classesbymodule QtMultimediaWidgets}
+
+ \section2 Qt Spatial Audio Module
+ \generatelist {classesbymodule QtSpatialAudio}
*/
diff --git a/src/multimedia/doc/src/qtmultimedia-examples.qdoc b/src/multimedia/doc/src/qtmultimedia-examples.qdoc
index d8da05c32..e53eed32f 100644
--- a/src/multimedia/doc/src/qtmultimedia-examples.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-examples.qdoc
@@ -1,37 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2015 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\group multimedia_examples
- \ingroup all-examples
\title Qt Multimedia Examples
\brief Demonstrates the multimedia functionality provided by Qt.
- The \l{Qt Multimedia} module provides low-level audio support on Linux,
- Windows and \macos. It also provides audio plugin API to allow developers
- implement their own audio support for custom devices and platforms.
+ The \l{Qt Multimedia} module provides cross-platform multimedia capabilities
+ for Qt based applications.
+
+ The examples listed below show some typical use cases in various areas, featuring
+ both low-level audio examples, high level audio and video playback
+ as well as capturing and recording of audiovisual content using both C++ and QML.
*/
diff --git a/src/multimedia/doc/src/qtmultimedia-index.qdoc b/src/multimedia/doc/src/qtmultimedia-index.qdoc
index aab7db7ee..67b6688be 100644
--- a/src/multimedia/doc/src/qtmultimedia-index.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-index.qdoc
@@ -1,65 +1,34 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt for Multimedia module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtmultimedia-index.html
\title Qt Multimedia
\image noun_Media_166644.svg "image of multimedia icons, courtesy of misirlou from the Noun Project"
- \brief The Qt Multimedia module provides APIs for audio, video and
- camera-related functionality
+ \brief The Qt Multimedia module provides APIs for playing back and recording
+ audiovisual content
Qt Multimedia is an add-on module that provides a rich set of QML types
- and C++ classes to handle multimedia content. It also provides necessary
- APIs to access the camera functionality.
+ and C++ classes to handle multimedia content. It contains an easy to use
+ API for playing back audio and video files and rendering those on screen, as
+ well as a comprehensive API for recording audio and video from the system's
+ cameras and microphones.
The functionality of this module is divided into the following submodules:
\table
\row
\li \l{Multimedia Overview}{Qt Multimedia}
- \li Provides API for multimedia-specific use cases.
+ \li Provides an API for multimedia-specific use cases.
\row
\li \l{Qt Multimedia Widgets}
- \li Provides the widget-based multimedia API.
+ \li Provides a widget-based multimedia API.
+ \row
+ \li \l{Qt Spatial Audio}
+ \li Provides an API for implementing sound fields in 3D space.
\endtable
- \section1 Getting started
+ \section1 Getting started
If you are porting from Qt 5 to Qt 6 see \l{Changes to Qt Multimedia}.
If you are new to Qt Multimedia, the QML types can be
@@ -70,27 +39,31 @@
import QtMultimedia
\endqml
- If you want to use the C++ classes in your application, include the C++
- definitions using the following directive:
-
- \code
- #include <QtMultimedia>
- #include <QtMultimediaWidgets>
- \endcode
-
- \note If you are using a few classes from this module, we recommend
- including those specific classes only instead of the module.
-
To link against the C++ libraries, add the following to your project's
\c CMakeLists.txt file. Substitute \c my_project with the name of your
project.
\code
- find_package(Qt6 COMPONENTS Multimedia REQUIRED)
- target_link_libraries(my_project PUBLIC Qt::Multimedia)
+ find_package(Qt6 REQUIRED COMPONENTS Multimedia)
+ target_link_libraries(my_project PRIVATE Qt6::Multimedia)
\endcode
- \section1 QML Types
+ See \l {Building Qt Multimedia from sources} for guidance on building
+ Qt Multimedia from sources.
+
+ \section1 Overviews and important topics
+
+ \list
+ \li \l{Changes to Qt Multimedia}{Changes in Qt 6}
+ \li \l{Multimedia Overview}
+ \li \l{Audio Overview}
+ \li \l{Spatial Audio Overview}
+ \li \l{Video Overview}
+ \li \l{Camera Overview}
+ \li \l{Supported Media Formats}
+ \endlist
+
+ \section1 QML types
The following table outlines some important QML types.
@@ -99,94 +72,215 @@
\li Type
\li Description
\row
- \li \l {QtMultimedia::Playlist}{Playlist}
- \li For specifying a list of media to be played.
+ \li \l{MediaPlayer}
+ \li Add audio/video playback functionality to a scene.
+ \row
+ \li \l {QtMultimedia::CaptureSession}{CaptureSession}
+ \li Create a session for capturing audio/video.
\row
\li \l {QtMultimedia::Camera}{Camera}
- \li Access camera viewfinder frames
+ \li Access a camera connected to the system.
+ \row
+ \li \l {QtMultimedia::AudioInput}{AudioInput}
+ \li Access an audio input (microphone) connected to the system.
+ \row
+ \li \l {QtMultimedia::AudioOutput}{AudioOutput}
+ \li Access an audio output (speaker, headphone) connected to the system.
+ \row
+ \li \l {QtMultimedia::VideoOutput}{VideoOutput}
+ \li Display video content.
\row
- \li MediaPlayer
- \li Add audio and/or video playback functionality to a scene.
+ \li \l {QtMultimedia::MediaRecorder}{MediaRecorder}
+ \li Record audio/video from the CaptureSession.
+ \row
+ \li \l {QtMultimedia::ImageCapture}{ImageCapture}
+ \li Capture still images from the Camera.
\row
\li \l {QtMultimedia::Video}{Video}
- \li Add Video playback functionality to a scene. It uses MediaPlayer and
+ \li Add Video playback functionality to a scene. Uses MediaPlayer and
VideoOutput types to provide video playback functionality.
+ \row
+ \li \l {QtMultimedia::ScreenCapture}{ScreenCapture}
+ \li Captures a screen.
+ \row
+ \li \l {QtMultimedia::WindowCapture}{WindowCapture}
+ \li Captures a top-level window.
\endtable
- \section1 C++ Classes
+ \section1 C++ classes
- The following table outlines some important C++ Classes
+ The following table outlines some important C++ classes
\table
\header
\li Class
\li Description
\row
- \li QAudioSink
- \li Sends audio data to an audio output device.
+ \li QMediaPlayer
+ \li Playback media from a source.
+ \row
+ \li QVideoWidget
+ \li Display video from a media player or a capture session.
\row
\li QMediaCaptureSession
- \li Allows capturing of audio and video.
+ \li Capture audio and video.
\row
\li QCamera
- \li Access camera features.
+ \li Access a camera connected to the system
+ \row
+ \li QAudioInput
+ \li Access an audio input (microphone) connected to the system.
+ \row
+ \li QAudioOutput
+ \li Access an audio output (speaker, headphone) connected to the system.
\row
\li QImageCapture
\li Capture still images with a camera.
\row
\li QMediaRecorder
- \li Record media content from a camera source.
- \row
- \li QMediaPlayer
- \li Playback media from a source.
+ \li Record media content from a capture session.
\row
\li QVideoSink
- \li Class for video presentation.
+ \li Access and render individual video frames.
+ \row
+ \li QAudioSink
+ \li Sends raw audio data to an audio output device.
+ \row
+ \li QScreenCapture
+ \li Captures a screen.
+ \row
+ \li QWindowCapture
+ \li Captures a top-level window.
\endtable
+ For playback QMediaPlayer, QAudioOutput and QVideoOutput contain all the required functionality.
+ The other classes are used for capturing audio and video content, where the QMediaCaptureSession is the central
+ class managing the whole capture/recording process.
+
\section1 Licenses and attributions
- The Qt Quick Multimedia module is available under commercial licenses from
+ The Qt Multimedia module is available under commercial licenses from
\l{The Qt Company}.
- In addition, it is available under free software licenses. Since Qt 5.4,
+ In addition, it is available under free software licenses. Since Qt 5.6,
these free software licenses are
\l{GNU Lesser General Public License, version 3}, or
the \l{GNU General Public License, version 2}.
See \l{Qt Licensing} for further details.
- \section1 Related information
+ Furthermore, Qt Multimedia in Qt \QtVersion may contain third-party modules
+ under following permissive licenses:
- \section2 Guides
- \list
- \li \l{Changes to Qt Multimedia}{Changes in Qt 6}
- \li \l{Multimedia Overview}
- \li \l{Audio Overview}
- \li \l{Video Overview}
- \li \l{Camera Overview}
- \endlist
+ \generatelist{groupsbymodule attributions-qtmultimedia}
- \section2 Platform notes
+ Note that video compression standards, such as the H.264 media compression
+ standard, may be covered by patents and can incur royalty fees. This can
+ apply to any implementation, also if the implementation is provided as an
+ operating system service, through a third party library, or through any of
+ Qt Multimedia's backends. Such fees are not covered by the Qt licenses.
- For most features, Qt Multimedia builds upon the multimedia framework of the
- underlying operating system. Therefore there are several multimedia back ends
- based on different technologies and APIs. For further details, see the
- \l{Qt Multimedia Backends}{Qt Multimedia back ends wiki}.
+ \section1 Target platform and backend notes
+ We aim to align the behavior on all the platforms but there are some issues
+ to consider.
- \list
- \li \l{Qt Multimedia on macOS and iOS}{macOS and iOS}
- \endlist
+ \section2 Backends
+ On most platforms, there are two different backends that can be used for
+ Qt Multimedia.
- \section2 Reference
- \list
- \li Qt Multimedia
+ \section3 FFmpeg as the default backend
+ In this release the \l {http://ffmpeg.org}{FFmpeg framework} is set as the
+ default backend on Windows, macOS, Android, and Linux except Yocto distribution.
+
+ 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 See \l{Licenses and Attributions} regarding what components are removed
+ in the package shipped by Qt.
+
+ \section3 Native backends
+ These are:
\list
- \li \l{Qt Multimedia QML Types}{QML Types}
- \li \l{Qt Multimedia C++ Classes}{C++ Classes}
+ \li gstreamer on Linux
+ \li AVFoundation on macOS and iOS
+ \li WMF Windows
+ \li MediaCodec framework on Android
\endlist
+
+ \note These are still available but with \b limited support. The gstreamer
+ backend is only available on Linux.
+
+ \section2 Backend support
+ Maintainers will strive to fix critical issues with the native backends but
+ don't guarantee fixing minor issues and won't implement new features for the
+ native backends. Furthermore, even some major issues with the gstreamer
+ backend (on Linux) won't be fixed since gstreamer is difficult to debug and
+ is further complicated as it is dependent on Linux distributions.
+
+ We aim to align the behavior on all the platforms, especially, with the
+ FFmpeg backend. Despite this fact we still have platform-dependent issues
+ with formats, codecs, advanced camera features, and screen capturing due to
+ the Qt Multimedia API relying on target platform APIs. For example, with FFmpeg,
+ there are specific problems with hardware acceleration on Linux targets with
+ ARM architectures.
+
+ Backend-dependent limitations will be documented and their status maintained
+ in the respective classes.
+
+ \section2 Changing backends
+
+ In the case of issues with the default FFmpeg backend, we suggest testing with a native backend.
+ You can switch to native backends by setting the \c{QT_MEDIA_BACKEND} environment variable
+ to \c windows, \c gstreamer (on Linux), \c darwin (on macOS and iOS), or \c android:
+
+ \code
+ export QT_MEDIA_BACKEND=darwin
+ \endcode
+
+ In order to force assign FFmpeg as the used backend, set the variable to \c ffmpeg:
+
+ \code
+ export QT_MEDIA_BACKEND=ffmpeg
+ \endcode
+
+ On the Qt Multimedia compilation stage the default media backend can be configured
+ via cmake variable \c{QT_DEFAULT_MEDIA_BACKEND}.
+
+ \section2 Target platform notes
+ The following pages list issues for specific target platforms that are not
+ related to the multimedia backed.
+
+ \list
+ \li \l{Qt Multimedia on macOS and iOS}{macOS and iOS}
+ \li \l{Qt Multimedia on WebAssembly}{WebAssembly}
\endlist
- \section2 Examples
- \list
- \li \l{Qt Multimedia Examples}
- \endlist
+ \section1 Permissions
+
+ Starting from Qt 6.6, the Qt Multimedia module uses new \l QPermission API
+ to handle \l {QCameraPermission}{camera} and
+ \l {QMicrophonePermission}{microphone} permissions. This means that Qt
+ itself no longer queries for these permissions, so this needs to be done
+ directly from the client application.
+
+ Please refer to the \l {Application Permissions} page for an example of how
+ to integrate the new \l QPermission API into the application.
+
+ \section1 Reference and examples
+ \list
+ \li \l{Qt Multimedia QML Types}{QML Types}
+ \li \l{Qt Multimedia C++ Classes}{C++ Classes}
+ \li \l{Qt Multimedia Examples}{Examples}
+ \endlist
*/
diff --git a/src/multimedia/doc/src/qtmultimedia-qml-types.qdoc b/src/multimedia/doc/src/qtmultimedia-qml-types.qdoc
index 16e0e581b..0d61a8917 100644
--- a/src/multimedia/doc/src/qtmultimedia-qml-types.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-qml-types.qdoc
@@ -1,32 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2015 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\qmlmodule QtMultimedia
+\noautolist
\title Qt Multimedia QML Types
\ingroup qmlmodules
\brief Provides QML types for multimedia support.
@@ -44,11 +21,25 @@ The QML types for \l{Qt Multimedia} support the basic use cases such as:
Qt Multimedia QML types can be imported into your application using the
following import statement in your .qml file:
-\qml \QtMinorVersion
+\qml
import QtMultimedia
\endqml
\generatelist qmltypesbymodule QtMultimedia
-\noautolist
+The \QtMultimedia import provides also the following
+\l [QtQml]{QML Value Types}{value types}:
+
+\generatelist qmlvaluetypesbymodule QtMultimedia
+
+\section2 Qt Spatial Audio Module
+
+Qt Spatial Audio QML types can be imported into your application using the
+following import statement in your .qml file:
+
+\qml
+import QtQuick3D.SpatialAudio
+\endqml
+
+\generatelist qmltypesbymodule QtQuick3D.SpatialAudio
*/
diff --git a/src/multimedia/doc/src/videooverview.qdoc b/src/multimedia/doc/src/videooverview.qdoc
index a842db6b6..3185c9a02 100644
--- a/src/multimedia/doc/src/videooverview.qdoc
+++ b/src/multimedia/doc/src/videooverview.qdoc
@@ -1,42 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page videooverview.html
\title Video Overview
\brief Video playback
+\ingroup explanations-graphicsandmultimedia
\section1 Video Features
Qt Multimedia offers both high and low level C++ classes for playing and
-manipulating video data, and QML types for playback and control. Some
-of these classes also overlap with both \l {Camera Overview}{camera} and
-\l {Audio Overview}{audio} classes, which can be useful.
+manipulating video data, and QML types for playback and recording. Some
+of the classes presented here overlap with what is presented in the \l {Camera Overview} and
+\l {Audio Overview}.
\section1 Video Implementation Details
@@ -56,10 +33,10 @@ And an example with QGraphicsVideoItem:
You can use \l VideoOutput to render content that is provided by
either a \l MediaPlayer or a \l Camera. The VideoOutput is a visual
-component that can be transformed or acted upon by shaders (as the
-\l {QML Video Shader Effects Example} shows), while all media decoding
-and playback control is handled by the \l MediaPlayer or \l CaptureSession.
-\l Video has also been provided for convenience.
+component that can be embedded into a QQuickScene or \l Window, while
+all media decoding and playback control is handled by the \l MediaPlayer
+or \l CaptureSession. A \l Video element has been provided for convenience.
+It combines MediaPlayer, VideoOutput and AudioOutput elements in one item.
\section2 Working with Low Level Video Frames
@@ -76,8 +53,51 @@ allows you to receive these frames from \l QMediaPlayer and
\l QCamera.
\section2 Recording Video
-You can use the \l QMediaRecorder class as a simple way to record video to disk.
-For more advances use cases \l QMediaCaptureSession provides a more flexible API.
+The central class for any type of capturing or recording of audio and video is QMediaCaptureSession
+(or the CaptureSession QML type). You can connect a QCamera (Camera in QML) and a QMediaRecorder
+(MediaRecorder)to the session and then ask the media recorder to start recording.
+
+\section1 Supported Media Formats
+
+What media formats are supported ultimately depends on the configuration of the
+target system.
+
+\section2 Windows
+By default what is available on a MS Windows target depends on the version of
+\l{Windows Media Player} that was packaged with the OS. See the
+\l{Windows Media Player documentation} for official information.
+
+Independent of Windows Media Player, there are of course numerous codec packs
+that could be installed. See the \l{codec guide} site for some examples.
+
+\section2 Android
+See \l{Android supported media formats} for this information.
+
+\section2 Linux
+On Linux this is about installing the correct \l{GStreamer} plugins.
+
+\section3 Minimum Required GStreamer Plugins
+\list
+\li gstreamer1.0-plugins-base
+\li gstreamer1.0-plugins-good
+\li gstreamer1.0-plugins-pulseaudio
+\endlist
+
+For a Linux desktop target, it is strongly recommended to have \c gstreamer1.0-libav
+for good codec coverage and \c gstreamer1.0-vaapi to get hardware acceleration.
+
+On embedded Linux, the required set of plugins could be somewhat different.
+
+\section2 Determining Supported Media Formats at Runtime
+You can determine what formats are available on a target system at runtime using
+the static QMediaFormat API.
+
+\list
+\li Use \l QMediaFormat::isSupported() on a QMediaFormat::ConversionMode to query a
+ specific format.
+\li Use \l QMediaFormat::supportedFileFormats() on a default constructed QMediaFormat
+ to get all the supported file formats.
+\endlist
\section1 Examples
diff --git a/src/multimedia/platform/alsa/qalsaaudiodevice_p.h b/src/multimedia/platform/alsa/qalsaaudiodevice_p.h
deleted file mode 100644
index 4f7bc5757..000000000
--- a/src/multimedia/platform/alsa/qalsaaudiodevice_p.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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 QALSAAUDIODEVICEINFO_H
-#define QALSAAUDIODEVICEINFO_H
-
-#include <alsa/asoundlib.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qdebug.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <private/qaudiodevice_p.h>
-#include <private/qaudiosystem_p.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QAlsaAudioDeviceInfo : public QAudioDevicePrivate
-{
-public:
- QAlsaAudioDeviceInfo(const QByteArray &dev, const QString &description, QAudioDevice::Mode mode);
- ~QAlsaAudioDeviceInfo();
-
-private:
- void checkSurround();
- bool surround40;
- bool surround51;
- bool surround71;
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QALSAAUDIODEVICEINFO_H
diff --git a/src/multimedia/platform/alsa/qalsaaudiosink_p.h b/src/multimedia/platform/alsa/qalsaaudiosink_p.h
deleted file mode 100644
index 9c6da2557..000000000
--- a/src/multimedia/platform/alsa/qalsaaudiosink_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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 QAUDIOOUTPUTALSA_H
-#define QAUDIOOUTPUTALSA_H
-
-#include <alsa/asoundlib.h>
-
-#include <QtCore/qfile.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qiodevice.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qaudiodevice.h>
-#include <private/qaudiosystem_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAlsaAudioSink : public QPlatformAudioSink
-{
- friend class AlsaOutputPrivate;
- Q_OBJECT
-public:
- QAlsaAudioSink(const QByteArray &device);
- ~QAlsaAudioSink();
-
- qint64 write( const char *data, qint64 len );
-
- 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& fmt) override;
- QAudioFormat format() const override;
- void setVolume(qreal) override;
- qreal volume() const override;
-
-
- QIODevice* audioSource;
- QAudioFormat settings;
- QAudio::Error errorState;
- QAudio::State deviceState;
-
-private slots:
- void userFeed();
- bool deviceReady();
-
-signals:
- void processMore();
-
-private:
- bool opened;
- bool pullMode;
- bool resuming;
- int buffer_size;
- int period_size;
- qint64 totalTimeValue;
- unsigned int buffer_time;
- unsigned int period_time;
- snd_pcm_uframes_t buffer_frames;
- snd_pcm_uframes_t period_frames;
- int xrun_recovery(int err);
-
- int setFormat();
- bool open();
- void close();
-
- QTimer* timer;
- QByteArray m_device;
- int bytesAvailable;
- qint64 elapsedTimeOffset;
- char* audioBuffer;
- snd_pcm_t* handle;
- snd_pcm_access_t access;
- snd_pcm_format_t pcmformat;
- snd_pcm_hw_params_t *hwparams;
- qreal m_volume;
-};
-
-class AlsaOutputPrivate : public QIODevice
-{
- friend class QAlsaAudioSink;
- Q_OBJECT
-public:
- AlsaOutputPrivate(QAlsaAudioSink* audio);
- ~AlsaOutputPrivate();
-
- qint64 readData( char* data, qint64 len) override;
- qint64 writeData(const char* data, qint64 len) override;
-
-private:
- QAlsaAudioSink *audioDevice;
-};
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/platform/alsa/qalsaintegration.cpp b/src/multimedia/platform/alsa/qalsaintegration.cpp
deleted file mode 100644
index bfbc40c6a..000000000
--- a/src/multimedia/platform/alsa/qalsaintegration.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qalsaintegration_p.h"
-#include "qalsamediadevices_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QAlsaIntegration::QAlsaIntegration()
-{
-}
-
-QAlsaIntegration::~QAlsaIntegration()
-{
- delete m_devices;
-}
-
-QPlatformMediaDevices *QAlsaIntegration::devices()
-{
- if (!m_devices)
- m_devices = new QAlsaMediaDevices();
- return m_devices;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/alsa/qalsaintegration_p.h b/src/multimedia/platform/alsa/qalsaintegration_p.h
deleted file mode 100644
index a3b7315b3..000000000
--- a/src/multimedia/platform/alsa/qalsaintegration_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QALSAINTEGRATION_H
-#define QALSAINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAlsaMediaDevices;
-
-class QAlsaIntegration : public QPlatformMediaIntegration
-{
-public:
- QAlsaIntegration();
- ~QAlsaIntegration();
-
- QPlatformMediaDevices *devices() override;
-
- QAlsaMediaDevices *m_devices = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/alsa/qalsamediadevices.cpp b/src/multimedia/platform/alsa/qalsamediadevices.cpp
deleted file mode 100644
index e2561e66a..000000000
--- a/src/multimedia/platform/alsa/qalsamediadevices.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qalsamediadevices_p.h"
-#include "qmediadevices.h"
-#include "qcameradevice_p.h"
-
-#include "private/qalsaaudiosource_p.h"
-#include "private/qalsaaudiosink_p.h"
-#include "private/qalsaaudiodevice_p.h"
-
-#include <alsa/asoundlib.h>
-
-QT_BEGIN_NAMESPACE
-
-QAlsaMediaDevices::QAlsaMediaDevices()
- : QPlatformMediaDevices()
-{
-}
-
-static QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode)
-{
- QList<QAudioDevice> devices;
-
- QByteArray filter;
-
- // Create a list of all current audio devices that support mode
- void **hints, **n;
- char *name, *descr, *io;
-
- if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
- qWarning() << "no alsa devices available";
- return devices;
- }
- n = hints;
-
- if(mode == QAudioDevice::Input) {
- filter = "Input";
- } else {
- filter = "Output";
- }
-
- while (*n != NULL) {
- name = snd_device_name_get_hint(*n, "NAME");
- if (name != 0 && qstrcmp(name, "null") != 0) {
- descr = snd_device_name_get_hint(*n, "DESC");
- io = snd_device_name_get_hint(*n, "IOID");
-
- if ((descr != NULL) && ((io == NULL) || (io == filter))) {
- auto *infop = new QAlsaAudioDeviceInfo(name, QString::fromUtf8(descr), mode);
- devices.append(infop->create());
- if (strcmp(name, "default") == 0)
- infop->isDefault = true;
- }
-
- free(descr);
- free(io);
- }
- free(name);
- ++n;
- }
- snd_device_name_free_hint(hints);
-
- return devices;
-}
-
-QList<QAudioDevice> QAlsaMediaDevices::audioInputs() const
-{
- return availableDevices(QAudioDevice::Input);
-}
-
-QList<QAudioDevice> QAlsaMediaDevices::audioOutputs() const
-{
- return availableDevices(QAudioDevice::Output);
-}
-
-QList<QCameraDevice> QAlsaMediaDevices::videoInputs() const
-{
- return {};
-}
-
-QPlatformAudioSource *QAlsaMediaDevices::createAudioSource(const QAudioDevice &deviceInfo)
-{
- return new QAlsaAudioSource(deviceInfo.id());
-}
-
-QPlatformAudioSink *QAlsaMediaDevices::createAudioSink(const QAudioDevice &deviceInfo)
-{
- return new QAlsaAudioSink(deviceInfo.id());
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/alsa/qalsamediadevices_p.h b/src/multimedia/platform/alsa/qalsamediadevices_p.h
deleted file mode 100644
index 54df9c851..000000000
--- a/src/multimedia/platform/alsa/qalsamediadevices_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QALSAMEDIADEVICES_H
-#define QALSAMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <qset.h>
-#include <qaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAlsaEngine;
-
-class QAlsaMediaDevices : public QPlatformMediaDevices
-{
-public:
- QAlsaMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) override;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/android/audio/qandroidaudiodecoder.cpp b/src/multimedia/platform/android/audio/qandroidaudiodecoder.cpp
deleted file mode 100644
index 718492118..000000000
--- a/src/multimedia/platform/android/audio/qandroidaudiodecoder.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "qandroidaudiodecoder_p.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qjniobject.h>
-#include <QtCore/qjnienvironment.h>
-#include <QtCore/private/qandroidextras_p.h>
-#include <QTimer>
-#include <QFile>
-#include <QDir>
-
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-QT_BEGIN_NAMESPACE
-
-static const char tempFile[] = "encoded.tmp";
-static const char tempPath[] = "/storage/emulated/0/data/local/tmp/audiodecoder/";
-constexpr int dequeueTimeout = 5000;
-Q_LOGGING_CATEGORY(adLogger, "QAndroidAudioDecoder")
-
-Decoder::Decoder()
- : m_format(AMediaFormat_new())
-{}
-
-Decoder::~Decoder()
-{
- if (m_codec) {
- AMediaCodec_delete(m_codec);
- m_codec = nullptr;
- }
-
- if (m_extractor) {
- AMediaExtractor_delete(m_extractor);
- m_extractor = nullptr;
- }
-
- if (m_format) {
- AMediaFormat_delete(m_format);
- m_format = nullptr;
- }
-}
-
-void Decoder::stop()
-{
- const media_status_t err = AMediaCodec_stop(m_codec);
- if (err != AMEDIA_OK)
- qCWarning(adLogger) << "stop() error: " << err;
-}
-
-void Decoder::setSource(const QUrl &source)
-{
- if (!m_extractor)
- m_extractor = AMediaExtractor_new();
-
- int fd = -1;
- if (source.path().contains(QLatin1String("content"))) {
- fd = QJniObject::callStaticMethod<jint>("org/qtproject/qt/android/QtNative",
- "openFdForContentUrl",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I",
- QNativeInterface::QAndroidApplication::context(),
- QJniObject::fromString(source.path()).object(),
- QJniObject::fromString(QLatin1String("r")).object());
- } else {
- fd = open(source.path().toStdString().c_str(), O_RDONLY);
- }
-
- if (fd < 0) {
- emit error(QAudioDecoder::ResourceError, tr("Invalid fileDescriptor for source."));
- return;
- }
- const int size = QFile(source.toString()).size();
- media_status_t status = AMediaExtractor_setDataSourceFd(m_extractor, fd, 0,
- size > 0 ? size : LONG_MAX);
- close(fd);
-
- if (status != AMEDIA_OK) {
- if (m_extractor) {
- AMediaExtractor_delete(m_extractor);
- m_extractor = nullptr;
- }
- emit error(QAudioDecoder::ResourceError, tr("Setting source for Audio Decoder failed."));
- }
-}
-
-void Decoder::createDecoder()
-{
- // get encoded format for decoder
- m_format = AMediaExtractor_getTrackFormat(m_extractor, 0);
-
- const char *mime;
- if (!AMediaFormat_getString(m_format, AMEDIAFORMAT_KEY_MIME, &mime)) {
- if (m_extractor) {
- AMediaExtractor_delete(m_extractor);
- m_extractor = nullptr;
- }
- emit error(QAudioDecoder::FormatError, tr("Format not supported by Audio Decoder."));
-
- return;
- }
-
- // get audio duration from source
- int64_t durationUs;
- AMediaFormat_getInt64(m_format, AMEDIAFORMAT_KEY_DURATION, &durationUs);
- emit durationChanged(durationUs / 1000);
-
- // set default output audio format from input file
- if (!m_outputFormat.isValid()) {
- int32_t sampleRate;
- AMediaFormat_getInt32(m_format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sampleRate);
- m_outputFormat.setSampleRate(sampleRate);
- int32_t channelCount;
- AMediaFormat_getInt32(m_format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &channelCount);
- m_outputFormat.setChannelCount(channelCount);
- m_outputFormat.setSampleFormat(QAudioFormat::Int16);
- }
-
- m_codec = AMediaCodec_createDecoderByType(mime);
-}
-
-void Decoder::doDecode()
-{
- if (!m_extractor) {
- emit error(QAudioDecoder::ResourceError, tr("Cannot decode, source not set."));
- return;
- }
-
- createDecoder();
-
- media_status_t status = AMediaCodec_configure(m_codec, m_format, nullptr /* surface */,
- nullptr /* crypto */, 0);
-
- if (status != AMEDIA_OK) {
- emit error(QAudioDecoder::ResourceError, tr("Audio Decoder failed configuration."));
- return;
- }
-
- status = AMediaCodec_start(m_codec);
- if (status != AMEDIA_OK) {
- emit error(QAudioDecoder::ResourceError, tr("Audio Decoder failed to start."));
- return;
- }
-
- AMediaExtractor_selectTrack(m_extractor, 0);
-
- m_inputEOS = false;
- while (!m_inputEOS) {
- // handle input buffer
- const ssize_t bufferIdx = AMediaCodec_dequeueInputBuffer(m_codec, dequeueTimeout);
-
- if (bufferIdx >= 0) {
- size_t bufferSize = {};
- uint8_t *buffer = AMediaCodec_getInputBuffer(m_codec, bufferIdx, &bufferSize);
- const int sample = AMediaExtractor_readSampleData(m_extractor, buffer, bufferSize);
- if (sample < 0) {
- m_inputEOS = true;
- break;
- }
-
- const int64_t presentationTimeUs = AMediaExtractor_getSampleTime(m_extractor);
- AMediaCodec_queueInputBuffer(m_codec, bufferIdx, 0, sample, presentationTimeUs,
- m_inputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
- AMediaExtractor_advance(m_extractor);
-
- // handle output buffer
- AMediaCodecBufferInfo info;
- ssize_t idx = AMediaCodec_dequeueOutputBuffer(m_codec, &info, dequeueTimeout);
- if (idx >= 0) {
- if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
- break;
-
- if (info.size > 0) {
- size_t bufferSize;
- const uint8_t *bufferData = AMediaCodec_getOutputBuffer(m_codec, idx,
- &bufferSize);
- const QByteArray data((const char*)(bufferData + info.offset), info.size);
- auto audioBuffer = QAudioBuffer(data, m_outputFormat, presentationTimeUs);
- if (presentationTimeUs > 0)
- emit positionChanged(std::move(audioBuffer), presentationTimeUs / 1000);
- AMediaCodec_releaseOutputBuffer(m_codec, idx, false);
- }
- } else {
- // The outputIndex doubles as a status return if its value is < 0
- switch (idx) {
- case AMEDIACODEC_INFO_TRY_AGAIN_LATER:
- qCWarning(adLogger) << "dequeueOutputBuffer() status: try again later";
- break;
- case AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED:
- qCWarning(adLogger) << "dequeueOutputBuffer() status: output buffers changed";
- break;
- case AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED:
- m_format = AMediaCodec_getOutputFormat(m_codec);
- qCWarning(adLogger) << "dequeueOutputBuffer() status: outputFormat changed";
- break;
- }
- }
- } else {
- qCWarning(adLogger) << "dequeueInputBuffer() status: invalid buffer idx " << bufferIdx;
- }
- }
-
- emit finished();
-}
-
-QAndroidAudioDecoder::QAndroidAudioDecoder(QAudioDecoder *parent)
- : QPlatformAudioDecoder(parent),
- m_decoder(new Decoder())
-{
- connect(m_decoder, &Decoder::positionChanged, this, &QAndroidAudioDecoder::positionChanged);
- connect(m_decoder, &Decoder::durationChanged, this, &QAndroidAudioDecoder::durationChanged);
- connect(m_decoder, &Decoder::error, this, &QAndroidAudioDecoder::error);
- connect(m_decoder, &Decoder::finished, this, &QAndroidAudioDecoder::finished);
-}
-
-QAndroidAudioDecoder::~QAndroidAudioDecoder()
-{
- m_decoder->thread()->exit();
- m_decoder->deleteLater();
-}
-
-void QAndroidAudioDecoder::setSource(const QUrl &fileName)
-{
- if (!requestPermissions())
- return;
-
- if (isDecoding())
- return;
-
- m_device = nullptr;
- error(QAudioDecoder::NoError, QStringLiteral(""));
-
- if (m_source != fileName) {
- m_source = fileName;
- m_decoder->setSource(m_source);
- sourceChanged();
- }
-}
-
-void QAndroidAudioDecoder::setSourceDevice(QIODevice *device)
-{
- if (isDecoding())
- return;
-
- m_source.clear();
- if (m_device != device) {
- m_device = device;
-
- if (!requestPermissions())
- return;
-
- sourceChanged();
- }
-}
-
-void QAndroidAudioDecoder::start()
-{
- if (isDecoding())
- return;
-
- setIsDecoding(true);
- m_position = -1;
-
- QThread *threadDecoder = new QThread(this);
- m_decoder->moveToThread(threadDecoder);
- threadDecoder->start();
- decode();
-}
-
-void QAndroidAudioDecoder::stop()
-{
- if (!isDecoding())
- return;
-
- m_decoder->stop();
-
- QMutexLocker locker(&m_buffersMutex);
- m_position = -1;
- m_audioBuffer.clear();
- locker.unlock();
- setIsDecoding(false);
-}
-
-QAudioBuffer QAndroidAudioDecoder::read()
-{
- QMutexLocker locker(&m_buffersMutex);
- if (m_buffersAvailable && !m_audioBuffer.isEmpty()) {
- --m_buffersAvailable;
- return m_audioBuffer.takeFirst();
- }
-
- // no buffers available
- return {};
-}
-
-bool QAndroidAudioDecoder::bufferAvailable() const
-{
- QMutexLocker locker(&m_buffersMutex);
- return m_buffersAvailable;
-}
-
-qint64 QAndroidAudioDecoder::position() const
-{
- QMutexLocker locker(&m_buffersMutex);
- return m_position;
-}
-
-qint64 QAndroidAudioDecoder::duration() const
-{
- QMutexLocker locker(&m_buffersMutex);
- return m_duration;
-}
-
-void QAndroidAudioDecoder::positionChanged(QAudioBuffer audioBuffer, qint64 position)
-{
- QMutexLocker locker(&m_buffersMutex);
- m_audioBuffer.append(audioBuffer);
- m_position = position;
- m_buffersAvailable++;
- locker.unlock();
- emit bufferReady();
- emit QPlatformAudioDecoder::positionChanged(position);
-}
-
-void QAndroidAudioDecoder::durationChanged(qint64 duration)
-{
- QMutexLocker locker(&m_buffersMutex);
- m_duration = duration;
- locker.unlock();
- emit QPlatformAudioDecoder::durationChanged(duration);
-}
-
-void QAndroidAudioDecoder::error(const QAudioDecoder::Error err, const QString &errorString)
-{
- emit QPlatformAudioDecoder::error(err, errorString);
-}
-
-void QAndroidAudioDecoder::finished()
-{
- stop();
- // remove temp file when decoding is finished
- QFile(QString::fromUtf8(tempPath).append(QString::fromUtf8(tempFile))).remove();
- emit QPlatformAudioDecoder::finished();
-}
-
-bool QAndroidAudioDecoder::requestPermissions()
-{
- const auto writeRes = QtAndroidPrivate::requestPermission(QtAndroidPrivate::Storage);
- if (writeRes.result() == QtAndroidPrivate::Authorized)
- return true;
-
- return false;
-}
-
-void QAndroidAudioDecoder::decode()
-{
- if (m_device) {
- connect(m_device, &QIODevice::readyRead, this, &QAndroidAudioDecoder::readDevice);
- if (m_device->bytesAvailable())
- readDevice();
- } else {
- QTimer::singleShot(0, m_decoder, &Decoder::doDecode);
- }
-}
-
-bool QAndroidAudioDecoder::createTempFile()
-{
- QFile file = QFile(QString::fromUtf8(tempPath).append(QString::fromUtf8(tempFile)));
- if (!QDir().mkpath(QString::fromUtf8(tempPath)) || !file.open(QIODevice::WriteOnly)) {
- emit error(QAudioDecoder::ResourceError,
- QString::fromUtf8("Error while creating or opening tmp file"));
- return false;
- }
-
- QDataStream out;
- out.setDevice(&file);
- out << m_deviceBuffer;
- file.close();
-
- m_deviceBuffer.clear();
- m_decoder->setSource(file.fileName());
-
- return true;
-}
-
-void QAndroidAudioDecoder::readDevice() {
- m_deviceBuffer.append(m_device->readAll());
- if (m_device->atEnd()) {
- disconnect(m_device, &QIODevice::readyRead, this, &QAndroidAudioDecoder::readDevice);
- if (!createTempFile()) {
- m_deviceBuffer.clear();
- stop();
- return;
- }
- QTimer::singleShot(0, m_decoder, &Decoder::doDecode);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/audio/qandroidaudiodecoder_p.h b/src/multimedia/platform/android/audio/qandroidaudiodecoder_p.h
deleted file mode 100644
index d6e1bf32e..000000000
--- a/src/multimedia/platform/android/audio/qandroidaudiodecoder_p.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDAUDIODECODER_P_H
-#define QANDROIDAUDIODECODER_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 "private/qplatformaudiodecoder_p.h"
-
-#include <QtCore/qurl.h>
-#include <QtCore/qmutex.h>
-#include <QThread>
-
-#include "media/NdkMediaCodec.h"
-#include "media/NdkMediaExtractor.h"
-#include "media/NdkMediaFormat.h"
-#include "media/NdkMediaError.h"
-
-
-QT_USE_NAMESPACE
-
-class Decoder : public QObject
-{
- Q_OBJECT
-public:
- Decoder();
- ~Decoder();
-
-public slots:
- void setSource(const QUrl &source);
- void doDecode();
- void stop();
-
-signals:
- void positionChanged(const QAudioBuffer &buffer, qint64 position);
- void durationChanged(const qint64 duration);
- void error(const QAudioDecoder::Error error, const QString &errorString);
- void finished();
-
-private:
- void createDecoder();
-
- AMediaCodec *m_codec = nullptr;
- AMediaExtractor *m_extractor = nullptr;
- AMediaFormat *m_format = nullptr;
-
- QAudioFormat m_outputFormat;
- bool m_inputEOS;
-};
-
-
-class QAndroidAudioDecoder : public QPlatformAudioDecoder
-{
- Q_OBJECT
-public:
- QAndroidAudioDecoder(QAudioDecoder *parent);
- virtual ~QAndroidAudioDecoder();
-
- QUrl source() const override { return m_source; }
- void setSource(const QUrl &fileName) override;
-
- QIODevice *sourceDevice() const override { return m_device; }
- void setSourceDevice(QIODevice *device) override;
-
- void start() override;
- void stop() override;
-
- QAudioFormat audioFormat() const override { return {}; }
- void setAudioFormat(const QAudioFormat &/*format*/) override {}
-
- QAudioBuffer read() override;
- bool bufferAvailable() const override;
-
- qint64 position() const override;
- qint64 duration() const override;
-
-private slots:
- void positionChanged(QAudioBuffer audioBuffer, qint64 position);
- void durationChanged(qint64 duration);
- void error(const QAudioDecoder::Error error, const QString &errorString);
- void readDevice();
- void finished();
-
-private:
- bool requestPermissions();
- bool createTempFile();
- void decode();
-
- QIODevice *m_device = nullptr;
- Decoder *m_decoder;
-
- QList<QAudioBuffer> m_audioBuffer;
- QUrl m_source;
-
- mutable QMutex m_buffersMutex;
- qint64 m_position = -1;
- qint64 m_duration = -1;
- long long m_presentationTimeUs = 0;
- int m_buffersAvailable = 0;
-
- QByteArray m_deviceBuffer;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDAUDIODECODER_P_H
diff --git a/src/multimedia/platform/android/audio/qandroidaudiodevice.cpp b/src/multimedia/platform/android/audio/qandroidaudiodevice.cpp
deleted file mode 100644
index fcd979a5a..000000000
--- a/src/multimedia/platform/android/audio/qandroidaudiodevice.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidaudiodevice_p.h"
-
-#include "qopenslesengine_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QOpenSLESDeviceInfo::QOpenSLESDeviceInfo(const QByteArray &device, const QString &desc, QAudioDevice::Mode mode)
- : QAudioDevicePrivate(device, mode),
- m_engine(QOpenSLESEngine::instance())
-{
- description = desc;
-
- auto channels = m_engine->supportedChannelCounts(mode);
- if (channels.size()) {
- minimumChannelCount = channels.first();
- maximumChannelCount = channels.last();
- }
-
- auto sampleRates = m_engine->supportedSampleRates(mode);
- if (sampleRates.size()) {
- minimumSampleRate = sampleRates.first();
- maximumSampleRate = sampleRates.last();
- }
- if (mode == QAudioDevice::Input)
- supportedSampleFormats.append(QAudioFormat::UInt8);
- supportedSampleFormats.append(QAudioFormat::Int16);
-
- preferredFormat.setChannelCount(2);
- preferredFormat.setSampleRate(48000);
- QAudioFormat::SampleFormat f = QAudioFormat::Int16;
- if (!supportedSampleFormats.contains(f))
- f = supportedSampleFormats.value(0, QAudioFormat::Unknown);
- preferredFormat.setSampleFormat(f);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/audio/qandroidaudiodevice_p.h b/src/multimedia/platform/android/audio/qandroidaudiodevice_p.h
deleted file mode 100644
index 81b85c9fd..000000000
--- a/src/multimedia/platform/android/audio/qandroidaudiodevice_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPENSLESDEVICEINFO_H
-#define QOPENSLESDEVICEINFO_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 <qaudiosystem_p.h>
-#include <private/qaudiodevice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpenSLESEngine;
-
-class QOpenSLESDeviceInfo : public QAudioDevicePrivate
-{
-public:
- QOpenSLESDeviceInfo(const QByteArray &device, const QString &desc, QAudioDevice::Mode mode);
- ~QOpenSLESDeviceInfo() {}
-
-private:
- QOpenSLESEngine *m_engine;
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPENSLESDEVICEINFO_H
diff --git a/src/multimedia/platform/android/audio/qandroidaudiosink_p.h b/src/multimedia/platform/android/audio/qandroidaudiosink_p.h
deleted file mode 100644
index 40b964dc2..000000000
--- a/src/multimedia/platform/android/audio/qandroidaudiosink_p.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPENSLESAUDIOOUTPUT_H
-#define QOPENSLESAUDIOOUTPUT_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 <qaudiosystem_p.h>
-#include <SLES/OpenSLES.h>
-#include <qbytearray.h>
-#include <qmap.h>
-#include <QElapsedTimer>
-#include <QIODevice>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidAudioSink : public QPlatformAudioSink
-{
- Q_OBJECT
-
-public:
- QAndroidAudioSink(const QByteArray &device);
- ~QAndroidAudioSink();
-
- 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:
- friend class SLIODevicePrivate;
-
- Q_INVOKABLE void onEOSEvent();
- Q_INVOKABLE void onBytesProcessed(qint64 bytes);
- void bufferAvailable(quint32 count, quint32 playIndex);
-
- static void playCallback(SLPlayItf playItf, void *ctx, SLuint32 event);
- static void bufferQueueCallback(SLBufferQueueItf bufferQueue, void *ctx);
-
- bool preparePlayer();
- void destroyPlayer();
- void stopPlayer();
- void startPlayer();
- qint64 writeData(const char *data, qint64 len);
-
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
- SLmillibel adjustVolume(qreal vol);
-
- QByteArray m_deviceName;
- QAudio::State m_state;
- QAudio::Error m_error;
- SLObjectItf m_outputMixObject;
- SLObjectItf m_playerObject;
- SLPlayItf m_playItf;
- SLVolumeItf m_volumeItf;
- SLBufferQueueItf m_bufferQueueItf;
- QIODevice *m_audioSource;
- char *m_buffers;
- qreal m_volume;
- bool m_pullMode;
- int m_nextBuffer;
- int m_bufferSize;
- qint64 m_elapsedTime;
- qint64 m_processedBytes;
- QAtomicInt m_availableBuffers;
- SLuint32 m_eventMask;
- bool m_startRequiresInit;
-
- qint32 m_streamType;
- QAudioFormat m_format;
-};
-
-class SLIODevicePrivate : public QIODevice
-{
- Q_OBJECT
-
-public:
- inline SLIODevicePrivate(QAndroidAudioSink *audio) : m_audioDevice(audio) {}
- inline ~SLIODevicePrivate() override {}
-
-protected:
- inline qint64 readData(char *, qint64) override { return 0; }
- inline qint64 writeData(const char *data, qint64 len) override;
-
-private:
- QAndroidAudioSink *m_audioDevice;
-};
-
-qint64 SLIODevicePrivate::writeData(const char *data, qint64 len)
-{
- Q_ASSERT(m_audioDevice);
- return m_audioDevice->writeData(data, len);
-}
-
-QT_END_NAMESPACE
-
-#endif // QOPENSLESAUDIOOUTPUT_H
diff --git a/src/multimedia/platform/android/audio/qopenslesengine_p.h b/src/multimedia/platform/android/audio/qopenslesengine_p.h
deleted file mode 100644
index 36e994fb2..000000000
--- a/src/multimedia/platform/android/audio/qopenslesengine_p.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QOPENSLESENGINE_H
-#define QOPENSLESENGINE_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 <qglobal.h>
-#include <qaudio.h>
-#include <qlist.h>
-#include <qaudioformat.h>
-#include <qaudiodevice.h>
-#include <SLES/OpenSLES_Android.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpenSLESEngine
-{
-public:
- enum OutputValue { FramesPerBuffer, SampleRate };
-
- QOpenSLESEngine();
- ~QOpenSLESEngine();
-
- static QOpenSLESEngine *instance();
-
- SLEngineItf slEngine() const { return m_engine; }
-
- static SLDataFormat_PCM audioFormatToSLFormatPCM(const QAudioFormat &format);
-
- static QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode);
- QList<int> supportedChannelCounts(QAudioDevice::Mode mode) const;
- QList<int> supportedSampleRates(QAudioDevice::Mode mode) const;
-
- static int getOutputValue(OutputValue type, int defaultValue = 0);
- static int getDefaultBufferSize(const QAudioFormat &format);
- static int getLowLatencyBufferSize(const QAudioFormat &format);
- static bool supportsLowLatency();
- static bool printDebugInfo();
-
-private:
- void checkSupportedInputFormats();
- bool inputFormatIsSupported(SLAndroidDataFormat_PCM_EX format);
- SLObjectItf m_engineObject;
- SLEngineItf m_engine;
-
- QList<int> m_supportedInputChannelCounts;
- QList<int> m_supportedInputSampleRates;
- bool m_checkedInputFormats;
-};
-
-QT_END_NAMESPACE
-
-#endif // QOPENSLESENGINE_H
diff --git a/src/multimedia/platform/android/common/qandroidaudiooutput_p.h b/src/multimedia/platform/android/common/qandroidaudiooutput_p.h
deleted file mode 100644
index e17f158fc..000000000
--- a/src/multimedia/platform/android/common/qandroidaudiooutput_p.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QANDROIDAUDIOOUTPUT_H
-#define QANDROIDAUDIOOUTPUT_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformaudiooutput_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_MULTIMEDIA_EXPORT QAndroidAudioOutput : public QPlatformAudioOutput
-{
-public:
- QAndroidAudioOutput(QAudioOutput *qq) : QPlatformAudioOutput(qq) {}
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QANDROIDAUDIOOUTPUT_H
diff --git a/src/multimedia/platform/android/common/qandroidglobal_p.h b/src/multimedia/platform/android/common/qandroidglobal_p.h
deleted file mode 100644
index 45bd22ffb..000000000
--- a/src/multimedia/platform/android/common/qandroidglobal_p.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDGLOBAL_H
-#define QANDROIDGLOBAL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtmultimediaglobal_p.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qloggingcategory.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(qtAndroidMediaPlugin)
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDGLOBAL_H
diff --git a/src/multimedia/platform/android/common/qandroidmultimediautils.cpp b/src/multimedia/platform/android/common/qandroidmultimediautils.cpp
deleted file mode 100644
index 75f012f07..000000000
--- a/src/multimedia/platform/android/common/qandroidmultimediautils.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidmultimediautils_p.h"
-#include "qandroidglobal_p.h"
-
-#include <qlist.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/private/qandroidextras_p.h>
-
-QT_BEGIN_NAMESPACE
-
-int qt_findClosestValue(const QList<int> &list, int value)
-{
- if (list.size() < 2)
- return 0;
-
- int begin = 0;
- int end = list.size() - 1;
- int pivot = begin + (end - begin) / 2;
- int v = list.at(pivot);
-
- while (end - begin > 1) {
- if (value == v)
- return pivot;
-
- if (value > v)
- begin = pivot;
- else
- end = pivot;
-
- pivot = begin + (end - begin) / 2;
- v = list.at(pivot);
- }
-
- return value - v >= list.at(pivot + 1) - value ? pivot + 1 : pivot;
-}
-
-bool qt_sizeLessThan(const QSize &s1, const QSize &s2)
-{
- return s1.width() * s1.height() < s2.width() * s2.height();
-}
-
-QVideoFrameFormat::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f)
-{
- switch (f) {
- case AndroidCamera::NV21:
- return QVideoFrameFormat::Format_NV21;
- case AndroidCamera::YV12:
- return QVideoFrameFormat::Format_YV12;
- case AndroidCamera::YUY2:
- return QVideoFrameFormat::Format_YUYV;
- case AndroidCamera::JPEG:
- return QVideoFrameFormat::Format_Jpeg;
- default:
- return QVideoFrameFormat::Format_Invalid;
- }
-}
-
-AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrameFormat::PixelFormat f)
-{
- switch (f) {
- case QVideoFrameFormat::Format_NV21:
- return AndroidCamera::NV21;
- case QVideoFrameFormat::Format_YV12:
- return AndroidCamera::YV12;
- case QVideoFrameFormat::Format_YUYV:
- return AndroidCamera::YUY2;
- case QVideoFrameFormat::Format_Jpeg:
- return AndroidCamera::JPEG;
- default:
- return AndroidCamera::UnknownImageFormat;
- }
-}
-
-static bool androidRequestPermission(QtAndroidPrivate::PermissionType key)
-{
- if (QNativeInterface::QAndroidApplication::sdkVersion() < 23)
- return true;
-
- // Permission already granted?
- if (QtAndroidPrivate::checkPermission(key).result() == QtAndroidPrivate::Authorized)
- return true;
-
- if (QtAndroidPrivate::requestPermission(key).result() != QtAndroidPrivate::Authorized)
- return false;
-
- return true;
-}
-
-static bool androidCheckPermission(QtAndroidPrivate::PermissionType key)
-{
- if (QNativeInterface::QAndroidApplication::sdkVersion() < 23)
- return true;
-
- // Permission already granted?
- return (QtAndroidPrivate::checkPermission(key).result() == QtAndroidPrivate::Authorized);
-}
-
-bool qt_androidCheckCameraPermission()
-{
- return androidCheckPermission(QtAndroidPrivate::Camera);
-}
-
-bool qt_androidCheckMicrophonePermission()
-{
- return androidCheckPermission(QtAndroidPrivate::Microphone);
-}
-
-bool qt_androidRequestCameraPermission()
-{
- if (!androidRequestPermission(QtAndroidPrivate::Camera)) {
- qCDebug(qtAndroidMediaPlugin, "Camera permission denied by user!");
- return false;
- }
-
- return true;
-}
-
-bool qt_androidRequestRecordingPermission()
-{
- if (!androidRequestPermission(QtAndroidPrivate::Microphone)) {
- qCDebug(qtAndroidMediaPlugin, "Microphone permission denied by user!");
- return false;
- }
-
- return true;
-}
-
-bool qt_androidRequestWriteStoragePermission()
-{
- if (!androidRequestPermission(QtAndroidPrivate::Storage)) {
- qCDebug(qtAndroidMediaPlugin, "Storage permission denied by user!");
- return false;
- }
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/common/qandroidmultimediautils_p.h b/src/multimedia/platform/android/common/qandroidmultimediautils_p.h
deleted file mode 100644
index 5bc187da3..000000000
--- a/src/multimedia/platform/android/common/qandroidmultimediautils_p.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDMULTIMEDIAUTILS_H
-#define QANDROIDMULTIMEDIAUTILS_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 <qglobal.h>
-#include <qsize.h>
-#include "androidcamera_p.h"
-
-QT_BEGIN_NAMESPACE
-
-// return the index of the closest value to <value> in <list>
-// (binary search)
-int qt_findClosestValue(const QList<int> &list, int value);
-
-bool qt_sizeLessThan(const QSize &s1, const QSize &s2);
-
-QVideoFrameFormat::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f);
-AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrameFormat::PixelFormat f);
-
-bool qt_androidRequestCameraPermission();
-bool qt_androidRequestRecordingPermission();
-bool qt_androidRequestWriteStoragePermission();
-
-bool qt_androidCheckCameraPermission();
-bool qt_androidCheckMicrophonePermission();
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDMULTIMEDIAUTILS_H
diff --git a/src/multimedia/platform/android/common/qandroidvideooutput.cpp b/src/multimedia/platform/android/common/qandroidvideooutput.cpp
deleted file mode 100644
index d0f3203de..000000000
--- a/src/multimedia/platform/android/common/qandroidvideooutput.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidvideooutput_p.h"
-
-#include "androidsurfacetexture_p.h"
-#include <qvideosink.h>
-#include "private/qabstractvideobuffer_p.h"
-#include "private/qplatformvideosink_p.h"
-#include <QVideoFrameFormat>
-#include <QFile>
-#include <QtGui/private/qrhigles2_p.h>
-#include <QOpenGLContext>
-#include <QPainter>
-#include <QPainterPath>
-#include <QMutexLocker>
-#include <QTextLayout>
-#include <QTextFormat>
-
-QT_BEGIN_NAMESPACE
-
-void GraphicsResourceDeleter::deleteResourcesHelper(const QList<QRhiResource *> &res)
-{
- qDeleteAll(res);
-}
-
-void GraphicsResourceDeleter::deleteRhiHelper(QRhi *rhi, QOffscreenSurface *surf)
-{
- delete rhi;
- delete surf;
-}
-
-void GraphicsResourceDeleter::deleteThisHelper()
-{
- delete this;
-}
-
-bool AndroidTextureVideoBuffer::updateReadbackFrame()
-{
- // Even though the texture was updated in a previous call, we need to re-check
- // that this has not become a stale buffer, e.g., if the output size changed or
- // has since became invalid.
- if (!m_output->m_nativeSize.isValid())
- return false;
-
- // Size changed
- if (m_output->m_nativeSize != m_size)
- return false;
-
- // In the unlikely event that we don't have a valid fbo, but have a valid size,
- // force an update.
- const bool forceUpdate = !m_output->m_readbackTex;
- if (m_textureUpdated && !forceUpdate)
- return true;
-
- // update the video texture (called from the render thread)
- return (m_textureUpdated = m_output->renderAndReadbackFrame());
-}
-
-QAbstractVideoBuffer::MapData AndroidTextureVideoBuffer::map(QVideoFrame::MapMode mode)
-{
- MapData mapData;
- if (m_mapMode == QVideoFrame::NotMapped && mode == QVideoFrame::ReadOnly && updateReadbackFrame()) {
- m_mapMode = mode;
- m_image = m_output->m_readbackImage;
- mapData.nPlanes = 1;
- mapData.bytesPerLine[0] = m_image.bytesPerLine();
- mapData.size[0] = static_cast<int>(m_image.sizeInBytes());
- mapData.data[0] = m_image.bits();
- }
- return mapData;
-}
-
-static QMatrix4x4 extTransformMatrix(AndroidSurfaceTexture *surfaceTexture)
-{
- QMatrix4x4 m = surfaceTexture->getTransformMatrix();
- // flip it back, see
- // http://androidxref.com/9.0.0_r3/xref/frameworks/native/libs/gui/GLConsumer.cpp#866
- // (NB our matrix ctor takes row major)
- static const QMatrix4x4 flipV(1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, -1.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f);
- m *= flipV;
- return m;
-}
-
-quint64 AndroidTextureVideoBuffer::textureHandle(int plane) const
-{
- if (plane != 0 || !rhi || !m_output->m_nativeSize.isValid())
- return 0;
-
- m_output->ensureExternalTexture(rhi);
- m_output->m_surfaceTexture->updateTexImage();
- m_externalMatrix = extTransformMatrix(m_output->m_surfaceTexture);
- return m_output->m_externalTex->nativeTexture().object;
-}
-
-QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) : QAndroidVideoOutput(parent) { }
-
-QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput()
-{
- clearSurfaceTexture();
-
- if (m_graphicsDeleter) { // Make sure all of these are deleted on the render thread.
- m_graphicsDeleter->deleteResources({
- m_externalTex,
- m_readbackSrc,
- m_readbackTex,
- m_readbackVBuf,
- m_readbackUBuf,
- m_externalTexSampler,
- m_readbackSrb,
- m_readbackRenderTarget,
- m_readbackRpDesc,
- m_readbackPs
- });
-
- m_graphicsDeleter->deleteRhi(m_readbackRhi, m_readbackRhiFallbackSurface);
- m_graphicsDeleter->deleteThis();
- }
-}
-
-void QAndroidTextureVideoOutput::setSubtitle(const QString &subtitle)
-{
- if (!m_sink)
- return;
- auto *sink = m_sink->platformVideoSink();
- sink->setSubtitleText(subtitle);
-}
-
-QVideoSink *QAndroidTextureVideoOutput::surface() const
-{
- return m_sink;
-}
-
-void QAndroidTextureVideoOutput::setSurface(QVideoSink *surface)
-{
- if (surface == m_sink)
- return;
-
- m_sink = surface;
-}
-
-bool QAndroidTextureVideoOutput::isReady()
-{
- return true;
-}
-
-void QAndroidTextureVideoOutput::initSurfaceTexture()
-{
- if (m_surfaceTexture)
- return;
-
- if (!m_sink)
- return;
-
- QMutexLocker locker(&m_mutex);
-
- m_surfaceTexture = new AndroidSurfaceTexture(m_externalTex ? m_externalTex->nativeTexture().object : 0);
-
- if (m_surfaceTexture->surfaceTexture() != 0) {
- connect(m_surfaceTexture, &AndroidSurfaceTexture::frameAvailable,
- this, &QAndroidTextureVideoOutput::onFrameAvailable);
- } else {
- delete m_surfaceTexture;
- m_surfaceTexture = nullptr;
- if (m_graphicsDeleter)
- m_graphicsDeleter->deleteResources({ m_externalTex });
- m_externalTex = nullptr;
- }
-}
-
-void QAndroidTextureVideoOutput::clearSurfaceTexture()
-{
- QMutexLocker locker(&m_mutex);
- if (m_surfaceTexture) {
- delete m_surfaceTexture;
- m_surfaceTexture = nullptr;
- }
-
- // Also reset the attached texture
- if (m_graphicsDeleter)
- m_graphicsDeleter->deleteResources({ m_externalTex });
- m_externalTex = nullptr;
-}
-
-AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture()
-{
- initSurfaceTexture();
- return m_surfaceTexture;
-}
-
-void QAndroidTextureVideoOutput::setVideoSize(const QSize &size)
-{
- QMutexLocker locker(&m_mutex);
- if (m_nativeSize == size)
- return;
-
- stop();
-
- m_nativeSize = size;
-}
-
-void QAndroidTextureVideoOutput::stop()
-{
- m_nativeSize = QSize();
-}
-
-void QAndroidTextureVideoOutput::reset()
-{
- // flush pending frame
- if (m_sink)
- m_sink->platformVideoSink()->setVideoFrame(QVideoFrame());
-
- clearSurfaceTexture();
-}
-
-void QAndroidTextureVideoOutput::onFrameAvailable()
-{
- if (!m_nativeSize.isValid() || !m_sink)
- return;
-
- QRhi *rhi = m_sink ? m_sink->rhi() : nullptr;
- auto *buffer = new AndroidTextureVideoBuffer(rhi, this, m_nativeSize);
- const QVideoFrameFormat::PixelFormat format = rhi ? QVideoFrameFormat::Format_SamplerExternalOES
- : QVideoFrameFormat::Format_RGBA8888;
- QVideoFrame frame(buffer, QVideoFrameFormat(m_nativeSize, format));
- m_sink->platformVideoSink()->setVideoFrame(frame);
-}
-
-static const float g_quad[] = {
- -1.f, -1.f, 0.f, 0.f,
- -1.f, 1.f, 0.f, 1.f,
- 1.f, 1.f, 1.f, 1.f,
- 1.f, -1.f, 1.f, 0.f
-};
-
-static QShader getShader(const QString &name)
-{
- QFile f(name);
- if (f.open(QIODevice::ReadOnly))
- return QShader::fromSerialized(f.readAll());
-
- return QShader();
-}
-
-bool QAndroidTextureVideoOutput::renderAndReadbackFrame()
-{
- QMutexLocker locker(&m_mutex);
-
- if (!m_nativeSize.isValid() || !m_surfaceTexture)
- return false;
-
- if (!m_readbackRhi) {
- QRhi *sinkRhi = m_sink ? m_sink->rhi() : nullptr;
- if (sinkRhi && sinkRhi->backend() == QRhi::OpenGLES2) {
- // There is an rhi from the sink, e.g. VideoOutput. We lack the necessary
- // insight to use that directly, so create our own a QRhi that just wraps the
- // same QOpenGLContext.
- sinkRhi->finish();
- QRhiGles2NativeHandles h = *static_cast<const QRhiGles2NativeHandles *>(sinkRhi->nativeHandles());
- m_readbackRhiFallbackSurface = QRhiGles2InitParams::newFallbackSurface(h.context->format());
- QRhiGles2InitParams initParams;
- initParams.format = h.context->format();
- initParams.fallbackSurface = m_readbackRhiFallbackSurface;
- m_readbackRhi = QRhi::create(QRhi::OpenGLES2, &initParams, {}, &h);
- } else {
- // No rhi from the sink, e.g. QVideoWidget.
- // We will fire up our own QRhi with its own QOpenGLContext.
- m_readbackRhiFallbackSurface = QRhiGles2InitParams::newFallbackSurface({});
- QRhiGles2InitParams initParams;
- initParams.fallbackSurface = m_readbackRhiFallbackSurface;
- m_readbackRhi = QRhi::create(QRhi::OpenGLES2, &initParams);
- }
- }
-
- if (!m_readbackRhi) {
- qWarning("Failed to create QRhi for video frame readback");
- return false;
- }
-
- QRhiCommandBuffer *cb = nullptr;
- if (m_readbackRhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess)
- return false;
-
- if (!m_readbackTex || m_readbackTex->pixelSize() != m_nativeSize) {
- delete m_readbackRenderTarget;
- delete m_readbackRpDesc;
- delete m_readbackTex;
- m_readbackTex = m_readbackRhi->newTexture(QRhiTexture::RGBA8, m_nativeSize, 1, QRhiTexture::RenderTarget);
- if (!m_readbackTex->create()) {
- qWarning("Failed to create readback texture");
- return false;
- }
- m_readbackRenderTarget = m_readbackRhi->newTextureRenderTarget({ { m_readbackTex } });
- m_readbackRpDesc = m_readbackRenderTarget->newCompatibleRenderPassDescriptor();
- m_readbackRenderTarget->setRenderPassDescriptor(m_readbackRpDesc);
- m_readbackRenderTarget->create();
- }
-
- m_readbackRhi->makeThreadLocalNativeContextCurrent();
- ensureExternalTexture(m_readbackRhi);
- m_surfaceTexture->updateTexImage();
-
- // The only purpose of m_readbackSrc is to be nice and have a QRhiTexture that belongs
- // to m_readbackRhi, not the sink's rhi if there is one. The underlying native object
- // (and the rhi's OpenGL context) are the same regardless.
- if (!m_readbackSrc)
- m_readbackSrc = m_readbackRhi->newTexture(QRhiTexture::RGBA8, m_nativeSize, 1, QRhiTexture::ExternalOES);
-
- // Keep the object the same (therefore all references to m_readbackSrc in
- // the srb or other objects stay valid all the time), just call createFrom
- // if the native external texture changes.
- const quint64 texId = m_externalTex->nativeTexture().object;
- if (m_readbackSrc->nativeTexture().object != texId)
- m_readbackSrc->createFrom({ texId, 0 });
-
- QRhiResourceUpdateBatch *rub = nullptr;
- if (!m_readbackVBuf) {
- m_readbackVBuf = m_readbackRhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(g_quad));
- m_readbackVBuf->create();
- if (!rub)
- rub = m_readbackRhi->nextResourceUpdateBatch();
- rub->uploadStaticBuffer(m_readbackVBuf, g_quad);
- }
-
- if (!m_readbackUBuf) {
- m_readbackUBuf = m_readbackRhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 64 + 4 + 4);
- m_readbackUBuf->create();
- }
-
- if (!m_externalTexSampler) {
- m_externalTexSampler = m_readbackRhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
- QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
- m_externalTexSampler->create();
- }
-
- if (!m_readbackSrb) {
- m_readbackSrb = m_readbackRhi->newShaderResourceBindings();
- m_readbackSrb->setBindings({
- QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_readbackUBuf),
- QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, m_readbackSrc, m_externalTexSampler)
- });
- m_readbackSrb->create();
- }
-
- if (!m_readbackPs) {
- m_readbackPs = m_readbackRhi->newGraphicsPipeline();
- m_readbackPs->setTopology(QRhiGraphicsPipeline::TriangleFan);
- QShader vs = getShader(QStringLiteral(":/qt-project.org/multimedia/shaders/externalsampler.vert.qsb"));
- Q_ASSERT(vs.isValid());
- QShader fs = getShader(QStringLiteral(":/qt-project.org/multimedia/shaders/externalsampler.frag.qsb"));
- Q_ASSERT(fs.isValid());
- m_readbackPs->setShaderStages({
- { QRhiShaderStage::Vertex, vs },
- { QRhiShaderStage::Fragment, fs }
- });
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({
- { 4 * sizeof(float) }
- });
- inputLayout.setAttributes({
- { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
- { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
- });
- m_readbackPs->setVertexInputLayout(inputLayout);
- m_readbackPs->setShaderResourceBindings(m_readbackSrb);
- m_readbackPs->setRenderPassDescriptor(m_readbackRpDesc);
- m_readbackPs->create();
- }
-
- QMatrix4x4 identity;
- char *p = m_readbackUBuf->beginFullDynamicBufferUpdateForCurrentFrame();
- memcpy(p, identity.constData(), 64);
- QMatrix4x4 extMatrix = extTransformMatrix(m_surfaceTexture);
- memcpy(p + 64, extMatrix.constData(), 64);
- float opacity = 1.0f;
- memcpy(p + 64 + 64, &opacity, 4);
- m_readbackUBuf->endFullDynamicBufferUpdateForCurrentFrame();
-
- cb->beginPass(m_readbackRenderTarget, Qt::transparent, { 1.0f, 0 }, rub);
- cb->setGraphicsPipeline(m_readbackPs);
- cb->setViewport(QRhiViewport(0, 0, m_nativeSize.width(), m_nativeSize.height()));
- cb->setShaderResources();
- const QRhiCommandBuffer::VertexInput vbufBinding(m_readbackVBuf, 0);
- cb->setVertexInput(0, 1, &vbufBinding);
- cb->draw(4);
-
- QRhiReadbackDescription readDesc(m_readbackTex);
- QRhiReadbackResult readResult;
- bool readCompleted = false;
- // invoked at latest in the endOffscreenFrame() below
- readResult.completed = [&readCompleted] { readCompleted = true; };
- rub = m_readbackRhi->nextResourceUpdateBatch();
- rub->readBackTexture(readDesc, &readResult);
-
- cb->endPass(rub);
-
- m_readbackRhi->endOffscreenFrame();
-
- if (!readCompleted)
- return false;
-
- // implicit sharing, keep the data alive
- m_readbackImageData = readResult.data;
- // the QImage does not own the data
- m_readbackImage = QImage(reinterpret_cast<const uchar *>(m_readbackImageData.constData()),
- readResult.pixelSize.width(), readResult.pixelSize.height(),
- QImage::Format_ARGB32_Premultiplied);
-
- return true;
-}
-
-void QAndroidTextureVideoOutput::ensureExternalTexture(QRhi *rhi)
-{
- if (!m_graphicsDeleter)
- m_graphicsDeleter = new GraphicsResourceDeleter;
-
- if (!m_externalTex) {
- m_surfaceTexture->detachFromGLContext();
- m_externalTex = rhi->newTexture(QRhiTexture::RGBA8, m_nativeSize, 1, QRhiTexture::ExternalOES);
- if (!m_externalTex->create())
- qWarning("Failed to create native texture object");
- m_surfaceTexture->attachToGLContext(m_externalTex->nativeTexture().object);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/common/qandroidvideooutput_p.h b/src/multimedia/platform/android/common/qandroidvideooutput_p.h
deleted file mode 100644
index fc85d74fc..000000000
--- a/src/multimedia/platform/android/common/qandroidvideooutput_p.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDVIDEOOUTPUT_H
-#define QANDROIDVIDEOOUTPUT_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 <qsize.h>
-#include <qmutex.h>
-#include <qreadwritelock.h>
-#include <private/qabstractvideobuffer_p.h>
-#include <qmatrix4x4.h>
-#include <QtGui/private/qrhi_p.h>
-#include <QtGui/qoffscreensurface.h>
-#include <QPixmap>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidSurfaceTexture;
-class AndroidSurfaceHolder;
-class QVideoSink;
-
-class QAndroidVideoOutput : public QObject
-{
- Q_OBJECT
-public:
- virtual ~QAndroidVideoOutput() { }
-
- virtual AndroidSurfaceTexture *surfaceTexture() { return 0; }
- virtual AndroidSurfaceHolder *surfaceHolder() { return 0; }
-
- virtual bool isReady() { return true; }
-
- virtual void setVideoSize(const QSize &) { }
- virtual void stop() { }
- virtual void reset() { }
-
-Q_SIGNALS:
- void readyChanged(bool);
-
-protected:
- QAndroidVideoOutput(QObject *parent) : QObject(parent) { }
-};
-
-class GraphicsResourceDeleter : public QObject
-{
- Q_OBJECT
-public:
- void deleteResources(const QList<QRhiResource *> &res) { QMetaObject::invokeMethod(this, "deleteResourcesHelper", Qt::AutoConnection, Q_ARG(QList<QRhiResource*>, res)); }
- void deleteRhi(QRhi *rhi, QOffscreenSurface *surf) { QMetaObject::invokeMethod(this, "deleteRhiHelper", Qt::AutoConnection, Q_ARG(QRhi*, rhi), Q_ARG(QOffscreenSurface*, surf)); }
- void deleteThis() { QMetaObject::invokeMethod(this, "deleteThisHelper"); }
-
-private:
- Q_INVOKABLE void deleteResourcesHelper(const QList<QRhiResource *> &res);
- Q_INVOKABLE void deleteRhiHelper(QRhi *rhi, QOffscreenSurface *surf);
- Q_INVOKABLE void deleteThisHelper();
-};
-
-class QAndroidTextureVideoOutput : public QAndroidVideoOutput
-{
- Q_OBJECT
-public:
- explicit QAndroidTextureVideoOutput(QObject *parent = 0);
- ~QAndroidTextureVideoOutput() override;
-
- QVideoSink *surface() const;
- void setSurface(QVideoSink *surface);
-
- AndroidSurfaceTexture *surfaceTexture() override;
-
- bool isReady() override;
- void setVideoSize(const QSize &) override;
- void stop() override;
- void reset() override;
-
- void setSubtitle(const QString &subtitle);
-private Q_SLOTS:
- void onFrameAvailable();
-
-private:
- void initSurfaceTexture();
- bool renderAndReadbackFrame();
- void ensureExternalTexture(QRhi *rhi);
-
- QMutex m_mutex;
- QReadWriteLock m_subtitleLock;
-
- void clearSurfaceTexture();
-
- QVideoSink *m_sink = nullptr;
- QSize m_nativeSize;
-
- AndroidSurfaceTexture *m_surfaceTexture = nullptr;
-
- QRhiTexture *m_externalTex = nullptr;
-
- QRhi *m_readbackRhi = nullptr;
- QOffscreenSurface *m_readbackRhiFallbackSurface = nullptr;
- QRhiTexture *m_readbackSrc = nullptr;
- QRhiTexture *m_readbackTex = nullptr;
- QRhiBuffer *m_readbackVBuf = nullptr;
- QRhiBuffer *m_readbackUBuf = nullptr;
- QRhiSampler *m_externalTexSampler = nullptr;
- QRhiShaderResourceBindings *m_readbackSrb = nullptr;
- QRhiTextureRenderTarget *m_readbackRenderTarget = nullptr;
- QRhiRenderPassDescriptor *m_readbackRpDesc = nullptr;
- QRhiGraphicsPipeline *m_readbackPs = nullptr;
-
- QImage m_readbackImage;
- QByteArray m_readbackImageData;
-
- QString m_subtitleText;
- QPixmap m_subtitlePixmap;
-
- GraphicsResourceDeleter *m_graphicsDeleter = nullptr;
-
- friend class AndroidTextureVideoBuffer;
-};
-
-
-class AndroidTextureVideoBuffer : public QAbstractVideoBuffer
-{
-public:
- AndroidTextureVideoBuffer(QRhi *rhi, QAndroidTextureVideoOutput *output, const QSize &size)
- : QAbstractVideoBuffer(rhi ? QVideoFrame::RhiTextureHandle : QVideoFrame::NoHandle, rhi)
- , m_output(output)
- , m_size(size)
- {
- }
-
- virtual ~AndroidTextureVideoBuffer() {}
-
- QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
-
- MapData map(QVideoFrame::MapMode mode) override;
-
- void unmap() override
- {
- m_image = QImage();
- m_mapMode = QVideoFrame::NotMapped;
- }
-
- quint64 textureHandle(int plane) const override;
-
- QMatrix4x4 externalTextureMatrix() const
- {
- return m_externalMatrix;
- }
-
-private:
- bool updateReadbackFrame();
-
- QVideoFrame::MapMode m_mapMode = QVideoFrame::NotMapped;
- QAndroidTextureVideoOutput *m_output = nullptr;
- QImage m_image;
- QSize m_size;
- mutable QMatrix4x4 m_externalMatrix;
- bool m_textureUpdated = false;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QList<QRhiResource *>)
-Q_DECLARE_METATYPE(QRhi*)
-
-#endif // QANDROIDVIDEOOUTPUT_H
diff --git a/src/multimedia/platform/android/common/qandroidvideosink.cpp b/src/multimedia/platform/android/common/qandroidvideosink.cpp
deleted file mode 100644
index 7cc0fefe4..000000000
--- a/src/multimedia/platform/android/common/qandroidvideosink.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidvideosink_p.h"
-#include <QtGui/private/qrhi_p.h>
-
-#include <QtCore/qdebug.h>
-
-#include <QtCore/qloggingcategory.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(qLcMediaVideoSink, "qt.multimedia.videosink")
-
-QAndroidVideoSink::QAndroidVideoSink(QVideoSink *parent)
- : QPlatformVideoSink(parent)
-{
-}
-
-QAndroidVideoSink::~QAndroidVideoSink()
-{
-}
-
-void QAndroidVideoSink::setRhi(QRhi *rhi)
-{
- if (rhi && rhi->backend() != QRhi::OpenGLES2)
- rhi = nullptr;
- if (m_rhi == rhi)
- return;
-
- m_rhi = rhi;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/common/qandroidvideosink_p.h b/src/multimedia/platform/android/common/qandroidvideosink_p.h
deleted file mode 100644
index d653234f1..000000000
--- a/src/multimedia/platform/android/common/qandroidvideosink_p.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDVIDEOSINK_P_H
-#define QANDROIDVIDEOSINK_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 <private/qtmultimediaglobal_p.h>
-#include <private/qplatformvideosink_p.h>
-
-#include <qvideosink.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidVideoSink
- : public QPlatformVideoSink
-{
- Q_OBJECT
-public:
- explicit QAndroidVideoSink(QVideoSink *parent = 0);
- ~QAndroidVideoSink();
-
- void setRhi(QRhi *rhi) override;
-
-private:
- QRhi *m_rhi = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/android/mediacapture/qandroidcamera.cpp b/src/multimedia/platform/android/mediacapture/qandroidcamera.cpp
deleted file mode 100644
index 3bcc93564..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidcamera.cpp
+++ /dev/null
@@ -1,590 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidcamera_p.h"
-#include "qandroidcamerasession_p.h"
-#include "qandroidcapturesession_p.h"
-#include "qandroidmediacapturesession_p.h"
-#include <qmediadevices.h>
-#include <qcameradevice.h>
-#include <qtimer.h>
-#include "qandroidmultimediautils_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QAndroidCamera::QAndroidCamera(QCamera *camera)
- : QPlatformCamera(camera)
-{
- Q_ASSERT(camera);
-}
-
-QAndroidCamera::~QAndroidCamera()
-{
-}
-
-void QAndroidCamera::setActive(bool active)
-{
- if (m_cameraSession)
- m_cameraSession->setActive(active);
-}
-
-bool QAndroidCamera::isActive() const
-{
- return m_cameraSession ? m_cameraSession->isActive() : false;
-}
-
-void QAndroidCamera::setCamera(const QCameraDevice &camera)
-{
- m_cameraDev = camera;
-
- if (m_cameraSession) {
- int id = 0;
- auto cameras = QMediaDevices::videoInputs();
- for (int i = 0; i < cameras.size(); ++i) {
- if (cameras.at(i) == camera) {
- id = i;
- break;
- }
- }
- if (id != m_cameraSession->getSelectedCameraId()) {
- m_cameraSession->setSelectedCameraId(id);
- reactivateCameraSession();
- }
- }
-}
-
-void QAndroidCamera::reactivateCameraSession()
-{
- if (m_cameraSession->isActive()) {
- if (m_service->captureSession() &&
- m_service->captureSession()->state() == QMediaRecorder::RecordingState) {
- m_service->captureSession()->stop();
- qWarning() << "Changing camera during recording not supported";
- }
- m_cameraSession->setActive(false);
- m_cameraSession->setActive(true);
- }
-}
-
-bool QAndroidCamera::setCameraFormat(const QCameraFormat &format)
-{
- m_cameraFormat = format;
-
- if (m_cameraSession)
- m_cameraSession->setCameraFormat(m_cameraFormat);
-
- return true;
-}
-
-void QAndroidCamera::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QAndroidMediaCaptureSession *captureSession = static_cast<QAndroidMediaCaptureSession *>(session);
- if (m_service == captureSession)
- return;
-
- m_service = captureSession;
- if (!m_service) {
- disconnect(m_cameraSession,nullptr,this,nullptr);
- m_cameraSession = nullptr;
- return;
- }
-
- m_cameraSession = m_service->cameraSession();
- Q_ASSERT(m_cameraSession);
- if (!m_cameraFormat.isNull())
- m_cameraSession->setCameraFormat(m_cameraFormat);
-
- setCamera(m_cameraDev);
-
- connect(m_cameraSession, &QAndroidCameraSession::activeChanged, this, &QAndroidCamera::activeChanged);
- connect(m_cameraSession, &QAndroidCameraSession::error, this, &QAndroidCamera::error);
- connect(m_cameraSession, &QAndroidCameraSession::opened, this, &QAndroidCamera::onCameraOpened);
-}
-
-void QAndroidCamera::setFocusMode(QCamera::FocusMode mode)
-{
- if (!m_cameraSession || !m_cameraSession->camera())
- return;
-
- if (isFocusModeSupported(mode)) {
- QString focusMode;
-
- switch (mode) {
- case QCamera::FocusModeHyperfocal:
- focusMode = QLatin1String("edof");
- break;
- case QCamera::FocusModeInfinity: // not 100%, but close
- focusMode = QLatin1String("infinity");
- break;
- case QCamera::FocusModeManual:
- focusMode = QLatin1String("fixed");
- break;
- case QCamera::FocusModeAutoNear:
- focusMode = QLatin1String("macro");
- break;
- case QCamera::FocusModeAuto:
- case QCamera::FocusModeAutoFar:
- if (1) { // ###?
- focusMode = QLatin1String("continuous-video");
- } else {
- focusMode = QLatin1String("continuous-picture");
- }
- break;
- }
-
- m_cameraSession->camera()->setFocusMode(focusMode);
-
- // reset focus position
- m_cameraSession->camera()->cancelAutoFocus();
-
- focusModeChanged(mode);
- }
-}
-
-bool QAndroidCamera::isFocusModeSupported(QCamera::FocusMode mode) const
-{
- return (m_cameraSession && m_cameraSession->camera()) ? m_supportedFocusModes.contains(mode) : false;
-}
-
-void QAndroidCamera::onCameraOpened()
-{
- Q_ASSERT(m_cameraSession);
- connect(m_cameraSession->camera(), &AndroidCamera::previewSizeChanged, this, &QAndroidCamera::setCameraFocusArea);
-
- m_supportedFocusModes.clear();
- m_continuousPictureFocusSupported = false;
- m_continuousVideoFocusSupported = false;
- m_focusPointSupported = false;
-
- QStringList focusModes = m_cameraSession->camera()->getSupportedFocusModes();
- for (int i = 0; i < focusModes.size(); ++i) {
- const QString &focusMode = focusModes.at(i);
- if (focusMode == QLatin1String("continuous-picture")) {
- m_supportedFocusModes << QCamera::FocusModeAuto;
- m_continuousPictureFocusSupported = true;
- } else if (focusMode == QLatin1String("continuous-video")) {
- m_supportedFocusModes << QCamera::FocusModeAuto;
- m_continuousVideoFocusSupported = true;
- } else if (focusMode == QLatin1String("edof")) {
- m_supportedFocusModes << QCamera::FocusModeHyperfocal;
- } else if (focusMode == QLatin1String("fixed")) {
- m_supportedFocusModes << QCamera::FocusModeManual;
- } else if (focusMode == QLatin1String("infinity")) {
- m_supportedFocusModes << QCamera::FocusModeInfinity;
- } else if (focusMode == QLatin1String("macro")) {
- m_supportedFocusModes << QCamera::FocusModeAutoNear;
- }
- }
-
- if (m_cameraSession->camera()->getMaxNumFocusAreas() > 0)
- m_focusPointSupported = true;
-
- auto m = focusMode();
- if (!m_supportedFocusModes.contains(m))
- m = QCamera::FocusModeAuto;
-
- setFocusMode(m);
- setCustomFocusPoint(focusPoint());
-
- if (m_cameraSession->camera()->isZoomSupported()) {
- m_zoomRatios = m_cameraSession->camera()->getZoomRatios();
- qreal maxZoom = m_zoomRatios.last() / qreal(100);
- if (m_maximumZoom != maxZoom) {
- m_maximumZoom = maxZoom;
- }
- zoomTo(1, -1);
- } else {
- m_zoomRatios.clear();
- m_maximumZoom = 1.0;
- }
-
- m_minExposureCompensationIndex = m_cameraSession->camera()->getMinExposureCompensation();
- m_maxExposureCompensationIndex = m_cameraSession->camera()->getMaxExposureCompensation();
- m_exposureCompensationStep = m_cameraSession->camera()->getExposureCompensationStep();
- exposureCompensationRangeChanged(m_minExposureCompensationIndex*m_exposureCompensationStep,
- m_maxExposureCompensationIndex*m_exposureCompensationStep);
-
- m_supportedExposureModes.clear();
- QStringList sceneModes = m_cameraSession->camera()->getSupportedSceneModes();
- if (!sceneModes.isEmpty()) {
- for (int i = 0; i < sceneModes.size(); ++i) {
- const QString &sceneMode = sceneModes.at(i);
- if (sceneMode == QLatin1String("auto"))
- m_supportedExposureModes << QCamera::ExposureAuto;
- else if (sceneMode == QLatin1String("beach"))
- m_supportedExposureModes << QCamera::ExposureBeach;
- else if (sceneMode == QLatin1String("night"))
- m_supportedExposureModes << QCamera::ExposureNight;
- else if (sceneMode == QLatin1String("portrait"))
- m_supportedExposureModes << QCamera::ExposurePortrait;
- else if (sceneMode == QLatin1String("snow"))
- m_supportedExposureModes << QCamera::ExposureSnow;
- else if (sceneMode == QLatin1String("sports"))
- m_supportedExposureModes << QCamera::ExposureSports;
- else if (sceneMode == QLatin1String("action"))
- m_supportedExposureModes << QCamera::ExposureAction;
- else if (sceneMode == QLatin1String("landscape"))
- m_supportedExposureModes << QCamera::ExposureLandscape;
- else if (sceneMode == QLatin1String("night-portrait"))
- m_supportedExposureModes << QCamera::ExposureNightPortrait;
- else if (sceneMode == QLatin1String("theatre"))
- m_supportedExposureModes << QCamera::ExposureTheatre;
- else if (sceneMode == QLatin1String("sunset"))
- m_supportedExposureModes << QCamera::ExposureSunset;
- else if (sceneMode == QLatin1String("steadyphoto"))
- m_supportedExposureModes << QCamera::ExposureSteadyPhoto;
- else if (sceneMode == QLatin1String("fireworks"))
- m_supportedExposureModes << QCamera::ExposureFireworks;
- else if (sceneMode == QLatin1String("party"))
- m_supportedExposureModes << QCamera::ExposureParty;
- else if (sceneMode == QLatin1String("candlelight"))
- m_supportedExposureModes << QCamera::ExposureCandlelight;
- else if (sceneMode == QLatin1String("barcode"))
- m_supportedExposureModes << QCamera::ExposureBarcode;
- }
- }
-
- setExposureCompensation(exposureCompensation());
- setExposureMode(exposureMode());
-
- isFlashSupported = false;
- isFlashAutoSupported = false;
- isTorchSupported = false;
-
- QStringList flashModes = m_cameraSession->camera()->getSupportedFlashModes();
- for (int i = 0; i < flashModes.size(); ++i) {
- const QString &flashMode = flashModes.at(i);
- if (flashMode == QLatin1String("auto"))
- isFlashAutoSupported = true;
- else if (flashMode == QLatin1String("on"))
- isFlashSupported = true;
- else if (flashMode == QLatin1String("torch"))
- isTorchSupported = true;
- }
-
- setFlashMode(flashMode());
-
- m_supportedWhiteBalanceModes.clear();
- QStringList whiteBalanceModes = m_cameraSession->camera()->getSupportedWhiteBalance();
- for (int i = 0; i < whiteBalanceModes.size(); ++i) {
- const QString &wb = whiteBalanceModes.at(i);
- if (wb == QLatin1String("auto")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceAuto,
- QStringLiteral("auto"));
- } else if (wb == QLatin1String("cloudy-daylight")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceCloudy,
- QStringLiteral("cloudy-daylight"));
- } else if (wb == QLatin1String("daylight")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceSunlight,
- QStringLiteral("daylight"));
- } else if (wb == QLatin1String("fluorescent")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceFluorescent,
- QStringLiteral("fluorescent"));
- } else if (wb == QLatin1String("incandescent")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceTungsten,
- QStringLiteral("incandescent"));
- } else if (wb == QLatin1String("shade")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceShade,
- QStringLiteral("shade"));
- } else if (wb == QLatin1String("twilight")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceSunset,
- QStringLiteral("twilight"));
- } else if (wb == QLatin1String("warm-fluorescent")) {
- m_supportedWhiteBalanceModes.insert(QCamera::WhiteBalanceFlash,
- QStringLiteral("warm-fluorescent"));
- }
- }
-
-}
-
-//void QAndroidCameraFocusControl::onCameraCaptureModeChanged()
-//{
-// if (m_cameraSession->camera() && m_focusMode == QCamera::FocusModeAudio) {
-// QString focusMode;
-// if ((m_cameraSession->captureMode().testFlag(QCamera::CaptureVideo) && m_continuousVideoFocusSupported)
-// || !m_continuousPictureFocusSupported) {
-// focusMode = QLatin1String("continuous-video");
-// } else {
-// focusMode = QLatin1String("continuous-picture");
-// }
-// m_cameraSession->camera()->setFocusMode(focusMode);
-// m_cameraSession->camera()->cancelAutoFocus();
-// }
-//}
-
-static QRect adjustedArea(const QRectF &area)
-{
- // Qt maps focus points in the range (0.0, 0.0) -> (1.0, 1.0)
- // Android maps focus points in the range (-1000, -1000) -> (1000, 1000)
- // Converts an area in Qt coordinates to Android coordinates
- return QRect(-1000 + qRound(area.x() * 2000),
- -1000 + qRound(area.y() * 2000),
- qRound(area.width() * 2000),
- qRound(area.height() * 2000))
- .intersected(QRect(-1000, -1000, 2000, 2000));
-}
-
-void QAndroidCamera::setCameraFocusArea()
-{
- if (!m_cameraSession)
- return;
-
- QList<QRect> areas;
- auto focusPoint = customFocusPoint();
- if (QRectF(0., 0., 1., 1.).contains(focusPoint)) {
- // in FocusPointAuto mode, leave the area list empty
- // to let the driver choose the focus point.
- QSize viewportSize = m_cameraSession->camera()->previewSize();
-
- if (!viewportSize.isValid())
- return;
-
- // Set up a 50x50 pixel focus area around the focal point
- QSizeF focusSize(50.f / viewportSize.width(), 50.f / viewportSize.height());
- float x = qBound(qreal(0),
- focusPoint.x() - (focusSize.width() / 2),
- 1.f - focusSize.width());
- float y = qBound(qreal(0),
- focusPoint.y() - (focusSize.height() / 2),
- 1.f - focusSize.height());
-
- QRectF area(QPointF(x, y), focusSize);
-
- areas.append(adjustedArea(area));
- }
- m_cameraSession->camera()->setFocusAreas(areas);
-}
-
-void QAndroidCamera::zoomTo(float factor, float rate)
-{
- Q_UNUSED(rate);
-
- if (zoomFactor() == factor)
- return;
-
- if (!m_cameraSession || !m_cameraSession->camera())
- return;
-
- factor = qBound(qreal(1), factor, maxZoomFactor());
- int validZoomIndex = qt_findClosestValue(m_zoomRatios, qRound(factor * 100));
- float newZoom = m_zoomRatios.at(validZoomIndex) / qreal(100);
- m_cameraSession->camera()->setZoom(validZoomIndex);
- zoomFactorChanged(newZoom);
-}
-
-void QAndroidCamera::setFlashMode(QCamera::FlashMode mode)
-{
- if (!m_cameraSession || !m_cameraSession->camera())
- return;
-
- if (!isFlashModeSupported(mode))
- return;
-
- QString flashMode;
- if (mode == QCamera::FlashAuto)
- flashMode = QLatin1String("auto");
- else if (mode == QCamera::FlashOn)
- flashMode = QLatin1String("on");
- else // FlashOff
- flashMode = QLatin1String("off");
-
- m_cameraSession->camera()->setFlashMode(flashMode);
- flashModeChanged(mode);
-}
-
-bool QAndroidCamera::isFlashModeSupported(QCamera::FlashMode mode) const
-{
- if (!m_cameraSession || !m_cameraSession->camera())
- return false;
- switch (mode) {
- case QCamera::FlashOff:
- return true;
- case QCamera::FlashOn:
- return isFlashSupported;
- case QCamera::FlashAuto:
- return isFlashAutoSupported;
- }
-}
-
-bool QAndroidCamera::isFlashReady() const
-{
- // Android doesn't have an API for that
- return true;
-}
-
-void QAndroidCamera::setTorchMode(QCamera::TorchMode mode)
-{
- if (!m_cameraSession)
- return;
- auto *camera = m_cameraSession->camera();
- if (!camera || !isTorchSupported || mode == QCamera::TorchAuto)
- return;
-
- if (mode == QCamera::TorchOn) {
- camera->setFlashMode(QLatin1String("torch"));
- } else if (mode == QCamera::TorchOff) {
- // if torch was enabled, it first needs to be turned off before restoring the flash mode
- camera->setFlashMode(QLatin1String("off"));
- setFlashMode(flashMode());
- }
- torchModeChanged(mode);
-}
-
-bool QAndroidCamera::isTorchModeSupported(QCamera::TorchMode mode) const
-{
- if (!m_cameraSession || !m_cameraSession->camera())
- return false;
- switch (mode) {
- case QCamera::TorchOff:
- return true;
- case QCamera::TorchOn:
- return isTorchSupported;
- case QCamera::TorchAuto:
- return false;
- }
-}
-
-void QAndroidCamera::setExposureMode(QCamera::ExposureMode mode)
-{
- if (exposureMode() == mode)
- return;
-
- if (!m_cameraSession || !m_cameraSession->camera())
- return;
-
- if (!m_supportedExposureModes.contains(mode))
- return;
-
- QString sceneMode;
- switch (mode) {
- case QCamera::ExposureAuto:
- sceneMode = QLatin1String("auto");
- break;
- case QCamera::ExposureSports:
- sceneMode = QLatin1String("sports");
- break;
- case QCamera::ExposurePortrait:
- sceneMode = QLatin1String("portrait");
- break;
- case QCamera::ExposureBeach:
- sceneMode = QLatin1String("beach");
- break;
- case QCamera::ExposureSnow:
- sceneMode = QLatin1String("snow");
- break;
- case QCamera::ExposureNight:
- sceneMode = QLatin1String("night");
- break;
- case QCamera::ExposureAction:
- sceneMode = QLatin1String("action");
- break;
- case QCamera::ExposureLandscape:
- sceneMode = QLatin1String("landscape");
- break;
- case QCamera::ExposureNightPortrait:
- sceneMode = QLatin1String("night-portrait");
- break;
- case QCamera::ExposureTheatre:
- sceneMode = QLatin1String("theatre");
- break;
- case QCamera::ExposureSunset:
- sceneMode = QLatin1String("sunset");
- break;
- case QCamera::ExposureSteadyPhoto:
- sceneMode = QLatin1String("steadyphoto");
- break;
- case QCamera::ExposureFireworks:
- sceneMode = QLatin1String("fireworks");
- break;
- case QCamera::ExposureParty:
- sceneMode = QLatin1String("party");
- break;
- case QCamera::ExposureCandlelight:
- sceneMode = QLatin1String("candlelight");
- break;
- case QCamera::ExposureBarcode:
- sceneMode = QLatin1String("barcode");
- break;
- default:
- sceneMode = QLatin1String("auto");
- mode = QCamera::ExposureAuto;
- break;
- }
-
- m_cameraSession->camera()->setSceneMode(sceneMode);
- exposureModeChanged(mode);
-}
-
-bool QAndroidCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
-{
- return m_supportedExposureModes.contains(mode);
-}
-
-void QAndroidCamera::setExposureCompensation(float bias)
-{
- if (exposureCompensation() == bias || !m_cameraSession || !m_cameraSession->camera())
- return;
-
- int biasIndex = qRound(bias / m_exposureCompensationStep);
- biasIndex = qBound(m_minExposureCompensationIndex, biasIndex, m_maxExposureCompensationIndex);
- float comp = biasIndex * m_exposureCompensationStep;
- m_cameraSession->camera()->setExposureCompensation(biasIndex);
- exposureCompensationChanged(comp);
-}
-
-bool QAndroidCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
-{
- return m_supportedWhiteBalanceModes.contains(mode);
-}
-
-void QAndroidCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
-{
- if (!m_cameraSession)
- return;
- auto *camera = m_cameraSession->camera();
- if (!camera)
- return;
- QString wb = m_supportedWhiteBalanceModes.value(mode, QString());
- if (!wb.isEmpty()) {
- camera->setWhiteBalance(wb);
- whiteBalanceModeChanged(mode);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediacapture/qandroidcamera_p.h b/src/multimedia/platform/android/mediacapture/qandroidcamera_p.h
deleted file mode 100644
index e97368698..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidcamera_p.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#ifndef QANDROIDCAMERACONTROL_H
-#define QANDROIDCAMERACONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformcamera_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidCameraSession;
-class QAndroidCameraVideoRendererControl;
-class QAndroidMediaCaptureSession;
-
-class QAndroidCamera : public QPlatformCamera
-{
- Q_OBJECT
-public:
- explicit QAndroidCamera(QCamera *camera);
- virtual ~QAndroidCamera();
-
- bool isActive() const override;
- void setActive(bool active) override;
-
- void setCamera(const QCameraDevice &camera) override;
- bool setCameraFormat(const QCameraFormat &format) override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *session) override;
-
- void setFocusMode(QCamera::FocusMode mode) override;
- bool isFocusModeSupported(QCamera::FocusMode mode) const override;
-
- void zoomTo(float factor, float rate) override;
-
- void setFlashMode(QCamera::FlashMode mode) override;
- bool isFlashModeSupported(QCamera::FlashMode mode) const override;
- bool isFlashReady() const override;
-
- void setTorchMode(QCamera::TorchMode mode) override;
- bool isTorchModeSupported(QCamera::TorchMode mode) const override;
-
- void setExposureMode(QCamera::ExposureMode mode) override;
- bool isExposureModeSupported(QCamera::ExposureMode mode) const override;
-
- void setExposureCompensation(float bias) override;
-
- bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override;
- void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override;
-
-private Q_SLOTS:
- void onCameraOpened();
- void setCameraFocusArea();
-
-private:
- void reactivateCameraSession();
-
- QAndroidCameraSession *m_cameraSession = nullptr;
- QAndroidMediaCaptureSession *m_service = nullptr;
-
- QList<QCamera::FocusMode> m_supportedFocusModes;
- bool m_continuousPictureFocusSupported = false;
- bool m_continuousVideoFocusSupported = false;
- bool m_focusPointSupported = false;
-
- float m_maximumZoom;
- QList<int> m_zoomRatios;
-
- QList<QCamera::ExposureMode> m_supportedExposureModes;
- int m_minExposureCompensationIndex;
- int m_maxExposureCompensationIndex;
- qreal m_exposureCompensationStep;
-
- bool isFlashSupported = false;
- bool isFlashAutoSupported = false;
- bool isTorchSupported = false;
- QCameraDevice m_cameraDev;
-
- QMap<QCamera::WhiteBalanceMode, QString> m_supportedWhiteBalanceModes;
- QCameraFormat m_cameraFormat;
-};
-
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDCAMERACONTROL_H
diff --git a/src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp b/src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp
deleted file mode 100644
index 38b819352..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidcamerasession.cpp
+++ /dev/null
@@ -1,794 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Ruslan Baratov
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidcamerasession_p.h"
-
-#include "androidcamera_p.h"
-#include "androidmultimediautils_p.h"
-#include "qandroidvideooutput_p.h"
-#include "qandroidmultimediautils_p.h"
-#include <qvideosink.h>
-#include <QtConcurrent/qtconcurrentrun.h>
-#include <qfile.h>
-#include <qguiapplication.h>
-#include <qscreen.h>
-#include <qdebug.h>
-#include <qvideoframe.h>
-#include <private/qplatformimagecapture_p.h>
-#include <private/qmemoryvideobuffer_p.h>
-#include <private/qcameradevice_p.h>
-#include <private/qmediastoragelocation_p.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(QList<QCameraDevice>, g_availableCameras)
-
-QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
- : QObject(parent)
- , m_selectedCamera(0)
- , m_camera(0)
- , m_videoOutput(0)
- , m_savedState(-1)
- , m_previewStarted(false)
- , m_lastImageCaptureId(0)
- , m_readyForCapture(false)
- , m_currentImageCaptureId(-1)
- , m_previewCallback(0)
- , m_keepActive(false)
-{
- if (qApp) {
- connect(qApp, &QGuiApplication::applicationStateChanged,
- this, &QAndroidCameraSession::onApplicationStateChanged);
-
- auto screen = qApp->primaryScreen();
- if (screen) {
- connect(screen, &QScreen::orientationChanged, this,
- &QAndroidCameraSession::updateOrientation);
- enableRotation();
- }
- }
-}
-
-QAndroidCameraSession::~QAndroidCameraSession()
-{
- close();
-}
-
-//void QAndroidCameraSession::setCaptureMode(QCamera::CaptureModes mode)
-//{
-// if (m_captureMode == mode || !isCaptureModeSupported(mode))
-// return;
-
-// m_captureMode = mode;
-// emit captureModeChanged(m_captureMode);
-
-// if (m_previewStarted && m_captureMode.testFlag(QCamera::CaptureStillImage))
-// applyResolution(m_actualImageSettings.resolution());
-//}
-
-void QAndroidCameraSession::setActive(bool active)
-{
- if (m_active == active)
- return;
-
- m_active = active;
-
- // If the application is inactive, the camera shouldn't be started. Save the desired state
- // instead and it will be set when the application becomes active.
- if (qApp->applicationState() == Qt::ApplicationActive)
- setActiveHelper(active);
- else
- m_savedState = active;
-
- emit activeChanged(m_active);
-}
-
-void QAndroidCameraSession::setActiveHelper(bool active)
-{
- if (!active) {
- stopPreview();
- close();
- } else {
- if (!m_camera && !open()) {
- emit error(QCamera::CameraError, QStringLiteral("Failed to open camera"));
- return;
- }
- startPreview();
- }
-}
-
-void QAndroidCameraSession::updateAvailableCameras()
-{
- g_availableCameras->clear();
-
- const int numCameras = AndroidCamera::getNumberOfCameras();
- for (int i = 0; i < numCameras; ++i) {
- QCameraDevicePrivate *info = new QCameraDevicePrivate;
- AndroidCamera::getCameraInfo(i, info);
-
- if (!info->id.isEmpty()) {
- AndroidCamera::getSupportedFormats(i, info->videoFormats);
- // Add supported picture sizes to the camera info
- AndroidCamera *camera = AndroidCamera::open(i);
- if (camera)
- info->photoResolutions = camera->getSupportedPictureSizes();
- delete camera;
- g_availableCameras->append(info->create());
- }
- }
-}
-
-const QList<QCameraDevice> &QAndroidCameraSession::availableCameras()
-{
- if (g_availableCameras->isEmpty())
- updateAvailableCameras();
-
- return *g_availableCameras;
-}
-
-bool QAndroidCameraSession::open()
-{
- close();
-
- m_camera = AndroidCamera::open(m_selectedCamera);
-
- if (m_camera) {
- connect(m_camera, &AndroidCamera::pictureExposed,
- this, &QAndroidCameraSession::onCameraPictureExposed);
- connect(m_camera, &AndroidCamera::lastPreviewFrameFetched,
- this, &QAndroidCameraSession::onLastPreviewFrameFetched,
- Qt::DirectConnection);
- connect(m_camera, &AndroidCamera::newPreviewFrame,
- this, &QAndroidCameraSession::onNewPreviewFrame,
- Qt::DirectConnection);
- connect(m_camera, &AndroidCamera::pictureCaptured,
- this, &QAndroidCameraSession::onCameraPictureCaptured);
- connect(m_camera, &AndroidCamera::previewStarted,
- this, &QAndroidCameraSession::onCameraPreviewStarted);
- connect(m_camera, &AndroidCamera::previewStopped,
- this, &QAndroidCameraSession::onCameraPreviewStopped);
- connect(m_camera, &AndroidCamera::previewFailedToStart,
- this, &QAndroidCameraSession::onCameraPreviewFailedToStart);
- connect(m_camera, &AndroidCamera::takePictureFailed,
- this, &QAndroidCameraSession::onCameraTakePictureFailed);
-
- if (m_camera->getPreviewFormat() != AndroidCamera::NV21)
- m_camera->setPreviewFormat(AndroidCamera::NV21);
-
- m_camera->notifyNewFrames(m_previewCallback);
-
- emit opened();
- setActive(true);
- }
-
- return m_camera != 0;
-}
-
-void QAndroidCameraSession::close()
-{
- if (!m_camera)
- return;
-
- stopPreview();
-
- m_readyForCapture = false;
- m_currentImageCaptureId = -1;
- m_currentImageCaptureFileName.clear();
- m_actualImageSettings = m_requestedImageSettings;
-
- m_camera->release();
- delete m_camera;
- m_camera = 0;
-
- setActive(false);
-}
-
-void QAndroidCameraSession::setVideoOutput(QAndroidVideoOutput *output)
-{
- if (m_videoOutput) {
- m_videoOutput->stop();
- m_videoOutput->reset();
- }
-
- if (output) {
- m_videoOutput = output;
- if (m_videoOutput->isReady()) {
- onVideoOutputReady(true);
- } else {
- connect(m_videoOutput, &QAndroidVideoOutput::readyChanged,
- this, &QAndroidCameraSession::onVideoOutputReady);
- }
- } else {
- m_videoOutput = 0;
- }
-}
-
-void QAndroidCameraSession::setCameraFormat(const QCameraFormat &format)
-{
- m_requestedFpsRange.min = format.minFrameRate();
- m_requestedFpsRange.max = format.maxFrameRate();
- m_requestedPixelFromat = AndroidCamera::AndroidImageFormatFromQtPixelFormat(format.pixelFormat());
-
- m_requestedImageSettings.setResolution(format.resolution());
- m_actualImageSettings.setResolution(format.resolution());
- if (m_readyForCapture)
- applyResolution(m_actualImageSettings.resolution());
-}
-
-void QAndroidCameraSession::applyResolution(const QSize &captureSize, bool restartPreview)
-{
- if (!m_camera)
- return;
-
- const QSize currentViewfinderResolution = m_camera->previewSize();
- const AndroidCamera::ImageFormat currentPreviewFormat = m_camera->getPreviewFormat();
- const AndroidCamera::FpsRange currentFpsRange = m_camera->getPreviewFpsRange();
-
- // -- adjust resolution
- QSize adjustedViewfinderResolution;
- const bool validCaptureSize = captureSize.width() > 0 && captureSize.height() > 0;
- if (validCaptureSize
- && m_camera->getPreferredPreviewSizeForVideo().isEmpty()) {
- // According to the Android doc, if getPreferredPreviewSizeForVideo() returns null, it means
- // the preview size cannot be different from the capture size
- adjustedViewfinderResolution = captureSize;
- } else {
- qreal captureAspectRatio = 0;
- if (validCaptureSize)
- captureAspectRatio = qreal(captureSize.width()) / qreal(captureSize.height());
-
- const QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes();
-
- if (validCaptureSize) {
- // search for viewfinder resolution with the same aspect ratio
- qreal minAspectDiff = 1;
- QSize closestResolution;
- for (int i = previewSizes.count() - 1; i >= 0; --i) {
- const QSize &size = previewSizes.at(i);
- const qreal sizeAspect = qreal(size.width()) / size.height();
- if (qFuzzyCompare(captureAspectRatio, sizeAspect)) {
- adjustedViewfinderResolution = size;
- break;
- } else if (minAspectDiff > qAbs(sizeAspect - captureAspectRatio)) {
- closestResolution = size;
- minAspectDiff = qAbs(sizeAspect - captureAspectRatio);
- }
- }
- if (!adjustedViewfinderResolution.isValid()) {
- qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio.");
- if (closestResolution.isValid()) {
- adjustedViewfinderResolution = closestResolution;
- qWarning("Using closest viewfinder resolution.");
- } else {
- return;
- }
- }
- } else {
- adjustedViewfinderResolution = previewSizes.last();
- }
- }
-
- // -- adjust pixel format
-
- AndroidCamera::ImageFormat adjustedPreviewFormat = m_requestedPixelFromat;
- if (adjustedPreviewFormat == AndroidCamera::UnknownImageFormat)
- adjustedPreviewFormat = AndroidCamera::NV21;
-
- // -- adjust FPS
-
- AndroidCamera::FpsRange adjustedFps = m_requestedFpsRange;;
- if (adjustedFps.min == 0 || adjustedFps.max == 0)
- adjustedFps = currentFpsRange;
-
- // -- Set values on camera
-
- if (currentViewfinderResolution != adjustedViewfinderResolution
- || currentPreviewFormat != adjustedPreviewFormat
- || currentFpsRange.min != adjustedFps.min
- || currentFpsRange.max != adjustedFps.max) {
-
- if (m_videoOutput) {
- // fix the resolution of output based on the orientation
- QSize outputResolution = adjustedViewfinderResolution;
- const int rotation = currentCameraRotation();
- if (rotation == 90 || rotation == 270)
- outputResolution.transpose();
- m_videoOutput->setVideoSize(outputResolution);
- }
-
- // if preview is started, we have to stop it first before changing its size
- if (m_previewStarted && restartPreview)
- m_camera->stopPreview();
-
- m_camera->setPreviewSize(adjustedViewfinderResolution);
- m_camera->setPreviewFormat(adjustedPreviewFormat);
- m_camera->setPreviewFpsRange(adjustedFps);
-
- // restart preview
- if (m_previewStarted && restartPreview)
- m_camera->startPreview();
- }
-}
-
-QList<QSize> QAndroidCameraSession::getSupportedPreviewSizes() const
-{
- return m_camera ? m_camera->getSupportedPreviewSizes() : QList<QSize>();
-}
-
-QList<QVideoFrameFormat::PixelFormat> QAndroidCameraSession::getSupportedPixelFormats() const
-{
- QList<QVideoFrameFormat::PixelFormat> formats;
-
- if (!m_camera)
- return formats;
-
- const QList<AndroidCamera::ImageFormat> nativeFormats = m_camera->getSupportedPreviewFormats();
-
- formats.reserve(nativeFormats.size());
-
- for (AndroidCamera::ImageFormat nativeFormat : nativeFormats) {
- QVideoFrameFormat::PixelFormat format = AndroidCamera::QtPixelFormatFromAndroidImageFormat(nativeFormat);
- if (format != QVideoFrameFormat::Format_Invalid)
- formats.append(format);
- }
-
- return formats;
-}
-
-QList<AndroidCamera::FpsRange> QAndroidCameraSession::getSupportedPreviewFpsRange() const
-{
- return m_camera ? m_camera->getSupportedPreviewFpsRange() : QList<AndroidCamera::FpsRange>();
-}
-
-
-bool QAndroidCameraSession::startPreview()
-{
- if (!m_camera || !m_videoOutput)
- return false;
-
- if (m_previewStarted)
- return true;
-
- if (!m_videoOutput->isReady())
- return true; // delay starting until the video output is ready
-
- Q_ASSERT(m_videoOutput->surfaceTexture() || m_videoOutput->surfaceHolder());
-
- if ((m_videoOutput->surfaceTexture() && !m_camera->setPreviewTexture(m_videoOutput->surfaceTexture()))
- || (m_videoOutput->surfaceHolder() && !m_camera->setPreviewDisplay(m_videoOutput->surfaceHolder())))
- return false;
-
- applyImageSettings();
- applyResolution(m_actualImageSettings.resolution());
-
- AndroidMultimediaUtils::enableOrientationListener(true);
-
- updateOrientation();
-
- m_camera->startPreview();
- m_previewStarted = true;
-
- return true;
-}
-
-void QAndroidCameraSession::stopPreview()
-{
- if (!m_camera || !m_previewStarted)
- return;
-
- AndroidMultimediaUtils::enableOrientationListener(false);
-
- m_camera->stopPreview();
- m_camera->setPreviewSize(QSize());
- m_camera->setPreviewTexture(0);
- m_camera->setPreviewDisplay(0);
-
- if (m_videoOutput) {
- m_videoOutput->stop();
- m_videoOutput->reset();
- }
- m_previewStarted = false;
-}
-
-void QAndroidCameraSession::setImageSettings(const QImageEncoderSettings &settings)
-{
- if (m_requestedImageSettings == settings)
- return;
-
- m_requestedImageSettings = m_actualImageSettings = settings;
-
- applyImageSettings();
-
- if (m_readyForCapture)
- applyResolution(m_actualImageSettings.resolution());
-}
-
-void QAndroidCameraSession::enableRotation()
-{
- m_rotationEnabled = true;
-}
-
-void QAndroidCameraSession::disableRotation()
-{
- m_rotationEnabled = false;
-}
-
-void QAndroidCameraSession::updateOrientation()
-{
- if (!m_camera || !m_rotationEnabled)
- return;
-
- m_camera->setDisplayOrientation(currentCameraRotation());
- applyResolution(m_actualImageSettings.resolution());
-}
-
-
-int QAndroidCameraSession::currentCameraRotation() const
-{
- if (!m_camera)
- return 0;
-
- auto screen = QGuiApplication::primaryScreen();
- auto screenOrientation = screen->orientation();
- if (screenOrientation == Qt::PrimaryOrientation)
- screenOrientation = screen->primaryOrientation();
-
- int deviceOrientation = 0;
- switch (screenOrientation) {
- case Qt::PrimaryOrientation:
- case Qt::PortraitOrientation:
- break;
- case Qt::LandscapeOrientation:
- deviceOrientation = 90;
- break;
- case Qt::InvertedPortraitOrientation:
- deviceOrientation = 180;
- break;
- case Qt::InvertedLandscapeOrientation:
- deviceOrientation = 270;
- break;
- }
-
- int nativeCameraOrientation = m_camera->getNativeOrientation();
-
- int rotation;
- // subtract natural camera orientation and physical device orientation
- if (m_camera->getFacing() == AndroidCamera::CameraFacingFront) {
- rotation = (nativeCameraOrientation + deviceOrientation) % 360;
- rotation = (360 - rotation) % 360; // compensate the mirror
- } else { // back-facing camera
- rotation = (nativeCameraOrientation - deviceOrientation + 360) % 360;
- }
- return rotation;
-}
-
-void QAndroidCameraSession::setPreviewFormat(AndroidCamera::ImageFormat format)
-{
- if (format == AndroidCamera::UnknownImageFormat)
- return;
-
- m_camera->setPreviewFormat(format);
-}
-
-void QAndroidCameraSession::setPreviewCallback(PreviewCallback *callback)
-{
- m_videoFrameCallbackMutex.lock();
- m_previewCallback = callback;
- if (m_camera)
- m_camera->notifyNewFrames(m_previewCallback);
- m_videoFrameCallbackMutex.unlock();
-}
-
-void QAndroidCameraSession::applyImageSettings()
-{
- if (!m_camera)
- return;
-
- // only supported format right now.
- m_actualImageSettings.setFormat(QImageCapture::JPEG);
-
- const QSize requestedResolution = m_requestedImageSettings.resolution();
- const QList<QSize> supportedResolutions = m_camera->getSupportedPictureSizes();
- if (!requestedResolution.isValid()) {
- // use the highest supported one
- m_actualImageSettings.setResolution(supportedResolutions.last());
- } else if (!supportedResolutions.contains(requestedResolution)) {
- // if the requested resolution is not supported, find the closest one
- int reqPixelCount = requestedResolution.width() * requestedResolution.height();
- QList<int> supportedPixelCounts;
- for (int i = 0; i < supportedResolutions.size(); ++i) {
- const QSize &s = supportedResolutions.at(i);
- supportedPixelCounts.append(s.width() * s.height());
- }
- int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
- m_actualImageSettings.setResolution(supportedResolutions.at(closestIndex));
- }
- m_camera->setPictureSize(m_actualImageSettings.resolution());
-
- int jpegQuality = 100;
- switch (m_requestedImageSettings.quality()) {
- case QImageCapture::VeryLowQuality:
- jpegQuality = 20;
- break;
- case QImageCapture::LowQuality:
- jpegQuality = 40;
- break;
- case QImageCapture::NormalQuality:
- jpegQuality = 60;
- break;
- case QImageCapture::HighQuality:
- jpegQuality = 80;
- break;
- case QImageCapture::VeryHighQuality:
- jpegQuality = 100;
- break;
- }
- m_camera->setJpegQuality(jpegQuality);
-}
-
-bool QAndroidCameraSession::isReadyForCapture() const
-{
- return isActive() && m_readyForCapture;
-}
-
-void QAndroidCameraSession::setReadyForCapture(bool ready)
-{
- if (m_readyForCapture == ready)
- return;
-
- m_readyForCapture = ready;
- emit readyForCaptureChanged(ready);
-}
-
-int QAndroidCameraSession::capture(const QString &fileName)
-{
- ++m_lastImageCaptureId;
-
- if (!isReadyForCapture()) {
- emit imageCaptureError(m_lastImageCaptureId, QImageCapture::NotReadyError,
- QPlatformImageCapture::msgCameraNotReady());
- return m_lastImageCaptureId;
- }
-
- setReadyForCapture(false);
-
- m_currentImageCaptureId = m_lastImageCaptureId;
- m_currentImageCaptureFileName = fileName;
-
- applyImageSettings();
- applyResolution(m_actualImageSettings.resolution());
-
- // adjust picture rotation depending on the device orientation
- m_camera->setRotation(currentCameraRotation());
-
- m_camera->takePicture();
-
- return m_lastImageCaptureId;
-}
-
-void QAndroidCameraSession::onCameraTakePictureFailed()
-{
- emit imageCaptureError(m_currentImageCaptureId, QImageCapture::ResourceError,
- tr("Failed to capture image"));
-
- // Preview needs to be restarted and the preview call back must be setup again
- m_camera->startPreview();
-}
-
-void QAndroidCameraSession::onCameraPictureExposed()
-{
- if (!m_camera)
- return;
-
- emit imageExposed(m_currentImageCaptureId);
- m_camera->fetchLastPreviewFrame();
-}
-
-void QAndroidCameraSession::onLastPreviewFrameFetched(const QVideoFrame &frame)
-{
- if (!m_camera)
- return;
-
- (void) QtConcurrent::run(&QAndroidCameraSession::processPreviewImage, this,
- m_currentImageCaptureId,
- frame,
- m_camera->getRotation());
-}
-
-void QAndroidCameraSession::processPreviewImage(int id, const QVideoFrame &frame, int rotation)
-{
- // Preview display of front-facing cameras is flipped horizontally, but the frame data
- // we get here is not. Flip it ourselves if the camera is front-facing to match what the user
- // sees on the viewfinder.
- QTransform transform;
- if (m_camera->getFacing() == AndroidCamera::CameraFacingFront)
- transform.scale(-1, 1);
- transform.rotate(rotation);
-
- emit imageCaptured(id, frame.toImage().transformed(transform));
-}
-
-void QAndroidCameraSession::onNewPreviewFrame(const QVideoFrame &frame)
-{
- if (!m_camera)
- return;
-
- m_videoFrameCallbackMutex.lock();
-
- if (m_previewCallback)
- m_previewCallback->onFrameAvailable(frame);
-
- m_videoFrameCallbackMutex.unlock();
-}
-
-void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data)
-{
- // Loading and saving the captured image can be slow, do it in a separate thread
- (void) QtConcurrent::run(&QAndroidCameraSession::processCapturedImage, this,
- m_currentImageCaptureId,
- data,
- m_actualImageSettings.resolution(),
- /* captureToBuffer = */ false,
- m_currentImageCaptureFileName);
-
- // Preview needs to be restarted after taking a picture
- if (m_camera)
- m_camera->startPreview();
-}
-
-void QAndroidCameraSession::onCameraPreviewStarted()
-{
- setReadyForCapture(true);
-}
-
-void QAndroidCameraSession::onCameraPreviewFailedToStart()
-{
- if (isActive()) {
- Q_EMIT error(QCamera::CameraError, tr("Camera preview failed to start."));
-
- AndroidMultimediaUtils::enableOrientationListener(false);
- m_camera->setPreviewSize(QSize());
- m_camera->setPreviewTexture(0);
- if (m_videoOutput) {
- m_videoOutput->stop();
- m_videoOutput->reset();
- }
- m_previewStarted = false;
-
- setActive(false);
- setReadyForCapture(false);
- }
-}
-
-void QAndroidCameraSession::onCameraPreviewStopped()
-{
- if (!m_previewStarted)
- setActive(false);
- setReadyForCapture(false);
-}
-
-void QAndroidCameraSession::processCapturedImage(int id,
- const QByteArray &data,
- const QSize &resolution,
- bool captureToBuffer,
- const QString &fileName)
-{
-
-
- if (!captureToBuffer) {
- const QString actualFileName = QMediaStorageLocation::generateFileName(fileName, QStandardPaths::PicturesLocation, QLatin1String("jpg"));
-
- QFile file(actualFileName);
- if (file.open(QFile::WriteOnly)) {
- if (file.write(data) == data.size()) {
- // if the picture is saved into the standard picture location, register it
- // with the Android media scanner so it appears immediately in apps
- // such as the gallery.
- if (fileName.isEmpty() || QFileInfo(fileName).isRelative())
- AndroidMultimediaUtils::registerMediaFile(actualFileName);
-
- emit imageSaved(id, actualFileName);
- } else {
- emit imageCaptureError(id, QImageCapture::OutOfSpaceError, file.errorString());
- }
- } else {
- const QString errorMessage = tr("Could not open destination file: %1").arg(actualFileName);
- emit imageCaptureError(id, QImageCapture::ResourceError, errorMessage);
- }
- } else {
- QVideoFrame frame(new QMemoryVideoBuffer(data, -1), QVideoFrameFormat(resolution, QVideoFrameFormat::Format_Jpeg));
- emit imageAvailable(id, frame);
- }
-}
-
-void QAndroidCameraSession::onVideoOutputReady(bool ready)
-{
- if (ready && m_active)
- startPreview();
-}
-
-void QAndroidCameraSession::onApplicationStateChanged(Qt::ApplicationState state)
-{
- switch (state) {
- case Qt::ApplicationInactive:
- if (!m_keepActive && m_active) {
- m_savedState = m_active;
- close();
- setActive(false);
- }
- break;
- case Qt::ApplicationActive:
- if (m_savedState != -1) {
- setActiveHelper(m_savedState);
- m_savedState = -1;
- }
- break;
- default:
- break;
- }
-}
-
-bool QAndroidCameraSession::requestCameraPermission()
-{
- m_keepActive = true;
- const bool result = qt_androidRequestCameraPermission();
- m_keepActive = false;
- return result;
-}
-
-void QAndroidCameraSession::setVideoSink(QVideoSink *sink)
-{
- if (m_sink == sink)
- return;
-
- m_sink = sink;
-
- if (m_sink) {
- delete m_textureOutput;
- m_textureOutput = nullptr;
-
- m_textureOutput = new QAndroidTextureVideoOutput(this);
- m_textureOutput->setSurface(m_sink);
- }
-
- setVideoOutput(m_textureOutput);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediacapture/qandroidcamerasession_p.h b/src/multimedia/platform/android/mediacapture/qandroidcamerasession_p.h
deleted file mode 100644
index fc3efef26..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidcamerasession_p.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Ruslan Baratov
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDCAMERASESSION_H
-#define QANDROIDCAMERASESSION_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 <qcamera.h>
-#include <QImageCapture>
-#include <QSet>
-#include <QMutex>
-#include <private/qplatformimagecapture_p.h>
-#include "androidcamera_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidVideoOutput;
-class QAndroidTextureVideoOutput ;
-class QVideoSink;
-
-class QAndroidCameraSession : public QObject
-{
- Q_OBJECT
-public:
- explicit QAndroidCameraSession(QObject *parent = 0);
- ~QAndroidCameraSession();
-
- static const QList<QCameraDevice> &availableCameras();
-
- void setSelectedCameraId(int cameraId) { m_selectedCamera = cameraId; }
- int getSelectedCameraId() { return m_selectedCamera; }
- AndroidCamera *camera() const { return m_camera; }
-
- bool isActive() const { return m_active; }
- void setActive(bool active);
-
- void applyResolution(const QSize &captureSize = QSize(), bool restartPreview = true);
-
- QAndroidVideoOutput *videoOutput() const { return m_videoOutput; }
- void setVideoOutput(QAndroidVideoOutput *output);
-
- void setCameraFormat(const QCameraFormat &format);
-
- QList<QSize> getSupportedPreviewSizes() const;
- QList<QVideoFrameFormat::PixelFormat> getSupportedPixelFormats() const;
- QList<AndroidCamera::FpsRange> getSupportedPreviewFpsRange() const;
-
- QImageEncoderSettings imageSettings() const { return m_actualImageSettings; }
- void setImageSettings(const QImageEncoderSettings &settings);
-
- bool isReadyForCapture() const;
- void setReadyForCapture(bool ready);
- int capture(const QString &fileName);
-
- int currentCameraRotation() const;
-
- void setPreviewFormat(AndroidCamera::ImageFormat format);
-
- struct PreviewCallback
- {
- virtual void onFrameAvailable(const QVideoFrame &frame) = 0;
- };
- void setPreviewCallback(PreviewCallback *callback);
- bool requestCameraPermission();
-
- void setVideoSink(QVideoSink *surface);
-
- void disableRotation();
- void enableRotation();
-
-Q_SIGNALS:
- void activeChanged(bool);
- void error(int error, const QString &errorString);
- void opened();
-
- void readyForCaptureChanged(bool);
- void imageExposed(int id);
- void imageCaptured(int id, const QImage &preview);
- void imageMetadataAvailable(int id, const QMediaMetaData &key);
- void imageAvailable(int id, const QVideoFrame &buffer);
- void imageSaved(int id, const QString &fileName);
- void imageCaptureError(int id, int error, const QString &errorString);
-
-private Q_SLOTS:
- void onVideoOutputReady(bool ready);
- void updateOrientation();
-
- void onApplicationStateChanged(Qt::ApplicationState state);
-
- void onCameraTakePictureFailed();
- void onCameraPictureExposed();
- void onCameraPictureCaptured(const QByteArray &data);
- void onLastPreviewFrameFetched(const QVideoFrame &frame);
- void onNewPreviewFrame(const QVideoFrame &frame);
- void onCameraPreviewStarted();
- void onCameraPreviewFailedToStart();
- void onCameraPreviewStopped();
-
-private:
- static void updateAvailableCameras();
-
- bool open();
- void close();
-
- bool startPreview();
- void stopPreview();
-
- void applyImageSettings();
-
- void processPreviewImage(int id, const QVideoFrame &frame, int rotation);
- void processCapturedImage(int id,
- const QByteArray &data,
- const QSize &resolution,
- bool captureToBuffer,
- const QString &fileName);
-
- void setActiveHelper(bool active);
-
- int m_selectedCamera;
- AndroidCamera *m_camera;
- QAndroidVideoOutput *m_videoOutput;
-
- bool m_active = false;
- int m_savedState = -1;
- bool m_previewStarted;
-
- bool m_rotationEnabled = false;
-
- QVideoSink *m_sink = nullptr;
- QAndroidTextureVideoOutput *m_textureOutput = nullptr;
-
- QImageEncoderSettings m_requestedImageSettings;
- QImageEncoderSettings m_actualImageSettings;
- AndroidCamera::FpsRange m_requestedFpsRange;
- AndroidCamera::ImageFormat m_requestedPixelFromat;
-
- int m_lastImageCaptureId;
- bool m_readyForCapture;
- int m_currentImageCaptureId;
- QString m_currentImageCaptureFileName;
-
- QMutex m_videoFrameCallbackMutex;
- PreviewCallback *m_previewCallback;
- bool m_keepActive;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDCAMERASESSION_H
diff --git a/src/multimedia/platform/android/mediacapture/qandroidcapturesession.cpp b/src/multimedia/platform/android/mediacapture/qandroidcapturesession.cpp
deleted file mode 100644
index 913a75ee9..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidcapturesession.cpp
+++ /dev/null
@@ -1,472 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidcapturesession_p.h"
-
-#include "androidcamera_p.h"
-#include "qandroidcamerasession_p.h"
-#include "androidmediaplayer_p.h"
-#include "androidmultimediautils_p.h"
-#include "qandroidmultimediautils_p.h"
-#include "qandroidvideooutput_p.h"
-#include "qandroidglobal_p.h"
-#include <private/qplatformaudioinput_p.h>
-#include <private/qplatformaudiooutput_p.h>
-#include <private/qmediarecorder_p.h>
-#include <private/qmediastoragelocation_p.h>
-#include <QtCore/qmimetype.h>
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-QAndroidCaptureSession::QAndroidCaptureSession()
- : QObject()
- , m_mediaRecorder(0)
- , m_cameraSession(0)
- , m_duration(0)
- , m_state(QMediaRecorder::StoppedState)
- , m_outputFormat(AndroidMediaRecorder::DefaultOutputFormat)
- , m_audioEncoder(AndroidMediaRecorder::DefaultAudioEncoder)
- , m_videoEncoder(AndroidMediaRecorder::DefaultVideoEncoder)
-{
- m_notifyTimer.setInterval(1000);
- connect(&m_notifyTimer, &QTimer::timeout, this, &QAndroidCaptureSession::updateDuration);
-}
-
-QAndroidCaptureSession::~QAndroidCaptureSession()
-{
- stop();
- delete m_mediaRecorder;
-}
-
-void QAndroidCaptureSession::setCameraSession(QAndroidCameraSession *cameraSession)
-{
- if (m_cameraSession) {
- disconnect(m_connOpenCamera);
- disconnect(m_connActiveChangedCamera);
- }
-
- m_cameraSession = cameraSession;
- if (m_cameraSession) {
- m_connOpenCamera = connect(cameraSession, &QAndroidCameraSession::opened,
- this, &QAndroidCaptureSession::onCameraOpened);
- m_connActiveChangedCamera = connect(cameraSession, &QAndroidCameraSession::activeChanged,
- this, [this](bool isActive) {
- if (!isActive)
- stop();
- });
-
- // It requests permission on setAudioInput instead of on start because asking for
- // permission can pause the activity and android can release the surface referenced
- // by camera crashing the app when mediaRecorder tries to use it
- // TODO: https://bugreports.qt.io/browse/QTBUG-96346
- m_cameraSession->requestCameraPermission();
- }
-}
-
-void QAndroidCaptureSession::setAudioInput(QPlatformAudioInput *input)
-{
- m_audioInput = input;
-
- // It requests permission on setAudioInput instead of on start because asking for
- // permission can pause the activity and android can release the surface referenced
- // by camera crashing the app when mediaRecorder tries to use it
- // TODO: https://bugreports.qt.io/browse/QTBUG-96346
- qt_androidRequestRecordingPermission();
-}
-
-void QAndroidCaptureSession::setAudioOutput(QPlatformAudioOutput *output)
-{
- if (m_audioOutput == output)
- return;
-
- m_audioOutput = output;
-
- if (m_audioOutput)
- AndroidMediaPlayer::setAudioOutput(m_audioOutput->device.id());
-}
-
-QMediaRecorder::RecorderState QAndroidCaptureSession::state() const
-{
- return m_state;
-}
-
-void QAndroidCaptureSession::start(QMediaEncoderSettings &settings, const QUrl &outputLocation)
-{
- if (m_state == QMediaRecorder::RecordingState)
- return;
-
- if (m_mediaRecorder) {
- m_mediaRecorder->release();
- delete m_mediaRecorder;
- m_mediaRecorder = nullptr;
- }
-
- if (!m_cameraSession && !m_audioInput) {
- Q_EMIT error(QMediaRecorder::ResourceError, QLatin1String("No devices are set"));
- return;
- }
-
- applySettings(settings);
-
- m_mediaRecorder = new AndroidMediaRecorder;
- connect(m_mediaRecorder, &AndroidMediaRecorder::error, this, &QAndroidCaptureSession::onError);
- connect(m_mediaRecorder, &AndroidMediaRecorder::info, this, &QAndroidCaptureSession::onInfo);
-
- // Set audio/video sources
- if (m_cameraSession) {
- if (!qt_androidCheckCameraPermission()) {
- Q_EMIT error(QMediaRecorder::ResourceError, QLatin1String("Camera permission denied."));
- return;
- }
-
- m_cameraSession->camera()->stopPreviewSynchronous();
- m_cameraSession->applyResolution(settings.videoResolution(), false);
- m_cameraSession->camera()->unlock();
- m_mediaRecorder->setCamera(m_cameraSession->camera());
- m_mediaRecorder->setAudioSource(AndroidMediaRecorder::Camcorder);
- m_mediaRecorder->setVideoSource(AndroidMediaRecorder::Camera);
- }
-
- if (m_audioInput) {
- if (!qt_androidCheckMicrophonePermission()) {
- Q_EMIT error(QMediaRecorder::ResourceError,
- QLatin1String("Microphone permission denied."));
- return;
- }
-
- m_mediaRecorder->setAudioInput(m_audioInput->device.id());
- if (!m_mediaRecorder->isAudioSourceSet())
- m_mediaRecorder->setAudioSource(AndroidMediaRecorder::DefaultAudioSource);
- }
-
- // Set output format
- m_mediaRecorder->setOutputFormat(m_outputFormat);
-
- // Set audio encoder settings
- m_mediaRecorder->setAudioChannels(settings.audioChannelCount());
- m_mediaRecorder->setAudioEncodingBitRate(settings.audioBitRate());
- m_mediaRecorder->setAudioSamplingRate(settings.audioSampleRate());
- m_mediaRecorder->setAudioEncoder(m_audioEncoder);
-
- // Set video encoder settings
- if (m_cameraSession) {
- m_mediaRecorder->setVideoSize(settings.videoResolution());
- m_mediaRecorder->setVideoFrameRate(qRound(settings.videoFrameRate()));
- m_mediaRecorder->setVideoEncodingBitRate(settings.videoBitRate());
- m_mediaRecorder->setVideoEncoder(m_videoEncoder);
-
- m_mediaRecorder->setOrientationHint(m_cameraSession->currentCameraRotation());
- }
-
- QString extension = settings.mimeType().preferredSuffix();
-
- // Set output file
- auto location = outputLocation.toString(QUrl::PreferLocalFile);
- auto filePath = QMediaStorageLocation::generateFileName(
- location, m_cameraSession ? QStandardPaths::MoviesLocation : QStandardPaths::MusicLocation, extension);
-
- m_usedOutputLocation = QUrl::fromLocalFile(filePath);
- m_outputLocationIsStandard = location.isEmpty() || QFileInfo(location).isRelative();
- m_mediaRecorder->setOutputFile(filePath);
-
- // Even though the Android doc explicitly says that calling MediaRecorder.setPreviewDisplay()
- // is not necessary when the Camera already has a Surface, it doesn't actually work on some
- // devices. For example on the Samsung Galaxy Tab 2, the camera server dies after prepare()
- // and start() if MediaRecorder.setPreviewDispaly() is not called.
- if (m_cameraSession) {
- // When using a SurfaceTexture, we need to pass a new one to the MediaRecorder, not the same
- // one that is set on the Camera or it will crash, hence the reset().
- m_cameraSession->videoOutput()->reset();
- if (m_cameraSession->videoOutput()->surfaceTexture())
- m_mediaRecorder->setSurfaceTexture(m_cameraSession->videoOutput()->surfaceTexture());
- else if (m_cameraSession->videoOutput()->surfaceHolder())
- m_mediaRecorder->setSurfaceHolder(m_cameraSession->videoOutput()->surfaceHolder());
-
- m_cameraSession->disableRotation();
- }
-
- if (!m_mediaRecorder->prepare()) {
- emit error(QMediaRecorder::FormatError, QLatin1String("Unable to prepare the media recorder."));
- if (m_cameraSession)
- restartViewfinder();
- return;
- }
-
- if (!m_mediaRecorder->start()) {
- emit error(QMediaRecorder::FormatError,
- QMediaRecorderPrivate::msgFailedStartRecording());
- if (m_cameraSession)
- restartViewfinder();
- return;
- }
-
- m_elapsedTime.start();
- m_notifyTimer.start();
- updateDuration();
-
- if (m_cameraSession) {
- m_cameraSession->setReadyForCapture(false);
-
- // Preview frame callback is cleared when setting up the camera with the media recorder.
- // We need to reset it.
- m_cameraSession->camera()->setupPreviewFrameCallback();
- }
-
- m_state = QMediaRecorder::RecordingState;
- emit stateChanged(m_state);
-}
-
-void QAndroidCaptureSession::stop(bool error)
-{
- if (m_state == QMediaRecorder::StoppedState || m_mediaRecorder == 0)
- return;
-
- m_mediaRecorder->stop();
- m_notifyTimer.stop();
- updateDuration();
- m_elapsedTime.invalidate();
- m_mediaRecorder->release();
- delete m_mediaRecorder;
- m_mediaRecorder = 0;
-
- if (m_cameraSession && m_cameraSession->isActive()) {
- // Viewport needs to be restarted after recording
- restartViewfinder();
- }
-
- if (!error) {
- // if the media is saved into the standard media location, register it
- // with the Android media scanner so it appears immediately in apps
- // such as the gallery.
- if (m_outputLocationIsStandard)
- AndroidMultimediaUtils::registerMediaFile(m_usedOutputLocation.toLocalFile());
-
- emit actualLocationChanged(m_usedOutputLocation);
- }
-
- m_state = QMediaRecorder::StoppedState;
- emit stateChanged(m_state);
-}
-
-qint64 QAndroidCaptureSession::duration() const
-{
- return m_duration;
-}
-
-void QAndroidCaptureSession::applySettings(QMediaEncoderSettings &settings)
-{
- // container settings
- auto fileFormat = settings.mediaFormat().fileFormat();
- if (!m_cameraSession && fileFormat == QMediaFormat::AAC) {
- m_outputFormat = AndroidMediaRecorder::AAC_ADTS;
- } else if (fileFormat == QMediaFormat::Ogg) {
- m_outputFormat = AndroidMediaRecorder::OGG;
- } else if (fileFormat == QMediaFormat::WebM) {
- m_outputFormat = AndroidMediaRecorder::WEBM;
-// } else if (fileFormat == QLatin1String("3gp")) {
-// m_outputFormat = AndroidMediaRecorder::THREE_GPP;
- } else {
- // fallback to MP4
- m_outputFormat = AndroidMediaRecorder::MPEG_4;
- }
-
- // audio settings
- if (settings.audioChannelCount() <= 0)
- settings.setAudioChannelCount(m_defaultSettings.audioChannels);
- if (settings.audioBitRate() <= 0)
- settings.setAudioBitRate(m_defaultSettings.audioBitRate);
- if (settings.audioSampleRate() <= 0)
- settings.setAudioSampleRate(m_defaultSettings.audioSampleRate);
-
- if (settings.audioCodec() == QMediaFormat::AudioCodec::AAC)
- m_audioEncoder = AndroidMediaRecorder::AAC;
- else if (settings.audioCodec() == QMediaFormat::AudioCodec::Opus)
- m_audioEncoder = AndroidMediaRecorder::OPUS;
- else if (settings.audioCodec() == QMediaFormat::AudioCodec::Vorbis)
- m_audioEncoder = AndroidMediaRecorder::VORBIS;
- else
- m_audioEncoder = m_defaultSettings.audioEncoder;
-
-
- // video settings
- if (m_cameraSession && m_cameraSession->camera()) {
- if (settings.videoResolution().isEmpty()) {
- settings.setVideoResolution(m_defaultSettings.videoResolution);
- } else if (!m_supportedResolutions.contains(settings.videoResolution())) {
- // if the requested resolution is not supported, find the closest one
- QSize reqSize = settings.videoResolution();
- int reqPixelCount = reqSize.width() * reqSize.height();
- QList<int> supportedPixelCounts;
- for (int i = 0; i < m_supportedResolutions.size(); ++i) {
- const QSize &s = m_supportedResolutions.at(i);
- supportedPixelCounts.append(s.width() * s.height());
- }
- int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
- settings.setVideoResolution(m_supportedResolutions.at(closestIndex));
- }
-
- if (settings.videoFrameRate() <= 0)
- settings.setVideoFrameRate(m_defaultSettings.videoFrameRate);
- if (settings.videoBitRate() <= 0)
- settings.setVideoBitRate(m_defaultSettings.videoBitRate);
-
- if (settings.videoCodec() == QMediaFormat::VideoCodec::H264)
- m_videoEncoder = AndroidMediaRecorder::H264;
- else if (settings.videoCodec() == QMediaFormat::VideoCodec::H265)
- m_videoEncoder = AndroidMediaRecorder::HEVC;
- else if (settings.videoCodec() == QMediaFormat::VideoCodec::MPEG4)
- m_videoEncoder = AndroidMediaRecorder::MPEG_4_SP;
- else
- m_videoEncoder = m_defaultSettings.videoEncoder;
-
- }
-}
-
-void QAndroidCaptureSession::restartViewfinder()
-{
- if (!m_cameraSession)
- return;
- m_cameraSession->camera()->reconnect();
-
- // This is not necessary on most devices, but it crashes on some if we don't stop the
- // preview and reset the preview display on the camera when recording is over.
- m_cameraSession->camera()->stopPreviewSynchronous();
- m_cameraSession->videoOutput()->reset();
- if (m_cameraSession->videoOutput()->surfaceTexture())
- m_cameraSession->camera()->setPreviewTexture(m_cameraSession->videoOutput()->surfaceTexture());
- else if (m_cameraSession->videoOutput()->surfaceHolder())
- m_cameraSession->camera()->setPreviewDisplay(m_cameraSession->videoOutput()->surfaceHolder());
-
- m_cameraSession->camera()->startPreview();
- m_cameraSession->setReadyForCapture(true);
- m_cameraSession->enableRotation();
-}
-
-void QAndroidCaptureSession::updateDuration()
-{
- if (m_elapsedTime.isValid())
- m_duration = m_elapsedTime.elapsed();
-
- emit durationChanged(m_duration);
-}
-
-void QAndroidCaptureSession::onCameraOpened()
-{
- m_supportedResolutions.clear();
- m_supportedFramerates.clear();
-
- // get supported resolutions from predefined profiles
- for (int i = 0; i < 8; ++i) {
- CaptureProfile profile = getProfile(i);
- if (!profile.isNull) {
- if (i == AndroidCamcorderProfile::QUALITY_HIGH)
- m_defaultSettings = profile;
-
- if (!m_supportedResolutions.contains(profile.videoResolution))
- m_supportedResolutions.append(profile.videoResolution);
- if (!m_supportedFramerates.contains(profile.videoFrameRate))
- m_supportedFramerates.append(profile.videoFrameRate);
- }
- }
-
- std::sort(m_supportedResolutions.begin(), m_supportedResolutions.end(), qt_sizeLessThan);
- std::sort(m_supportedFramerates.begin(), m_supportedFramerates.end());
-}
-
-QAndroidCaptureSession::CaptureProfile QAndroidCaptureSession::getProfile(int id)
-{
- CaptureProfile profile;
- const bool hasProfile = AndroidCamcorderProfile::hasProfile(m_cameraSession->camera()->cameraId(),
- AndroidCamcorderProfile::Quality(id));
-
- if (hasProfile) {
- AndroidCamcorderProfile camProfile = AndroidCamcorderProfile::get(m_cameraSession->camera()->cameraId(),
- AndroidCamcorderProfile::Quality(id));
-
- profile.outputFormat = AndroidMediaRecorder::OutputFormat(camProfile.getValue(AndroidCamcorderProfile::fileFormat));
- profile.audioEncoder = AndroidMediaRecorder::AudioEncoder(camProfile.getValue(AndroidCamcorderProfile::audioCodec));
- profile.audioBitRate = camProfile.getValue(AndroidCamcorderProfile::audioBitRate);
- profile.audioChannels = camProfile.getValue(AndroidCamcorderProfile::audioChannels);
- profile.audioSampleRate = camProfile.getValue(AndroidCamcorderProfile::audioSampleRate);
- profile.videoEncoder = AndroidMediaRecorder::VideoEncoder(camProfile.getValue(AndroidCamcorderProfile::videoCodec));
- profile.videoBitRate = camProfile.getValue(AndroidCamcorderProfile::videoBitRate);
- profile.videoFrameRate = camProfile.getValue(AndroidCamcorderProfile::videoFrameRate);
- profile.videoResolution = QSize(camProfile.getValue(AndroidCamcorderProfile::videoFrameWidth),
- camProfile.getValue(AndroidCamcorderProfile::videoFrameHeight));
-
- if (profile.outputFormat == AndroidMediaRecorder::MPEG_4)
- profile.outputFileExtension = QStringLiteral("mp4");
- else if (profile.outputFormat == AndroidMediaRecorder::THREE_GPP)
- profile.outputFileExtension = QStringLiteral("3gp");
- else if (profile.outputFormat == AndroidMediaRecorder::AMR_NB_Format)
- profile.outputFileExtension = QStringLiteral("amr");
- else if (profile.outputFormat == AndroidMediaRecorder::AMR_WB_Format)
- profile.outputFileExtension = QStringLiteral("awb");
-
- profile.isNull = false;
- }
-
- return profile;
-}
-
-void QAndroidCaptureSession::onError(int what, int extra)
-{
- Q_UNUSED(what);
- Q_UNUSED(extra);
- stop(true);
- emit error(QMediaRecorder::ResourceError, QLatin1String("Unknown error."));
-}
-
-void QAndroidCaptureSession::onInfo(int what, int extra)
-{
- Q_UNUSED(extra);
- if (what == 800) {
- // MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
- stop();
- emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum duration reached."));
- } else if (what == 801) {
- // MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
- stop();
- emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum file size reached."));
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediacapture/qandroidcapturesession_p.h b/src/multimedia/platform/android/mediacapture/qandroidcapturesession_p.h
deleted file mode 100644
index 16b3c8481..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidcapturesession_p.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDCAPTURESESSION_H
-#define QANDROIDCAPTURESESSION_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 <qmediarecorder.h>
-#include <qurl.h>
-#include <qelapsedtimer.h>
-#include <qtimer.h>
-#include "androidmediarecorder_p.h"
-#include "qandroidmediaencoder_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QAudioInput;
-class QAndroidCameraSession;
-
-class QAndroidCaptureSession : public QObject
-{
- Q_OBJECT
-public:
- explicit QAndroidCaptureSession();
- ~QAndroidCaptureSession();
-
- QList<QSize> supportedResolutions() const { return m_supportedResolutions; }
- QList<qreal> supportedFrameRates() const { return m_supportedFramerates; }
-
- void setCameraSession(QAndroidCameraSession *cameraSession = 0);
- void setAudioInput(QPlatformAudioInput *input);
- void setAudioOutput(QPlatformAudioOutput *output);
-
- QMediaRecorder::RecorderState state() const;
-
- void start(QMediaEncoderSettings &settings, const QUrl &outputLocation);
- void stop(bool error = false);
-
- qint64 duration() const;
-
- QMediaEncoderSettings encoderSettings() { return m_encoderSettings; }
-
- void setMediaEncoder(QAndroidMediaEncoder *encoder) { m_mediaEncoder = encoder; }
-
- void stateChanged(QMediaRecorder::RecorderState state) {
- if (m_mediaEncoder)
- m_mediaEncoder->stateChanged(state);
- }
- void durationChanged(qint64 position)
- {
- if (m_mediaEncoder)
- m_mediaEncoder->durationChanged(position);
- }
- void actualLocationChanged(const QUrl &location)
- {
- if (m_mediaEncoder)
- m_mediaEncoder->actualLocationChanged(location);
- }
- void error(int error, const QString &errorString)
- {
- if (m_mediaEncoder)
- m_mediaEncoder->error(QMediaRecorder::Error(error), errorString);
- }
-
-private Q_SLOTS:
- void updateDuration();
- void onCameraOpened();
-
- void onError(int what, int extra);
- void onInfo(int what, int extra);
-
-private:
- void applySettings(QMediaEncoderSettings &settings);
-
- struct CaptureProfile {
- AndroidMediaRecorder::OutputFormat outputFormat;
- QString outputFileExtension;
-
- AndroidMediaRecorder::AudioEncoder audioEncoder;
- int audioBitRate;
- int audioChannels;
- int audioSampleRate;
-
- AndroidMediaRecorder::VideoEncoder videoEncoder;
- int videoBitRate;
- int videoFrameRate;
- QSize videoResolution;
-
- bool isNull;
-
- CaptureProfile()
- : outputFormat(AndroidMediaRecorder::MPEG_4)
- , outputFileExtension(QLatin1String("mp4"))
- , audioEncoder(AndroidMediaRecorder::DefaultAudioEncoder)
- , audioBitRate(128000)
- , audioChannels(2)
- , audioSampleRate(44100)
- , videoEncoder(AndroidMediaRecorder::DefaultVideoEncoder)
- , videoBitRate(1)
- , videoFrameRate(-1)
- , videoResolution(1280, 720)
- , isNull(true)
- { }
- };
-
- CaptureProfile getProfile(int id);
-
- void restartViewfinder();
-
- QAndroidMediaEncoder *m_mediaEncoder = nullptr;
- AndroidMediaRecorder *m_mediaRecorder;
- QAndroidCameraSession *m_cameraSession;
-
- QPlatformAudioInput *m_audioInput = nullptr;
- QPlatformAudioOutput *m_audioOutput = nullptr;
-
- QElapsedTimer m_elapsedTime;
- QTimer m_notifyTimer;
- qint64 m_duration;
-
- QMediaRecorder::RecorderState m_state;
- QUrl m_usedOutputLocation;
- bool m_outputLocationIsStandard = false;
-
- CaptureProfile m_defaultSettings;
-
- QMediaEncoderSettings m_encoderSettings;
- AndroidMediaRecorder::OutputFormat m_outputFormat;
- AndroidMediaRecorder::AudioEncoder m_audioEncoder;
- AndroidMediaRecorder::VideoEncoder m_videoEncoder;
-
- QList<QSize> m_supportedResolutions;
- QList<qreal> m_supportedFramerates;
-
- QMetaObject::Connection m_connOpenCamera;
- QMetaObject::Connection m_connActiveChangedCamera;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDCAPTURESESSION_H
diff --git a/src/multimedia/platform/android/mediacapture/qandroidimagecapture.cpp b/src/multimedia/platform/android/mediacapture/qandroidimagecapture.cpp
deleted file mode 100644
index 32e787290..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidimagecapture.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidimagecapture_p.h"
-
-#include "qandroidcamerasession_p.h"
-#include "qandroidmediacapturesession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QAndroidImageCapture::QAndroidImageCapture(QImageCapture *parent)
- : QPlatformImageCapture(parent)
-{
-}
-
-bool QAndroidImageCapture::isReadyForCapture() const
-{
- return m_session->isReadyForCapture();
-}
-
-int QAndroidImageCapture::capture(const QString &fileName)
-{
- return m_session->capture(fileName);
-}
-
-int QAndroidImageCapture::captureToBuffer()
-{
- // ### implement me!
- const QLatin1String errorMessage("Capturing to buffer not supported.");
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, -1),
- Q_ARG(int, QImageCapture::NotSupportedFeatureError),
- Q_ARG(QString, errorMessage));
- return -1;
-}
-
-QImageEncoderSettings QAndroidImageCapture::imageSettings() const
-{
- return m_session->imageSettings();
-}
-
-void QAndroidImageCapture::setImageSettings(const QImageEncoderSettings &settings)
-{
- m_session->setImageSettings(settings);
-}
-
-void QAndroidImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QAndroidMediaCaptureSession *captureSession = static_cast<QAndroidMediaCaptureSession *>(session);
- if (m_service == captureSession)
- return;
-
- m_service = captureSession;
- if (!m_service) {
- disconnect(m_session, nullptr, this, nullptr);
- return;
- }
-
- m_session = m_service->cameraSession();
- Q_ASSERT(m_session);
-
- connect(m_session, &QAndroidCameraSession::readyForCaptureChanged,
- this, &QAndroidImageCapture::readyForCaptureChanged);
- connect(m_session, &QAndroidCameraSession::imageExposed,
- this, &QAndroidImageCapture::imageExposed);
- connect(m_session, &QAndroidCameraSession::imageCaptured,
- this, &QAndroidImageCapture::imageCaptured);
- connect(m_session, &QAndroidCameraSession::imageMetadataAvailable,
- this, &QAndroidImageCapture::imageMetadataAvailable);
- connect(m_session, &QAndroidCameraSession::imageAvailable,
- this, &QAndroidImageCapture::imageAvailable);
- connect(m_session, &QAndroidCameraSession::imageSaved,
- this, &QAndroidImageCapture::imageSaved);
- connect(m_session, &QAndroidCameraSession::imageCaptureError,
- this, &QAndroidImageCapture::error);
-}
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediacapture/qandroidimagecapture_p.h b/src/multimedia/platform/android/mediacapture/qandroidimagecapture_p.h
deleted file mode 100644
index 83d15445f..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidimagecapture_p.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDCAMERAIMAGECAPTURECONTROL_H
-#define QANDROIDCAMERAIMAGECAPTURECONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformimagecapture_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidCameraSession;
-class QAndroidMediaCaptureSession;
-
-class QAndroidImageCapture : public QPlatformImageCapture
-{
- Q_OBJECT
-public:
- explicit QAndroidImageCapture(QImageCapture *parent = nullptr);
-
- bool isReadyForCapture() const override;
-
- int capture(const QString &fileName) override;
- int captureToBuffer() override;
-
- QImageEncoderSettings imageSettings() const override;
- void setImageSettings(const QImageEncoderSettings &settings) override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
-private:
- QAndroidCameraSession *m_session;
- QAndroidMediaCaptureSession *m_service;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDCAMERAIMAGECAPTURECONTROL_H
diff --git a/src/multimedia/platform/android/mediacapture/qandroidmediacapturesession.cpp b/src/multimedia/platform/android/mediacapture/qandroidmediacapturesession.cpp
deleted file mode 100644
index 94207c8a9..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidmediacapturesession.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Ruslan Baratov
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidmediacapturesession_p.h"
-
-#include "qandroidmediaencoder_p.h"
-#include "qandroidcapturesession_p.h"
-#include "qandroidcamera_p.h"
-#include "qandroidcamerasession_p.h"
-#include "qandroidimagecapture_p.h"
-#include "qmediadevices.h"
-#include "qaudiodevice.h"
-
-QT_BEGIN_NAMESPACE
-
-QAndroidMediaCaptureSession::QAndroidMediaCaptureSession()
- : m_captureSession(new QAndroidCaptureSession())
- , m_cameraSession(new QAndroidCameraSession())
-{
-}
-
-QAndroidMediaCaptureSession::~QAndroidMediaCaptureSession()
-{
- delete m_encoder;
- delete m_captureSession;
- delete m_cameraControl;
- delete m_imageCaptureControl;
- delete m_cameraSession;
-}
-
-QPlatformCamera *QAndroidMediaCaptureSession::camera()
-{
- return m_cameraControl;
-}
-
-void QAndroidMediaCaptureSession::setCamera(QPlatformCamera *camera)
-{
- if (camera) {
- m_captureSession->setCameraSession(m_cameraSession);
- } else {
- m_captureSession->setCameraSession(nullptr);
- }
-
- QAndroidCamera *control = static_cast<QAndroidCamera *>(camera);
- if (m_cameraControl == control)
- return;
-
- if (m_cameraControl)
- m_cameraControl->setCaptureSession(nullptr);
-
- m_cameraControl = control;
- if (m_cameraControl)
- m_cameraControl->setCaptureSession(this);
-
- emit cameraChanged();
-}
-
-QPlatformImageCapture *QAndroidMediaCaptureSession::imageCapture()
-{
- return m_imageCaptureControl;
-}
-
-void QAndroidMediaCaptureSession::setImageCapture(QPlatformImageCapture *imageCapture)
-{
- QAndroidImageCapture *control = static_cast<QAndroidImageCapture *>(imageCapture);
- if (m_imageCaptureControl == control)
- return;
-
- if (m_imageCaptureControl)
- m_imageCaptureControl->setCaptureSession(nullptr);
-
- m_imageCaptureControl = control;
- if (m_imageCaptureControl)
- m_imageCaptureControl->setCaptureSession(this);
-}
-
-QPlatformMediaEncoder *QAndroidMediaCaptureSession::mediaEncoder()
-{
- return m_encoder;
-}
-
-void QAndroidMediaCaptureSession::setMediaEncoder(QPlatformMediaEncoder *encoder)
-{
- QAndroidMediaEncoder *control = static_cast<QAndroidMediaEncoder *>(encoder);
-
- if (m_encoder == control)
- return;
-
- if (m_encoder)
- m_encoder->setCaptureSession(nullptr);
-
- m_encoder = control;
- if (m_encoder)
- m_encoder->setCaptureSession(this);
-
- emit encoderChanged();
-
-}
-
-void QAndroidMediaCaptureSession::setAudioInput(QPlatformAudioInput *input)
-{
- m_captureSession->setAudioInput(input);
-}
-
-void QAndroidMediaCaptureSession::setAudioOutput(QPlatformAudioOutput *output)
-{
- m_captureSession->setAudioOutput(output);
-}
-
-void QAndroidMediaCaptureSession::setVideoPreview(QVideoSink *sink)
-{
- m_cameraSession->setVideoSink(sink);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediacapture/qandroidmediacapturesession_p.h b/src/multimedia/platform/android/mediacapture/qandroidmediacapturesession_p.h
deleted file mode 100644
index 667fbba7a..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidmediacapturesession_p.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Ruslan Baratov
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDCAPTURESERVICE_H
-#define QANDROIDCAPTURESERVICE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediacapture_p.h>
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidMediaEncoder;
-class QAndroidCaptureSession;
-class QAndroidCamera;
-class QAndroidCameraSession;
-class QAndroidImageCapture;
-
-class QAndroidMediaCaptureSession : public QPlatformMediaCaptureSession
-{
- Q_OBJECT
-
-public:
- explicit QAndroidMediaCaptureSession();
- virtual ~QAndroidMediaCaptureSession();
-
- QPlatformCamera *camera() override;
- void setCamera(QPlatformCamera *camera) override;
-
- QPlatformImageCapture *imageCapture() override;
- void setImageCapture(QPlatformImageCapture *imageCapture) override;
-
- QPlatformMediaEncoder *mediaEncoder() override;
- void setMediaEncoder(QPlatformMediaEncoder *encoder) override;
-
- void setAudioInput(QPlatformAudioInput *input) override;
-
- void setVideoPreview(QVideoSink *sink) override;
-
- void setAudioOutput(QPlatformAudioOutput *output) override;
-
- QAndroidCaptureSession *captureSession() const { return m_captureSession; }
- QAndroidCameraSession *cameraSession() const { return m_cameraSession; }
-
-private:
- QAndroidMediaEncoder *m_encoder = nullptr;
- QAndroidCaptureSession *m_captureSession = nullptr;
- QAndroidCamera *m_cameraControl = nullptr;
- QAndroidCameraSession *m_cameraSession = nullptr;
- QAndroidImageCapture *m_imageCaptureControl = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDCAPTURESERVICE_H
diff --git a/src/multimedia/platform/android/mediacapture/qandroidmediaencoder.cpp b/src/multimedia/platform/android/mediacapture/qandroidmediaencoder.cpp
deleted file mode 100644
index 5e7ae990d..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidmediaencoder.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidmediaencoder_p.h"
-#include "qandroidmultimediautils_p.h"
-#include "qandroidcapturesession_p.h"
-#include "qandroidmediacapturesession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QAndroidMediaEncoder::QAndroidMediaEncoder(QMediaRecorder *parent)
- : QPlatformMediaEncoder(parent)
-{
-}
-
-bool QAndroidMediaEncoder::isLocationWritable(const QUrl &location) const
-{
- return location.isValid()
- && (location.isLocalFile() || location.isRelative());
-}
-
-QMediaRecorder::RecorderState QAndroidMediaEncoder::state() const
-{
- return m_session ? m_session->state() : QMediaRecorder::StoppedState;
-}
-
-qint64 QAndroidMediaEncoder::duration() const
-{
- return m_session ? m_session->duration() : 0;
-
-}
-
-void QAndroidMediaEncoder::record(QMediaEncoderSettings &settings)
-{
- if (m_session)
- m_session->start(settings, outputLocation());
-}
-
-void QAndroidMediaEncoder::stop()
-{
- if (m_session)
- m_session->stop();
-}
-
-void QAndroidMediaEncoder::setOutputLocation(const QUrl &location)
-{
- if (location.isLocalFile()) {
- qt_androidRequestWriteStoragePermission();
- }
- QPlatformMediaEncoder::setOutputLocation(location);
-}
-
-void QAndroidMediaEncoder::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QAndroidMediaCaptureSession *captureSession = static_cast<QAndroidMediaCaptureSession *>(session);
- if (m_service == captureSession)
- return;
-
- if (m_service)
- stop();
- if (m_session)
- m_session->setMediaEncoder(nullptr);
-
- m_service = captureSession;
- if (!m_service)
- return;
- m_session = m_service->captureSession();
- Q_ASSERT(m_session);
- m_session->setMediaEncoder(this);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediacapture/qandroidmediaencoder_p.h b/src/multimedia/platform/android/mediacapture/qandroidmediaencoder_p.h
deleted file mode 100644
index 6c6160ca9..000000000
--- a/src/multimedia/platform/android/mediacapture/qandroidmediaencoder_p.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDMEDIAENCODER_H
-#define QANDROIDMEDIAENCODER_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaencoder_p.h>
-#include <private/qplatformmediacapture_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidCaptureSession;
-class QAndroidMediaCaptureSession;
-
-class QAndroidMediaEncoder : public QPlatformMediaEncoder
-{
-public:
- explicit QAndroidMediaEncoder(QMediaRecorder *parent);
-
- bool isLocationWritable(const QUrl &location) const override;
- QMediaRecorder::RecorderState state() const override;
- qint64 duration() const override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
- void setOutputLocation(const QUrl &location) override;
- void record(QMediaEncoderSettings &settings) override;
- void stop() override;
-
-private:
- friend class QAndroidCaptureSession;
-
- QAndroidCaptureSession *m_session = nullptr;
- QAndroidMediaCaptureSession *m_service = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDMEDIAENCODER_H
diff --git a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp
deleted file mode 100644
index 8ae49715e..000000000
--- a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp
+++ /dev/null
@@ -1,983 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidmediaplayer_p.h"
-#include "androidmediaplayer_p.h"
-#include "qandroidvideooutput_p.h"
-#include "qandroidmetadata_p.h"
-#include "qandroidaudiooutput_p.h"
-#include "qaudiooutput.h"
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcMediaPlayer, "qt.multimedia.mediaplayer.android")
-
-class StateChangeNotifier
-{
-public:
- StateChangeNotifier(QAndroidMediaPlayer *mp)
- : mControl(mp)
- , mPreviousState(mp->state())
- , mPreviousMediaStatus(mp->mediaStatus())
- {
- ++mControl->mActiveStateChangeNotifiers;
- }
-
- ~StateChangeNotifier()
- {
- if (--mControl->mActiveStateChangeNotifiers)
- return;
-
- if (mPreviousMediaStatus != mControl->mediaStatus())
- Q_EMIT mControl->mediaStatusChanged(mControl->mediaStatus());
-
- if (mPreviousState != mControl->state())
- Q_EMIT mControl->stateChanged(mControl->state());
- }
-
-private:
- QAndroidMediaPlayer *mControl;
- QMediaPlayer::PlaybackState mPreviousState;
- QMediaPlayer::MediaStatus mPreviousMediaStatus;
-};
-
-QAndroidMediaPlayer::QAndroidMediaPlayer(QMediaPlayer *parent)
- : QPlatformMediaPlayer(parent),
- mMediaPlayer(new AndroidMediaPlayer),
- mState(AndroidMediaPlayer::Uninitialized)
-{
- connect(mMediaPlayer, &AndroidMediaPlayer::bufferingChanged, this,
- &QAndroidMediaPlayer::onBufferingChanged);
- connect(mMediaPlayer, &AndroidMediaPlayer::info, this, &QAndroidMediaPlayer::onInfo);
- connect(mMediaPlayer, &AndroidMediaPlayer::error, this, &QAndroidMediaPlayer::onError);
- connect(mMediaPlayer, &AndroidMediaPlayer::stateChanged, this,
- &QAndroidMediaPlayer::onStateChanged);
- connect(mMediaPlayer, &AndroidMediaPlayer::videoSizeChanged, this,
- &QAndroidMediaPlayer::onVideoSizeChanged);
- connect(mMediaPlayer, &AndroidMediaPlayer::progressChanged, this,
- &QAndroidMediaPlayer::positionChanged);
- connect(mMediaPlayer, &AndroidMediaPlayer::durationChanged, this,
- &QAndroidMediaPlayer::durationChanged);
- connect(mMediaPlayer, &AndroidMediaPlayer::tracksInfoChanged, this,
- &QAndroidMediaPlayer::updateTrackInfo);
-}
-
-QAndroidMediaPlayer::~QAndroidMediaPlayer()
-{
- mMediaPlayer->release();
- delete mMediaPlayer;
-}
-
-qint64 QAndroidMediaPlayer::duration() const
-{
- if ((mState & (AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::Stopped
- | AndroidMediaPlayer::PlaybackCompleted)) == 0) {
- return 0;
- }
-
- return mMediaPlayer->getDuration();
-}
-
-qint64 QAndroidMediaPlayer::position() const
-{
- if (mediaStatus() == QMediaPlayer::EndOfMedia)
- return duration();
-
- if ((mState & (AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted))) {
- return mMediaPlayer->getCurrentPosition();
- }
-
- return (mPendingPosition == -1) ? 0 : mPendingPosition;
-}
-
-void QAndroidMediaPlayer::setPosition(qint64 position)
-{
- if (!isSeekable())
- return;
-
- const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
-
- if (seekPosition == this->position())
- return;
-
- StateChangeNotifier notifier(this);
-
- if (mediaStatus() == QMediaPlayer::EndOfMedia)
- setMediaStatus(QMediaPlayer::LoadedMedia);
-
- if ((mState & (AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted)) == 0) {
- mPendingPosition = seekPosition;
- } else {
- mMediaPlayer->seekTo(seekPosition);
-
- if (mPendingPosition != -1) {
- mPendingPosition = -1;
- }
- }
-
- Q_EMIT positionChanged(seekPosition);
-}
-
-void QAndroidMediaPlayer::setVolume(float volume)
-{
- if ((mState & (AndroidMediaPlayer::Idle
- | AndroidMediaPlayer::Initialized
- | AndroidMediaPlayer::Stopped
- | AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted)) == 0) {
- mPendingVolume = volume;
- return;
- }
-
- mMediaPlayer->setVolume(qRound(volume*100.));
- mPendingVolume = -1;
-}
-
-void QAndroidMediaPlayer::setMuted(bool muted)
-{
- if ((mState & (AndroidMediaPlayer::Idle
- | AndroidMediaPlayer::Initialized
- | AndroidMediaPlayer::Stopped
- | AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted)) == 0) {
- mPendingMute = muted;
- return;
- }
-
- mMediaPlayer->setMuted(muted);
- mPendingMute = -1;
-}
-
-QMediaMetaData QAndroidMediaPlayer::metaData() const
-{
- return QAndroidMetaData::extractMetadata(mMediaContent);
-}
-
-float QAndroidMediaPlayer::bufferProgress() const
-{
- return mBufferFilled ? 1. : 0;
-}
-
-bool QAndroidMediaPlayer::isAudioAvailable() const
-{
- return mAudioAvailable;
-}
-
-bool QAndroidMediaPlayer::isVideoAvailable() const
-{
- return mVideoAvailable;
-}
-
-QMediaTimeRange QAndroidMediaPlayer::availablePlaybackRanges() const
-{
- return mAvailablePlaybackRange;
-}
-
-void QAndroidMediaPlayer::updateAvailablePlaybackRanges()
-{
- if (mBuffering) {
- const qint64 pos = position();
- const qint64 end = (duration() / 100) * mBufferPercent;
- mAvailablePlaybackRange.addInterval(pos, end);
- } else if (isSeekable()) {
- mAvailablePlaybackRange = QMediaTimeRange(0, duration());
- } else {
- mAvailablePlaybackRange = QMediaTimeRange();
- }
-
-// #### Q_EMIT availablePlaybackRangesChanged(mAvailablePlaybackRange);
-}
-
-qreal QAndroidMediaPlayer::playbackRate() const
-{
- if (mHasPendingPlaybackRate ||
- (mState & (AndroidMediaPlayer::Initialized
- | AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted
- | AndroidMediaPlayer::Error)) == 0) {
- return mPendingPlaybackRate;
- }
-
- return mMediaPlayer->playbackRate();
-}
-
-void QAndroidMediaPlayer::setPlaybackRate(qreal rate)
-{
- if ((mState & (AndroidMediaPlayer::Initialized
- | AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted
- | AndroidMediaPlayer::Error)) == 0) {
- if (mPendingPlaybackRate != rate) {
- mPendingPlaybackRate = rate;
- mHasPendingPlaybackRate = true;
- Q_EMIT playbackRateChanged(rate);
- }
- return;
- }
-
- bool succeeded = mMediaPlayer->setPlaybackRate(rate);
-
- if (mHasPendingPlaybackRate) {
- mHasPendingPlaybackRate = false;
- mPendingPlaybackRate = qreal(1.0);
- if (!succeeded)
- Q_EMIT playbackRateChanged(playbackRate());
- } else if (succeeded) {
- Q_EMIT playbackRateChanged(rate);
- }
-}
-
-QUrl QAndroidMediaPlayer::media() const
-{
- return mMediaContent;
-}
-
-const QIODevice *QAndroidMediaPlayer::mediaStream() const
-{
- return mMediaStream;
-}
-
-void QAndroidMediaPlayer::setMedia(const QUrl &mediaContent,
- QIODevice *stream)
-{
- StateChangeNotifier notifier(this);
-
- mReloadingMedia = (mMediaContent == mediaContent) && !mPendingSetMedia;
-
- if (!mReloadingMedia) {
- mMediaContent = mediaContent;
- mMediaStream = stream;
- }
-
- if (mediaContent.isEmpty()) {
- setMediaStatus(QMediaPlayer::NoMedia);
- } else {
- if (mVideoOutput && !mVideoOutput->isReady()) {
- // if a video output is set but the video texture is not ready, delay loading the media
- // since it can cause problems on some hardware
- mPendingSetMedia = true;
- return;
- }
-
- if (mVideoSize.isValid() && mVideoOutput)
- mVideoOutput->setVideoSize(mVideoSize);
-
- if ((mMediaPlayer->display() == 0) && mVideoOutput)
- mMediaPlayer->setDisplay(mVideoOutput->surfaceTexture());
- mMediaPlayer->setDataSource(QNetworkRequest(mediaContent));
- mMediaPlayer->prepareAsync();
- }
-
- resetBufferingProgress();
-
- mReloadingMedia = false;
-}
-
-void QAndroidMediaPlayer::setVideoSink(QVideoSink *sink)
-{
- if (m_videoSink == sink)
- return;
-
- m_videoSink = sink;
-
- if (!m_videoSink) {
- return;
- }
-
- if (mVideoOutput) {
- delete mVideoOutput;
- mVideoOutput = nullptr;
- mMediaPlayer->setDisplay(nullptr);
- }
-
- mVideoOutput = new QAndroidTextureVideoOutput(this);
- connect(mVideoOutput, &QAndroidTextureVideoOutput::readyChanged, this,
- &QAndroidMediaPlayer::onVideoOutputReady);
- connect(mMediaPlayer, &AndroidMediaPlayer::timedTextChanged, mVideoOutput,
- &QAndroidTextureVideoOutput::setSubtitle);
-
- mVideoOutput->setSurface(sink);
-
- if (mVideoOutput->isReady())
- mMediaPlayer->setDisplay(mVideoOutput->surfaceTexture());
-}
-
-void QAndroidMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
-{
- if (m_audioOutput == output)
- return;
- if (m_audioOutput)
- m_audioOutput->q->disconnect(this);
- m_audioOutput = static_cast<QAndroidAudioOutput *>(output);
- if (m_audioOutput) {
- connect(m_audioOutput->q, &QAudioOutput::deviceChanged, this, &QAndroidMediaPlayer::updateAudioDevice);
- connect(m_audioOutput->q, &QAudioOutput::volumeChanged, this, &QAndroidMediaPlayer::setVolume);
- connect(m_audioOutput->q, &QAudioOutput::mutedChanged, this, &QAndroidMediaPlayer::setMuted);
- updateAudioDevice();
- }
-}
-
-void QAndroidMediaPlayer::updateAudioDevice()
-{
- if (m_audioOutput)
- mMediaPlayer->setAudioOutput(m_audioOutput->device.id());
-}
-
-void QAndroidMediaPlayer::play()
-{
- StateChangeNotifier notifier(this);
-
- // We need to prepare the mediaplayer again.
- if ((mState & AndroidMediaPlayer::Stopped) && !mMediaContent.isEmpty()) {
- setMedia(mMediaContent, mMediaStream);
- }
-
- if (!mMediaContent.isEmpty())
- stateChanged(QMediaPlayer::PlayingState);
-
- if ((mState & (AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted)) == 0) {
- mPendingState = QMediaPlayer::PlayingState;
- return;
- }
-
- mMediaPlayer->play();
-}
-
-void QAndroidMediaPlayer::pause()
-{
- StateChangeNotifier notifier(this);
-
- stateChanged(QMediaPlayer::PausedState);
-
- if ((mState & (AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted)) == 0) {
- mPendingState = QMediaPlayer::PausedState;
- return;
- }
-
- mMediaPlayer->pause();
-}
-
-void QAndroidMediaPlayer::stop()
-{
- StateChangeNotifier notifier(this);
-
- stateChanged(QMediaPlayer::StoppedState);
-
- if ((mState & (AndroidMediaPlayer::Prepared
- | AndroidMediaPlayer::Started
- | AndroidMediaPlayer::Stopped
- | AndroidMediaPlayer::Paused
- | AndroidMediaPlayer::PlaybackCompleted)) == 0) {
- if ((mState & (AndroidMediaPlayer::Idle | AndroidMediaPlayer::Uninitialized | AndroidMediaPlayer::Error)) == 0)
- mPendingState = QMediaPlayer::StoppedState;
- return;
- }
-
- mMediaPlayer->stop();
-}
-
-bool QAndroidMediaPlayer::isSeekable() const
-{
- return true;
-}
-
-void QAndroidMediaPlayer::onInfo(qint32 what, qint32 extra)
-{
- StateChangeNotifier notifier(this);
-
- Q_UNUSED(extra);
- switch (what) {
- case AndroidMediaPlayer::MEDIA_INFO_UNKNOWN:
- break;
- case AndroidMediaPlayer::MEDIA_INFO_VIDEO_TRACK_LAGGING:
- // IGNORE
- break;
- case AndroidMediaPlayer::MEDIA_INFO_VIDEO_RENDERING_START:
- break;
- case AndroidMediaPlayer::MEDIA_INFO_BUFFERING_START:
- mPendingState = state();
- stateChanged(QMediaPlayer::PausedState);
- setMediaStatus(QMediaPlayer::StalledMedia);
- break;
- case AndroidMediaPlayer::MEDIA_INFO_BUFFERING_END:
- if (state() != QMediaPlayer::StoppedState)
- flushPendingStates();
- break;
- case AndroidMediaPlayer::MEDIA_INFO_BAD_INTERLEAVING:
- break;
- case AndroidMediaPlayer::MEDIA_INFO_NOT_SEEKABLE:
- seekableChanged(false);
- break;
- case AndroidMediaPlayer::MEDIA_INFO_METADATA_UPDATE:
- Q_EMIT metaDataChanged();
- break;
- }
-}
-
-void QAndroidMediaPlayer::onError(qint32 what, qint32 extra)
-{
- StateChangeNotifier notifier(this);
-
- QString errorString;
- QMediaPlayer::Error error = QMediaPlayer::ResourceError;
-
- switch (what) {
- case AndroidMediaPlayer::MEDIA_ERROR_UNKNOWN:
- errorString = QLatin1String("Error:");
- break;
- case AndroidMediaPlayer::MEDIA_ERROR_SERVER_DIED:
- errorString = QLatin1String("Error: Server died");
- error = QMediaPlayer::ResourceError;
- break;
- case AndroidMediaPlayer::MEDIA_ERROR_INVALID_STATE:
- errorString = QLatin1String("Error: Invalid state");
- error = QMediaPlayer::ResourceError;
- break;
- }
-
- switch (extra) {
- case AndroidMediaPlayer::MEDIA_ERROR_IO: // Network OR file error
- errorString += QLatin1String(" (I/O operation failed)");
- error = QMediaPlayer::NetworkError;
- setMediaStatus(QMediaPlayer::InvalidMedia);
- break;
- case AndroidMediaPlayer::MEDIA_ERROR_MALFORMED:
- errorString += QLatin1String(" (Malformed bitstream)");
- error = QMediaPlayer::FormatError;
- setMediaStatus(QMediaPlayer::InvalidMedia);
- break;
- case AndroidMediaPlayer::MEDIA_ERROR_UNSUPPORTED:
- errorString += QLatin1String(" (Unsupported media)");
- error = QMediaPlayer::FormatError;
- setMediaStatus(QMediaPlayer::InvalidMedia);
- break;
- case AndroidMediaPlayer::MEDIA_ERROR_TIMED_OUT:
- errorString += QLatin1String(" (Timed out)");
- break;
- case AndroidMediaPlayer::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
- errorString += QLatin1String(" (Unable to start progressive playback')");
- error = QMediaPlayer::FormatError;
- setMediaStatus(QMediaPlayer::InvalidMedia);
- break;
- case AndroidMediaPlayer::MEDIA_ERROR_BAD_THINGS_ARE_GOING_TO_HAPPEN:
- errorString += QLatin1String(" (Unknown error/Insufficient resources)");
- error = QMediaPlayer::ResourceError;
- break;
- }
-
- Q_EMIT QPlatformMediaPlayer::error(error, errorString);
-}
-
-void QAndroidMediaPlayer::onBufferingChanged(qint32 percent)
-{
- StateChangeNotifier notifier(this);
-
- mBuffering = percent != 100;
- mBufferPercent = percent;
-
- updateAvailablePlaybackRanges();
-
- if (state() != QMediaPlayer::StoppedState)
- setMediaStatus(mBuffering ? QMediaPlayer::BufferingMedia : QMediaPlayer::BufferedMedia);
-}
-
-void QAndroidMediaPlayer::onVideoSizeChanged(qint32 width, qint32 height)
-{
- QSize newSize(width, height);
-
- if (width == 0 || height == 0 || newSize == mVideoSize)
- return;
-
- setVideoAvailable(true);
- mVideoSize = newSize;
-
- if (mVideoOutput)
- mVideoOutput->setVideoSize(mVideoSize);
-}
-
-void QAndroidMediaPlayer::onStateChanged(qint32 state)
-{
- // If reloading, don't report state changes unless the new state is Prepared or Error.
- if ((mState & AndroidMediaPlayer::Stopped)
- && (state & (AndroidMediaPlayer::Prepared | AndroidMediaPlayer::Error | AndroidMediaPlayer::Uninitialized)) == 0) {
- return;
- }
-
- StateChangeNotifier notifier(this);
-
- mState = state;
- switch (mState) {
- case AndroidMediaPlayer::Idle:
- break;
- case AndroidMediaPlayer::Initialized:
- break;
- case AndroidMediaPlayer::Preparing:
- if (!mReloadingMedia)
- setMediaStatus(QMediaPlayer::LoadingMedia);
- break;
- case AndroidMediaPlayer::Prepared:
- setMediaStatus(QMediaPlayer::LoadedMedia);
- if (mBuffering) {
- setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia
- : QMediaPlayer::BufferingMedia);
- } else {
- onBufferingChanged(100);
- }
- Q_EMIT metaDataChanged();
- setAudioAvailable(true);
- flushPendingStates();
- break;
- case AndroidMediaPlayer::Started:
- stateChanged(QMediaPlayer::PlayingState);
- if (mBuffering) {
- setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia
- : QMediaPlayer::BufferingMedia);
- } else {
- setMediaStatus(QMediaPlayer::BufferedMedia);
- }
- Q_EMIT positionChanged(position());
- break;
- case AndroidMediaPlayer::Paused:
- stateChanged(QMediaPlayer::PausedState);
- break;
- case AndroidMediaPlayer::Error:
- stateChanged(QMediaPlayer::StoppedState);
- setMediaStatus(QMediaPlayer::InvalidMedia);
- mMediaPlayer->release();
- Q_EMIT positionChanged(0);
- break;
- case AndroidMediaPlayer::Stopped:
- stateChanged(QMediaPlayer::StoppedState);
- setMediaStatus(QMediaPlayer::LoadedMedia);
- Q_EMIT positionChanged(0);
- break;
- case AndroidMediaPlayer::PlaybackCompleted:
- stateChanged(QMediaPlayer::StoppedState);
- setMediaStatus(QMediaPlayer::EndOfMedia);
- break;
- case AndroidMediaPlayer::Uninitialized:
- // reset some properties (unless we reload the same media)
- if (!mReloadingMedia) {
- resetBufferingProgress();
- mPendingPosition = -1;
- mPendingSetMedia = false;
- mPendingState = -1;
-
- Q_EMIT durationChanged(0);
- Q_EMIT positionChanged(0);
-
- setAudioAvailable(false);
- setVideoAvailable(false);
- seekableChanged(true);
- }
- break;
- default:
- break;
- }
-
- if ((mState & (AndroidMediaPlayer::Stopped | AndroidMediaPlayer::Uninitialized)) != 0) {
- mMediaPlayer->setDisplay(0);
- if (mVideoOutput) {
- mVideoOutput->stop();
- mVideoOutput->reset();
- }
- }
-}
-
-int QAndroidMediaPlayer::trackCount(TrackType trackType)
-{
- if (!mTracksMetadata.contains(trackType))
- return -1;
-
- auto tracks = mTracksMetadata.value(trackType);
- return tracks.count();
-}
-
-QMediaMetaData QAndroidMediaPlayer::trackMetaData(TrackType trackType, int streamNumber)
-{
- if (!mTracksMetadata.contains(trackType))
- return QMediaMetaData();
-
- auto tracks = mTracksMetadata.value(trackType);
- if (tracks.count() < streamNumber)
- return QMediaMetaData();
-
- QAndroidMetaData trackInfo = tracks.at(streamNumber);
- return static_cast<QMediaMetaData>(trackInfo);
-}
-
-QPlatformMediaPlayer::TrackType convertTrackType(AndroidMediaPlayer::TrackType type)
-{
- switch (type) {
- case AndroidMediaPlayer::TrackType::Video:
- return QPlatformMediaPlayer::TrackType::VideoStream;
- case AndroidMediaPlayer::TrackType::Audio:
- return QPlatformMediaPlayer::TrackType::AudioStream;
- case AndroidMediaPlayer::TrackType::TimedText:
- return QPlatformMediaPlayer::TrackType::SubtitleStream;
- case AndroidMediaPlayer::TrackType::Subtitle:
- return QPlatformMediaPlayer::TrackType::SubtitleStream;
- case AndroidMediaPlayer::TrackType::Unknown:
- case AndroidMediaPlayer::TrackType::Metadata:
- return QPlatformMediaPlayer::TrackType::NTrackTypes;
- }
-
- return QPlatformMediaPlayer::TrackType::NTrackTypes;
-}
-
-int QAndroidMediaPlayer::convertTrackNumber(int androidTrackNumber)
-{
- int trackNumber = androidTrackNumber;
-
- int videoTrackCount = trackCount(QPlatformMediaPlayer::TrackType::VideoStream);
- if (trackNumber <= videoTrackCount)
- return trackNumber;
-
- trackNumber = trackNumber - videoTrackCount;
-
- int audioTrackCount = trackCount(QPlatformMediaPlayer::TrackType::AudioStream);
- if (trackNumber <= audioTrackCount)
- return trackNumber;
-
- trackNumber = trackNumber - audioTrackCount;
-
- auto subtitleTracks = mTracksMetadata.value(QPlatformMediaPlayer::TrackType::SubtitleStream);
- int timedTextCount = 0;
- int subtitleTextCount = 0;
- for (const auto &track : subtitleTracks) {
- if (track.androidTrackType() == 3) // 3 == TimedText
- timedTextCount++;
-
- if (track.androidTrackType() == 4) // 4 == Subtitle
- subtitleTextCount++;
- }
-
- if (trackNumber <= timedTextCount)
- return trackNumber;
-
- trackNumber = trackNumber - timedTextCount;
-
- if (trackNumber <= subtitleTextCount)
- return trackNumber;
-
- return -1;
-}
-
-int QAndroidMediaPlayer::activeTrack(TrackType trackType)
-{
- int androidTrackNumber = -1;
-
- switch (trackType) {
- case QPlatformMediaPlayer::TrackType::VideoStream: {
- if (!mIsVideoTrackEnabled)
- return -1;
- androidTrackNumber = mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Video);
- }
- case QPlatformMediaPlayer::TrackType::AudioStream: {
- if (!mIsAudioTrackEnabled)
- return -1;
-
- androidTrackNumber = mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Audio);
- }
- case QPlatformMediaPlayer::TrackType::SubtitleStream: {
- int timedTextSelectedTrack =
- mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::TimedText);
-
- if (timedTextSelectedTrack > -1) {
- androidTrackNumber = timedTextSelectedTrack;
- break;
- }
-
- int subtitleSelectedTrack =
- mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Subtitle);
- if (subtitleSelectedTrack > -1) {
- androidTrackNumber = subtitleSelectedTrack;
- break;
- }
-
- return -1;
- }
- case QPlatformMediaPlayer::TrackType::NTrackTypes:
- return -1;
- }
-
- return convertTrackNumber(androidTrackNumber);
-}
-
-void QAndroidMediaPlayer::disableTrack(TrackType trackType)
-{
- const auto track = activeTrack(trackType);
-
- switch (trackType) {
- case VideoStream: {
- if (track > -1) {
- mMediaPlayer->setDisplay(nullptr);
- mIsVideoTrackEnabled = false;
- }
- break;
- }
- case AudioStream: {
- if (track > -1) {
- mMediaPlayer->setMuted(true);
- mMediaPlayer->blockAudio();
- mIsAudioTrackEnabled = false;
- }
- break;
- }
- case SubtitleStream: {
- // subtitles and timedtext tracks can be selected at the same time so deselect both
- int subtitleSelectedTrack =
- mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Subtitle);
- if (subtitleSelectedTrack > -1)
- mMediaPlayer->deselectTrack(subtitleSelectedTrack);
-
- int timedTextSelectedTrack =
- mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::TimedText);
- if (timedTextSelectedTrack > -1)
- mMediaPlayer->deselectTrack(timedTextSelectedTrack);
-
- break;
- }
- case NTrackTypes:
- break;
- }
-}
-
-void QAndroidMediaPlayer::setActiveTrack(TrackType trackType, int streamNumber)
-{
-
- if (!mTracksMetadata.contains(trackType)) {
- qCWarning(lcMediaPlayer)
- << "Trying to set a active track which type has no available tracks.";
- return;
- }
-
- const auto &tracks = mTracksMetadata.value(trackType);
- if (streamNumber > tracks.count()) {
- qCWarning(lcMediaPlayer) << "Trying to set a active track that does not exist.";
- return;
- }
-
- // in case of < 0 deselect tracktype
- if (streamNumber < 0) {
- disableTrack(trackType);
- return;
- }
-
- const auto currentTrack = activeTrack(trackType);
- if (streamNumber == currentTrack) {
- return;
- }
-
- if (trackType == TrackType::VideoStream && !mIsVideoTrackEnabled) {
- // enable video stream
- mMediaPlayer->setDisplay(mVideoOutput->surfaceTexture());
- mIsVideoTrackEnabled = true;
- }
-
- if (trackType == TrackType::AudioStream && !mIsAudioTrackEnabled) {
- // enable audio stream
- mMediaPlayer->unblockAudio();
- mMediaPlayer->setMuted(false);
- mIsAudioTrackEnabled = true;
- }
-
- if (trackType == TrackType::SubtitleStream) {
- // subtitles and timedtext tracks can be selected at the same time so deselect both before
- // selecting a new one
- disableTrack(TrackType::SubtitleStream);
- }
-
- const auto &trackInfo = tracks.at(streamNumber);
- const auto &trackNumber = trackInfo.androidTrackNumber();
- mMediaPlayer->selectTrack(trackNumber);
-}
-
-void QAndroidMediaPlayer::positionChanged(qint64 position)
-{
- QPlatformMediaPlayer::positionChanged(position);
-}
-
-void QAndroidMediaPlayer::durationChanged(qint64 duration)
-{
- QPlatformMediaPlayer::durationChanged(duration);
-}
-
-void QAndroidMediaPlayer::onVideoOutputReady(bool ready)
-{
- if ((mMediaPlayer->display() == 0) && mVideoOutput && ready)
- mMediaPlayer->setDisplay(mVideoOutput->surfaceTexture());
-
- flushPendingStates();
-}
-
-void QAndroidMediaPlayer::setMediaStatus(QMediaPlayer::MediaStatus status)
-{
- mediaStatusChanged(status);
-
- if (status == QMediaPlayer::NoMedia || status == QMediaPlayer::InvalidMedia)
- Q_EMIT durationChanged(0);
-
- if (status == QMediaPlayer::EndOfMedia)
- Q_EMIT positionChanged(position());
-
- updateBufferStatus();
-}
-
-void QAndroidMediaPlayer::setAudioAvailable(bool available)
-{
- if (mAudioAvailable == available)
- return;
-
- mAudioAvailable = available;
- Q_EMIT audioAvailableChanged(mAudioAvailable);
-}
-
-void QAndroidMediaPlayer::setVideoAvailable(bool available)
-{
- if (mVideoAvailable == available)
- return;
-
- if (!available)
- mVideoSize = QSize();
-
- mVideoAvailable = available;
- Q_EMIT videoAvailableChanged(mVideoAvailable);
-}
-
-void QAndroidMediaPlayer::resetBufferingProgress()
-{
- mBuffering = false;
- mBufferPercent = 0;
- mAvailablePlaybackRange = QMediaTimeRange();
-}
-
-void QAndroidMediaPlayer::flushPendingStates()
-{
- if (mPendingSetMedia) {
- setMedia(mMediaContent, 0);
- mPendingSetMedia = false;
- return;
- }
-
- const int newState = mPendingState;
- mPendingState = -1;
-
- if (mPendingPosition != -1)
- setPosition(mPendingPosition);
- if (mPendingVolume >= 0)
- setVolume(mPendingVolume);
- if (mPendingMute != -1)
- setMuted((mPendingMute == 1));
- if (mHasPendingPlaybackRate)
- setPlaybackRate(mPendingPlaybackRate);
-
- switch (newState) {
- case QMediaPlayer::PlayingState:
- play();
- break;
- case QMediaPlayer::PausedState:
- pause();
- break;
- case QMediaPlayer::StoppedState:
- stop();
- break;
- default:
- break;
- }
-}
-
-void QAndroidMediaPlayer::updateBufferStatus()
-{
- const auto &status = mediaStatus();
- bool bufferFilled = (status == QMediaPlayer::BufferedMedia || status == QMediaPlayer::BufferingMedia);
-
- if (mBufferFilled != bufferFilled) {
- mBufferFilled = bufferFilled;
- Q_EMIT bufferProgressChanged(bufferProgress());
- }
-}
-
-void QAndroidMediaPlayer::updateTrackInfo()
-{
- const auto &androidTracksInfo = mMediaPlayer->tracksInfo();
-
- // prepare mTracksMetadata
- mTracksMetadata[TrackType::VideoStream] = QList<QAndroidMetaData>();
- mTracksMetadata[TrackType::AudioStream] = QList<QAndroidMetaData>();
- mTracksMetadata[TrackType::SubtitleStream] = QList<QAndroidMetaData>();
- mTracksMetadata[TrackType::NTrackTypes] = QList<QAndroidMetaData>();
-
- for (const auto &androidTrackInfo : androidTracksInfo) {
-
- const auto &mediaPlayerType = convertTrackType(androidTrackInfo.trackType);
- auto &tracks = mTracksMetadata[mediaPlayerType];
-
- const QAndroidMetaData metadata(mediaPlayerType, androidTrackInfo.trackType,
- androidTrackInfo.trackNumber, androidTrackInfo.mimeType,
- androidTrackInfo.language);
- tracks.append(metadata);
- }
-
- emit tracksChanged();
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h
deleted file mode 100644
index b8e187a08..000000000
--- a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDMEDIAPLAYERCONTROL_H
-#define QANDROIDMEDIAPLAYERCONTROL_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 <qglobal.h>
-#include <private/qplatformmediaplayer_p.h>
-#include <private/qandroidmetadata_p.h>
-#include <qsize.h>
-#include <qurl.h>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidMediaPlayer;
-class QAndroidTextureVideoOutput;
-class QAndroidMediaPlayerVideoRendererControl;
-class QAndroidAudioOutput;
-
-class QAndroidMediaPlayer : public QObject, public QPlatformMediaPlayer
-{
- Q_OBJECT
-
-public:
- explicit QAndroidMediaPlayer(QMediaPlayer *parent = 0);
- ~QAndroidMediaPlayer() override;
-
- qint64 duration() const override;
- qint64 position() const override;
- float bufferProgress() const override;
- bool isAudioAvailable() const override;
- bool isVideoAvailable() const override;
- QMediaTimeRange availablePlaybackRanges() const override;
- qreal playbackRate() const override;
- void setPlaybackRate(qreal rate) override;
- QUrl media() const override;
- const QIODevice *mediaStream() const override;
- void setMedia(const QUrl &mediaContent, QIODevice *stream) override;
-
- QMediaMetaData metaData() const override;
-
- void setVideoSink(QVideoSink *surface) override;
-
- void setAudioOutput(QPlatformAudioOutput *output) override;
- void updateAudioDevice();
-
- void setPosition(qint64 position) override;
- void play() override;
- void pause() override;
- void stop() override;
-
- bool isSeekable() const override;
-
- int trackCount(TrackType trackType) override;
- QMediaMetaData trackMetaData(TrackType trackType, int streamNumber) override;
- int activeTrack(TrackType trackType) override;
- void setActiveTrack(TrackType trackType, int streamNumber) override;
-
-private Q_SLOTS:
- void setVolume(float volume);
- void setMuted(bool muted);
- void onVideoOutputReady(bool ready);
- void onError(qint32 what, qint32 extra);
- void onInfo(qint32 what, qint32 extra);
- void onBufferingChanged(qint32 percent);
- void onVideoSizeChanged(qint32 width, qint32 height);
- void onStateChanged(qint32 state);
- void positionChanged(qint64 position);
- void durationChanged(qint64 duration);
-
-private:
- AndroidMediaPlayer *mMediaPlayer = nullptr;
- QAndroidAudioOutput *m_audioOutput = nullptr;
- QUrl mMediaContent;
- QIODevice *mMediaStream = nullptr;
- QAndroidTextureVideoOutput *mVideoOutput = nullptr;
- QVideoSink *m_videoSink = nullptr;
- int mBufferPercent = -1;
- bool mBufferFilled = false;
- bool mAudioAvailable = false;
- bool mVideoAvailable = false;
- QSize mVideoSize;
- bool mBuffering = false;
- QMediaTimeRange mAvailablePlaybackRange;
- int mState;
- int mPendingState = -1;
- qint64 mPendingPosition = -1;
- bool mPendingSetMedia = false;
- float mPendingVolume = -1;
- int mPendingMute = -1;
- bool mReloadingMedia = false;
- int mActiveStateChangeNotifiers = 0;
- qreal mPendingPlaybackRate = 1.;
- bool mHasPendingPlaybackRate = false; // we need this because the rate can theoretically be negative
- QMap<TrackType, QList<QAndroidMetaData>> mTracksMetadata;
-
- bool mIsVideoTrackEnabled = true;
- bool mIsAudioTrackEnabled = true;
-
- void setMediaStatus(QMediaPlayer::MediaStatus status);
- void setAudioAvailable(bool available);
- void setVideoAvailable(bool available);
- void updateAvailablePlaybackRanges();
- void resetBufferingProgress();
- void flushPendingStates();
- void updateBufferStatus();
- void updateTrackInfo();
- void setSubtitle(QString subtitle);
- void disableTrack(TrackType trackType);
-
- int convertTrackNumber(int androidTrackNumber);
- friend class StateChangeNotifier;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDMEDIAPLAYERCONTROL_H
diff --git a/src/multimedia/platform/android/mediaplayer/qandroidmetadata.cpp b/src/multimedia/platform/android/mediaplayer/qandroidmetadata.cpp
deleted file mode 100644
index 059b62b52..000000000
--- a/src/multimedia/platform/android/mediaplayer/qandroidmetadata.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidmetadata_p.h"
-
-#include "androidmediametadataretriever_p.h"
-#include <QtMultimedia/qmediametadata.h>
-#include <qsize.h>
-#include <QDate>
-#include <QtCore/qlist.h>
-#include <QtConcurrent/qtconcurrentrun.h>
-
-QT_BEGIN_NAMESPACE
-
-// Genre name ordered by ID
-// see: http://id3.org/id3v2.3.0#Appendix_A_-_Genre_List_from_ID3v1
-static const char* qt_ID3GenreNames[] =
-{
- "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
- "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
- "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno",
- "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
- "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk",
- "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
- "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
- "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
- "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal",
- "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
- "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic",
- "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
- "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour",
- "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
- "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad",
- "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella",
- "Euro-House", "Dance Hall"
-};
-
-QMediaMetaData QAndroidMetaData::extractMetadata(const QUrl &url)
-{
- QMediaMetaData metadata;
-
- if (!url.isEmpty()) {
- AndroidMediaMetadataRetriever retriever;
- if (!retriever.setDataSource(url))
- return metadata;
-
- QString mimeType = retriever.extractMetadata(AndroidMediaMetadataRetriever::MimeType);
- if (!mimeType.isNull())
- metadata.insert(QMediaMetaData::MediaType, mimeType);
-
- bool isVideo = !retriever.extractMetadata(AndroidMediaMetadataRetriever::HasVideo).isNull()
- || mimeType.startsWith(QStringLiteral("video"));
-
- QString string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Album);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::AlbumTitle, string);
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::AlbumArtist);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::AlbumArtist, string);
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Artist);
- if (!string.isNull()) {
- metadata.insert(isVideo ? QMediaMetaData::LeadPerformer
- : QMediaMetaData::ContributingArtist,
- string.split(QLatin1Char('/'), Qt::SkipEmptyParts));
- }
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Author);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::Author, string.split(QLatin1Char('/'), Qt::SkipEmptyParts));
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Bitrate);
- if (!string.isNull()) {
- metadata.insert(isVideo ? QMediaMetaData::VideoBitRate
- : QMediaMetaData::AudioBitRate,
- string.toInt());
- }
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::CDTrackNumber);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::TrackNumber, string.toInt());
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Composer);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::Composer, string.split(QLatin1Char('/'), Qt::SkipEmptyParts));
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Date);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::Date, QDateTime::fromString(string, QStringLiteral("yyyyMMddTHHmmss.zzzZ")).date());
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Duration);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::Duration, string.toLongLong());
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Genre);
- if (!string.isNull()) {
- // The genre can be returned as an ID3v2 id, get the name for it in that case
- if (string.startsWith(QLatin1Char('(')) && string.endsWith(QLatin1Char(')'))) {
- bool ok = false;
- const int genreId = QStringView{string}.mid(1, string.length() - 2).toInt(&ok);
- if (ok && genreId >= 0 && genreId <= 125)
- string = QLatin1String(qt_ID3GenreNames[genreId]);
- }
- metadata.insert(QMediaMetaData::Genre, string);
- }
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Title);
- if (!string.isNull())
- metadata.insert(QMediaMetaData::Title, string);
-
- string = retriever.extractMetadata(AndroidMediaMetadataRetriever::VideoHeight);
- if (!string.isNull()) {
- const int height = string.toInt();
- const int width = retriever.extractMetadata(AndroidMediaMetadataRetriever::VideoWidth).toInt();
- metadata.insert(QMediaMetaData::Resolution, QSize(width, height));
- }
-
-// string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Writer);
-// if (!string.isNull())
-// metadata.insert(QMediaMetaData::Writer, string.split('/', Qt::SkipEmptyParts));
-
- }
-
- return metadata;
-}
-
-QLocale::Language getLocaleLanguage(const QString &language)
-{
- // undefined language or uncoded language
- if (language == QLatin1String("und") || language == QStringLiteral("mis"))
- return QLocale::AnyLanguage;
-
- QLocale locale(language);
- if (locale != QLocale::c())
- return locale.language();
-
- return QLocale::codeToLanguage(language.left(2));
-}
-
-QAndroidMetaData::QAndroidMetaData(int trackType, int androidTrackType, int androidTrackNumber,
- const QString &mimeType, const QString &language)
- : mTrackType(trackType),
- mAndroidTrackType(androidTrackType),
- mAndroidTrackNumber(androidTrackNumber)
-{
- insert(QMediaMetaData::MediaType, mimeType);
- insert(QMediaMetaData::Language, getLocaleLanguage(language));
-}
-
-int QAndroidMetaData::trackType() const
-{
- return mTrackType;
-}
-
-int QAndroidMetaData::androidTrackType() const
-{
- return mAndroidTrackType;
-}
-
-int QAndroidMetaData::androidTrackNumber() const
-{
- return mAndroidTrackNumber;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/mediaplayer/qandroidmetadata_p.h b/src/multimedia/platform/android/mediaplayer/qandroidmetadata_p.h
deleted file mode 100644
index 812edb062..000000000
--- a/src/multimedia/platform/android/mediaplayer/qandroidmetadata_p.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDMETADATA_H
-#define QANDROIDMETADATA_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 <qmediametadata.h>
-#include <qurl.h>
-#include <QMutex>
-#include <QVariant>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidMediaMetadataRetriever;
-
-class QAndroidMetaData : public QMediaMetaData
-{
-public:
- static QMediaMetaData extractMetadata(const QUrl &url);
-
- QAndroidMetaData(int trackType, int androidTrackType, int androidTrackNumber,
- const QString &mimeType, const QString &language);
-
- int trackType() const;
- int androidTrackType() const;
- int androidTrackNumber() const;
-
-private:
- int mTrackType;
- int mAndroidTrackType;
- int mAndroidTrackNumber;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDMETADATA_H
diff --git a/src/multimedia/platform/android/qandroidformatsinfo.cpp b/src/multimedia/platform/android/qandroidformatsinfo.cpp
deleted file mode 100644
index c45610b69..000000000
--- a/src/multimedia/platform/android/qandroidformatsinfo.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidformatsinfo_p.h"
-
-#include <qcoreapplication.h>
-
-QT_BEGIN_NAMESPACE
-
-QAndroidFormatInfo::QAndroidFormatInfo()
-{
- // Audio/Video/Image formats with their decoder/encoder information is documented at
- // https://developer.android.com/guide/topics/media/media-formats
- decoders = {
- { QMediaFormat::AAC, { QMediaFormat::AudioCodec::AAC }, {} },
- { QMediaFormat::MP3, { QMediaFormat::AudioCodec::MP3}, {} },
- { QMediaFormat::Ogg, { QMediaFormat::AudioCodec::Opus, QMediaFormat::AudioCodec::Vorbis },
- {} },
- { QMediaFormat::FLAC, { QMediaFormat::AudioCodec::FLAC }, {} },
- { QMediaFormat::Mpeg4Audio, { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::FLAC,
- QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::Vorbis},
- {} },
- { QMediaFormat::MPEG4, { QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::AAC,
- QMediaFormat::AudioCodec::FLAC, QMediaFormat::AudioCodec::Vorbis },
- { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265,
- QMediaFormat::VideoCodec::AV1 } },
- { QMediaFormat::Matroska, { QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::Opus,
- QMediaFormat::AudioCodec::Vorbis },
- { QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::VP9,
- QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265,
- QMediaFormat::VideoCodec::AV1} },
- { QMediaFormat::WebM, { QMediaFormat::AudioCodec::Opus, QMediaFormat::AudioCodec::Vorbis },
- { QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::VP9} }
- };
-
- // MP3 encoders doesn't seem to be supported by the default Android SDK
- encoders = {
- { QMediaFormat::AAC, { QMediaFormat::AudioCodec::AAC }, {} },
- { QMediaFormat::MP3, {}, {} },
- { QMediaFormat::FLAC, { QMediaFormat::AudioCodec::FLAC }, {} },
- { QMediaFormat::Mpeg4Audio, {QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::FLAC},
- {} },
- { QMediaFormat::MPEG4, { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::FLAC },
- { QMediaFormat::VideoCodec::H264 } }
- };
-
- // Opus encoder available only for Android 10+
- if (QNativeInterface::QAndroidApplication::sdkVersion() >= 29) {
- encoders.append({ QMediaFormat::Ogg, { QMediaFormat::AudioCodec::Opus }, {} });
- encoders.append({ QMediaFormat::Matroska, { QMediaFormat::AudioCodec::MP3,
- QMediaFormat::AudioCodec::Opus },
- { QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::H264 } });
- encoders.append({ QMediaFormat::WebM, { QMediaFormat::AudioCodec::Opus },
- { QMediaFormat::VideoCodec::VP8 } });
- } else {
- encoders.append({ QMediaFormat::Ogg, {}, {} });
- encoders.append({ QMediaFormat::Matroska, { QMediaFormat::AudioCodec::MP3 },
- { QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::H264 } });
- encoders.append({ QMediaFormat::WebM, {}, { QMediaFormat::VideoCodec::VP8 } });
- }
-
- imageFormats << QImageCapture::JPEG << QImageCapture::PNG << QImageCapture::WebP;
-}
-
-QAndroidFormatInfo::~QAndroidFormatInfo()
-{
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/qandroidformatsinfo_p.h b/src/multimedia/platform/android/qandroidformatsinfo_p.h
deleted file mode 100644
index 8810bb863..000000000
--- a/src/multimedia/platform/android/qandroidformatsinfo_p.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDFORMATINFO_H
-#define QANDROIDFORMATINFO_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaformatinfo_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidFormatInfo : public QPlatformMediaFormatInfo
-{
-public:
- QAndroidFormatInfo();
- ~QAndroidFormatInfo();
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/android/qandroidintegration.cpp b/src/multimedia/platform/android/qandroidintegration.cpp
deleted file mode 100644
index 5299275fa..000000000
--- a/src/multimedia/platform/android/qandroidintegration.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidintegration_p.h"
-#include "qandroidmediadevices_p.h"
-#include "private/qandroidglobal_p.h"
-#include "private/qandroidmediacapturesession_p.h"
-#include "private/androidmediaplayer_p.h"
-#include "private/qandroidcamerasession_p.h"
-#include "private/androidsurfacetexture_p.h"
-#include "private/androidsurfaceview_p.h"
-#include "private/androidcamera_p.h"
-#include "private/qandroidcamera_p.h"
-#include "private/qandroidimagecapture_p.h"
-#include "private/qandroidmediaencoder_p.h"
-#include "private/androidmediarecorder_p.h"
-#include "private/qandroidformatsinfo_p.h"
-#include "private/qandroidmediaplayer_p.h"
-#include "private/qandroidaudiooutput_p.h"
-#include "private/qandroidvideosink_p.h"
-#include "private/qandroidaudiodecoder_p.h"
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(qtAndroidMediaPlugin, "qt.multimedia.android")
-
-QAndroidIntegration::QAndroidIntegration()
-{
-
-}
-
-QAndroidIntegration::~QAndroidIntegration()
-{
- delete m_devices;
- delete m_formatInfo;
-}
-
-QPlatformMediaDevices *QAndroidIntegration::devices()
-{
- if (!m_devices)
- m_devices = new QAndroidMediaDevices();
- return m_devices;
-}
-
-QPlatformAudioDecoder *QAndroidIntegration::createAudioDecoder(QAudioDecoder *decoder)
-{
- return new QAndroidAudioDecoder(decoder);
-}
-
-QPlatformMediaFormatInfo *QAndroidIntegration::formatInfo()
-{
- if (!m_formatInfo)
- m_formatInfo = new QAndroidFormatInfo();
- return m_formatInfo;
-
-}
-
-QPlatformMediaCaptureSession *QAndroidIntegration::createCaptureSession()
-{
- return new QAndroidMediaCaptureSession();
-}
-
-QPlatformMediaPlayer *QAndroidIntegration::createPlayer(QMediaPlayer *player)
-{
- return new QAndroidMediaPlayer(player);
-}
-
-QPlatformCamera *QAndroidIntegration::createCamera(QCamera *camera)
-{
- return new QAndroidCamera(camera);
-}
-
-QPlatformMediaEncoder *QAndroidIntegration::createEncoder(QMediaRecorder *encoder)
-{
- return new QAndroidMediaEncoder(encoder);
-}
-
-QPlatformImageCapture *QAndroidIntegration::createImageCapture(QImageCapture *imageCapture)
-{
- return new QAndroidImageCapture(imageCapture);
-}
-
-QPlatformAudioOutput *QAndroidIntegration::createAudioOutput(QAudioOutput *q)
-{
- return new QAndroidAudioOutput(q);
-}
-
-QPlatformVideoSink *QAndroidIntegration::createVideoSink(QVideoSink *sink)
-{
- return new QAndroidVideoSink(sink);
-}
-
-Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
-{
- static bool initialized = false;
- if (initialized)
- return JNI_VERSION_1_6;
- initialized = true;
-
- QT_USE_NAMESPACE
- typedef union {
- JNIEnv *nativeEnvironment;
- void *venv;
- } UnionJNIEnvToVoid;
-
- UnionJNIEnvToVoid uenv;
- uenv.venv = NULL;
-
- if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK)
- return JNI_ERR;
-
- if (!AndroidMediaPlayer::registerNativeMethods()
- || !AndroidCamera::registerNativeMethods()
- || !AndroidMediaRecorder::registerNativeMethods()
- || !AndroidSurfaceHolder::registerNativeMethods()
- || !QAndroidMediaDevices::registerNativeMethods()) {
- return JNI_ERR;
- }
-
- AndroidSurfaceTexture::registerNativeMethods();
-
- return JNI_VERSION_1_6;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/qandroidintegration_p.h b/src/multimedia/platform/android/qandroidintegration_p.h
deleted file mode 100644
index a56881988..000000000
--- a/src/multimedia/platform/android/qandroidintegration_p.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDINTEGRATION_H
-#define QANDROIDINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidMediaDevices;
-
-class QAndroidIntegration : public QPlatformMediaIntegration
-{
-public:
- QAndroidIntegration();
- ~QAndroidIntegration();
-
- QPlatformMediaDevices *devices() override;
- QPlatformMediaFormatInfo *formatInfo() override;
-
- QPlatformAudioDecoder *createAudioDecoder(QAudioDecoder *decoder) override;
- QPlatformMediaCaptureSession *createCaptureSession() override;
- QPlatformMediaPlayer *createPlayer(QMediaPlayer *player) override;
- QPlatformCamera *createCamera(QCamera *camera) override;
- QPlatformMediaEncoder *createEncoder(QMediaRecorder *encoder) override;
- QPlatformImageCapture *createImageCapture(QImageCapture *imageCapture) override;
-
- QPlatformAudioOutput *createAudioOutput(QAudioOutput *q) override;
-
- QPlatformVideoSink *createVideoSink(QVideoSink *) override;
-
- QAndroidMediaDevices *m_devices = nullptr;
- QPlatformMediaFormatInfo *m_formatInfo = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/android/qandroidmediadevices.cpp b/src/multimedia/platform/android/qandroidmediadevices.cpp
deleted file mode 100644
index 6737c46c6..000000000
--- a/src/multimedia/platform/android/qandroidmediadevices.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidmediadevices_p.h"
-#include "qmediadevices.h"
-#include "qcameradevice_p.h"
-
-#include "private/qandroidaudiosource_p.h"
-#include "private/qandroidaudiosink_p.h"
-#include "private/qandroidaudiodevice_p.h"
-#include "private/qopenslesengine_p.h"
-#include "private/qplatformmediaintegration_p.h"
-#include "private/qandroidcamerasession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QAndroidMediaDevices::QAndroidMediaDevices()
- : QPlatformMediaDevices()
-{
-}
-
-QList<QAudioDevice> QAndroidMediaDevices::audioInputs() const
-{
- return QOpenSLESEngine::availableDevices(QAudioDevice::Input);
-}
-
-QList<QAudioDevice> QAndroidMediaDevices::audioOutputs() const
-{
- return QOpenSLESEngine::availableDevices(QAudioDevice::Output);
-}
-
-QList<QCameraDevice> QAndroidMediaDevices::videoInputs() const
-{
- return QAndroidCameraSession::availableCameras();
-}
-
-QPlatformAudioSource *QAndroidMediaDevices::createAudioSource(const QAudioDevice &deviceInfo)
-{
- return new QAndroidAudioSource(deviceInfo.id());
-}
-
-QPlatformAudioSink *QAndroidMediaDevices::createAudioSink(const QAudioDevice &deviceInfo)
-{
- return new QAndroidAudioSink(deviceInfo.id());
-}
-
-void QAndroidMediaDevices::forwardAudioOutputsChanged()
-{
- audioOutputsChanged();
-}
-
-void QAndroidMediaDevices::forwardAudioInputsChanged()
-{
- audioInputsChanged();
-}
-
-static void onAudioInputDevicesUpdated(JNIEnv */*env*/, jobject /*thiz*/)
-{
- static_cast<QAndroidMediaDevices*>(
- QPlatformMediaIntegration::instance()->devices())->forwardAudioInputsChanged();
-}
-
-static void onAudioOutputDevicesUpdated(JNIEnv */*env*/, jobject /*thiz*/)
-{
- static_cast<QAndroidMediaDevices*>(
- QPlatformMediaIntegration::instance()->devices())->forwardAudioOutputsChanged();
-}
-
-bool QAndroidMediaDevices::registerNativeMethods()
-{
- static const JNINativeMethod methods[] = {
- {"onAudioInputDevicesUpdated","()V",(void*)onAudioInputDevicesUpdated},
- {"onAudioOutputDevicesUpdated", "()V",(void*)onAudioOutputDevicesUpdated}
- };
- const int size = std::size(methods);
- return QJniEnvironment().registerNativeMethods(
- "org/qtproject/qt/android/multimedia/QtAudioDeviceManager", methods, size);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/qandroidmediadevices_p.h b/src/multimedia/platform/android/qandroidmediadevices_p.h
deleted file mode 100644
index 734678aad..000000000
--- a/src/multimedia/platform/android/qandroidmediadevices_p.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDMEDIADEVICES_H
-#define QANDROIDMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <qaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidMediaDevices : public QPlatformMediaDevices
-{
-public:
- QAndroidMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) override;
-
- void forwardAudioOutputsChanged();
- void forwardAudioInputsChanged();
- static bool registerNativeMethods();
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp b/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp
deleted file mode 100644
index e40921f38..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp
+++ /dev/null
@@ -1,1747 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Ruslan Baratov
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "androidcamera_p.h"
-#include "androidsurfacetexture_p.h"
-#include "androidsurfaceview_p.h"
-#include "qandroidmultimediautils_p.h"
-#include "qandroidglobal_p.h"
-
-#include <qstringlist.h>
-#include <qdebug.h>
-#include <QtCore/qthread.h>
-#include <QtCore/qreadwritelock.h>
-#include <QtCore/qmutex.h>
-#include <QtMultimedia/private/qmemoryvideobuffer_p.h>
-#include <QtCore/qcoreapplication.h>
-
-#include <mutex>
-
-QT_BEGIN_NAMESPACE
-
-static const char QtCameraListenerClassName[] = "org/qtproject/qt/android/multimedia/QtCameraListener";
-
-typedef QHash<int, AndroidCamera *> CameraMap;
-Q_GLOBAL_STATIC(CameraMap, cameras)
-Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
-
-static QRect areaToRect(jobject areaObj)
-{
- QJniObject area(areaObj);
- QJniObject rect = area.getObjectField("rect", "Landroid/graphics/Rect;");
-
- return QRect(rect.getField<jint>("left"),
- rect.getField<jint>("top"),
- rect.callMethod<jint>("width"),
- rect.callMethod<jint>("height"));
-}
-
-static QJniObject rectToArea(const QRect &rect)
-{
- QJniObject jrect("android/graphics/Rect",
- "(IIII)V",
- rect.left(), rect.top(), rect.right(), rect.bottom());
-
- QJniObject area("android/hardware/Camera$Area",
- "(Landroid/graphics/Rect;I)V",
- jrect.object(), 500);
-
- return area;
-}
-
-// native method for QtCameraLisener.java
-static void notifyAutoFocusComplete(JNIEnv* , jobject, int id, jboolean success)
-{
- QReadLocker locker(rwLock);
- const auto it = cameras->constFind(id);
- if (Q_UNLIKELY(it == cameras->cend()))
- return;
-
- Q_EMIT (*it)->autoFocusComplete(success);
-}
-
-static void notifyPictureExposed(JNIEnv* , jobject, int id)
-{
- QReadLocker locker(rwLock);
- const auto it = cameras->constFind(id);
- if (Q_UNLIKELY(it == cameras->cend()))
- return;
-
- Q_EMIT (*it)->pictureExposed();
-}
-
-static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
-{
- QReadLocker locker(rwLock);
- const auto it = cameras->constFind(id);
- if (Q_UNLIKELY(it == cameras->cend()))
- return;
-
- const int arrayLength = env->GetArrayLength(data);
- QByteArray bytes(arrayLength, Qt::Uninitialized);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
- Q_EMIT (*it)->pictureCaptured(bytes);
-}
-
-static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data,
- int width, int height, int format, int bpl)
-{
- QReadLocker locker(rwLock);
- const auto it = cameras->constFind(id);
- if (Q_UNLIKELY(it == cameras->cend()))
- return;
-
- const int arrayLength = env->GetArrayLength(data);
- if (arrayLength == 0)
- return;
-
- QByteArray bytes(arrayLength, Qt::Uninitialized);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
-
- QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl),
- QVideoFrameFormat(QSize(width, height),
- qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format))));
-
- Q_EMIT (*it)->newPreviewFrame(frame);
-}
-
-static void notifyFrameAvailable(JNIEnv *, jobject, int id)
-{
- QReadLocker locker(rwLock);
- const auto it = cameras->constFind(id);
- if (Q_UNLIKELY(it == cameras->cend()))
- return;
-
- (*it)->fetchLastPreviewFrame();
-}
-
-class AndroidCameraPrivate : public QObject
-{
- Q_OBJECT
-public:
- AndroidCameraPrivate();
- ~AndroidCameraPrivate();
-
- Q_INVOKABLE bool init(int cameraId);
-
- Q_INVOKABLE void release();
- Q_INVOKABLE bool lock();
- Q_INVOKABLE bool unlock();
- Q_INVOKABLE bool reconnect();
-
- Q_INVOKABLE AndroidCamera::CameraFacing getFacing();
- Q_INVOKABLE int getNativeOrientation();
-
- Q_INVOKABLE QSize getPreferredPreviewSizeForVideo();
- Q_INVOKABLE QList<QSize> getSupportedPreviewSizes();
- static QList<QSize> getSupportedPreviewSizes(QJniObject &parameters);
-
- Q_INVOKABLE QList<AndroidCamera::FpsRange> getSupportedPreviewFpsRange();
-
- Q_INVOKABLE AndroidCamera::FpsRange getPreviewFpsRange();
- static AndroidCamera::FpsRange getPreviewFpsRange(QJniObject &parameters);
- Q_INVOKABLE void setPreviewFpsRange(int min, int max);
-
- Q_INVOKABLE AndroidCamera::ImageFormat getPreviewFormat();
- Q_INVOKABLE void setPreviewFormat(AndroidCamera::ImageFormat fmt);
- Q_INVOKABLE QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats();
- static QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats(QJniObject &parameters);
-
- Q_INVOKABLE QSize previewSize() const { return m_previewSize; }
- Q_INVOKABLE QSize getPreviewSize();
- Q_INVOKABLE void updatePreviewSize();
- Q_INVOKABLE bool setPreviewTexture(void *surfaceTexture);
- Q_INVOKABLE bool setPreviewDisplay(void *surfaceHolder);
- Q_INVOKABLE void setDisplayOrientation(int degrees);
-
- Q_INVOKABLE bool isZoomSupported();
- Q_INVOKABLE int getMaxZoom();
- Q_INVOKABLE QList<int> getZoomRatios();
- Q_INVOKABLE int getZoom();
- Q_INVOKABLE void setZoom(int value);
-
- Q_INVOKABLE QString getFlashMode();
- Q_INVOKABLE void setFlashMode(const QString &value);
-
- Q_INVOKABLE QString getFocusMode();
- Q_INVOKABLE void setFocusMode(const QString &value);
-
- Q_INVOKABLE int getMaxNumFocusAreas();
- Q_INVOKABLE QList<QRect> getFocusAreas();
- Q_INVOKABLE void setFocusAreas(const QList<QRect> &areas);
-
- Q_INVOKABLE void autoFocus();
- Q_INVOKABLE void cancelAutoFocus();
-
- Q_INVOKABLE bool isAutoExposureLockSupported();
- Q_INVOKABLE bool getAutoExposureLock();
- Q_INVOKABLE void setAutoExposureLock(bool toggle);
-
- Q_INVOKABLE bool isAutoWhiteBalanceLockSupported();
- Q_INVOKABLE bool getAutoWhiteBalanceLock();
- Q_INVOKABLE void setAutoWhiteBalanceLock(bool toggle);
-
- Q_INVOKABLE int getExposureCompensation();
- Q_INVOKABLE void setExposureCompensation(int value);
- Q_INVOKABLE float getExposureCompensationStep();
- Q_INVOKABLE int getMinExposureCompensation();
- Q_INVOKABLE int getMaxExposureCompensation();
-
- Q_INVOKABLE QString getSceneMode();
- Q_INVOKABLE void setSceneMode(const QString &value);
-
- Q_INVOKABLE QString getWhiteBalance();
- Q_INVOKABLE void setWhiteBalance(const QString &value);
-
- Q_INVOKABLE void updateRotation();
-
- Q_INVOKABLE QList<QSize> getSupportedPictureSizes();
- Q_INVOKABLE void setPictureSize(const QSize &size);
- Q_INVOKABLE void setJpegQuality(int quality);
-
- Q_INVOKABLE void startPreview();
- Q_INVOKABLE void stopPreview();
-
- Q_INVOKABLE void takePicture();
-
- Q_INVOKABLE void setupPreviewFrameCallback();
- Q_INVOKABLE void notifyNewFrames(bool notify);
- Q_INVOKABLE void fetchLastPreviewFrame();
-
- Q_INVOKABLE void applyParameters();
-
- Q_INVOKABLE QStringList callParametersStringListMethod(const QByteArray &methodName);
-
- int m_cameraId;
- QRecursiveMutex m_parametersMutex;
- QSize m_previewSize;
- int m_rotation;
- QJniObject m_info;
- QJniObject m_parameters;
- QJniObject m_camera;
- QJniObject m_cameraListener;
-
-Q_SIGNALS:
- void previewSizeChanged();
- void previewStarted();
- void previewFailedToStart();
- void previewStopped();
-
- void autoFocusStarted();
-
- void whiteBalanceChanged();
-
- void takePictureFailed();
-
- void lastPreviewFrameFetched(const QVideoFrame &frame);
-};
-
-AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker)
- : QObject(),
- d_ptr(d),
- m_worker(worker)
-
-{
- connect(d, &AndroidCameraPrivate::previewSizeChanged, this, &AndroidCamera::previewSizeChanged);
- connect(d, &AndroidCameraPrivate::previewStarted, this, &AndroidCamera::previewStarted);
- connect(d, &AndroidCameraPrivate::previewFailedToStart, this, &AndroidCamera::previewFailedToStart);
- connect(d, &AndroidCameraPrivate::previewStopped, this, &AndroidCamera::previewStopped);
- connect(d, &AndroidCameraPrivate::autoFocusStarted, this, &AndroidCamera::autoFocusStarted);
- connect(d, &AndroidCameraPrivate::whiteBalanceChanged, this, &AndroidCamera::whiteBalanceChanged);
- connect(d, &AndroidCameraPrivate::takePictureFailed, this, &AndroidCamera::takePictureFailed);
- connect(d, &AndroidCameraPrivate::lastPreviewFrameFetched, this, &AndroidCamera::lastPreviewFrameFetched);
-}
-
-AndroidCamera::~AndroidCamera()
-{
- Q_D(AndroidCamera);
- if (d->m_camera.isValid()) {
- release();
- QWriteLocker locker(rwLock);
- cameras->remove(cameraId());
- }
-
- m_worker->exit();
- m_worker->wait(5000);
-}
-
-AndroidCamera *AndroidCamera::open(int cameraId)
-{
- if (!qt_androidRequestCameraPermission())
- return nullptr;
-
- AndroidCameraPrivate *d = new AndroidCameraPrivate();
- QThread *worker = new QThread;
- worker->start();
- d->moveToThread(worker);
- connect(worker, &QThread::finished, d, &AndroidCameraPrivate::deleteLater);
- bool ok = true;
- QMetaObject::invokeMethod(d, "init", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok), Q_ARG(int, cameraId));
- if (!ok) {
- worker->quit();
- worker->wait(5000);
- delete worker;
- return 0;
- }
-
- AndroidCamera *q = new AndroidCamera(d, worker);
- QWriteLocker locker(rwLock);
- cameras->insert(cameraId, q);
-
- return q;
-}
-
-int AndroidCamera::cameraId() const
-{
- Q_D(const AndroidCamera);
- return d->m_cameraId;
-}
-
-bool AndroidCamera::lock()
-{
- Q_D(AndroidCamera);
- bool ok = true;
- QMetaObject::invokeMethod(d, "lock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok));
- return ok;
-}
-
-bool AndroidCamera::unlock()
-{
- Q_D(AndroidCamera);
- bool ok = true;
- QMetaObject::invokeMethod(d, "unlock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok));
- return ok;
-}
-
-bool AndroidCamera::reconnect()
-{
- Q_D(AndroidCamera);
- bool ok = true;
- QMetaObject::invokeMethod(d, "reconnect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok));
- return ok;
-}
-
-void AndroidCamera::release()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "release", Qt::BlockingQueuedConnection);
-}
-
-AndroidCamera::CameraFacing AndroidCamera::getFacing()
-{
- Q_D(AndroidCamera);
- return d->getFacing();
-}
-
-int AndroidCamera::getNativeOrientation()
-{
- Q_D(AndroidCamera);
- return d->getNativeOrientation();
-}
-
-QSize AndroidCamera::getPreferredPreviewSizeForVideo()
-{
- Q_D(AndroidCamera);
- return d->getPreferredPreviewSizeForVideo();
-}
-
-QList<QSize> AndroidCamera::getSupportedPreviewSizes()
-{
- Q_D(AndroidCamera);
- return d->getSupportedPreviewSizes();
-}
-
-QList<AndroidCamera::FpsRange> AndroidCamera::getSupportedPreviewFpsRange()
-{
- Q_D(AndroidCamera);
- return d->getSupportedPreviewFpsRange();
-}
-
-AndroidCamera::FpsRange AndroidCamera::getPreviewFpsRange()
-{
- Q_D(AndroidCamera);
- return d->getPreviewFpsRange();
-}
-
-void AndroidCamera::setPreviewFpsRange(FpsRange range)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setPreviewFpsRange", Q_ARG(int, range.min), Q_ARG(int, range.max));
-}
-
-AndroidCamera::ImageFormat AndroidCamera::getPreviewFormat()
-{
- Q_D(AndroidCamera);
- return d->getPreviewFormat();
-}
-
-void AndroidCamera::setPreviewFormat(ImageFormat fmt)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setPreviewFormat", Q_ARG(AndroidCamera::ImageFormat, fmt));
-}
-
-QList<AndroidCamera::ImageFormat> AndroidCamera::getSupportedPreviewFormats()
-{
- Q_D(AndroidCamera);
- return d->getSupportedPreviewFormats();
-}
-
-QSize AndroidCamera::previewSize() const
-{
- Q_D(const AndroidCamera);
- return d->m_previewSize;
-}
-
-QSize AndroidCamera::actualPreviewSize()
-{
- Q_D(AndroidCamera);
- return d->getPreviewSize();
-}
-
-void AndroidCamera::setPreviewSize(const QSize &size)
-{
- Q_D(AndroidCamera);
- d->m_parametersMutex.lock();
- bool areParametersValid = d->m_parameters.isValid();
- d->m_parametersMutex.unlock();
- if (!areParametersValid)
- return;
-
- d->m_previewSize = size;
- QMetaObject::invokeMethod(d, "updatePreviewSize");
-}
-
-bool AndroidCamera::setPreviewTexture(AndroidSurfaceTexture *surfaceTexture)
-{
- Q_D(AndroidCamera);
- bool ok = true;
- QMetaObject::invokeMethod(d,
- "setPreviewTexture",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, ok),
- Q_ARG(void *, surfaceTexture ? surfaceTexture->surfaceTexture() : 0));
- return ok;
-}
-
-bool AndroidCamera::setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder)
-{
- Q_D(AndroidCamera);
- bool ok = true;
- QMetaObject::invokeMethod(d,
- "setPreviewDisplay",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(bool, ok),
- Q_ARG(void *, surfaceHolder ? surfaceHolder->surfaceHolder() : 0));
- return ok;
-}
-
-void AndroidCamera::setDisplayOrientation(int degrees)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setDisplayOrientation", Qt::QueuedConnection, Q_ARG(int, degrees));
-}
-
-bool AndroidCamera::isZoomSupported()
-{
- Q_D(AndroidCamera);
- return d->isZoomSupported();
-}
-
-int AndroidCamera::getMaxZoom()
-{
- Q_D(AndroidCamera);
- return d->getMaxZoom();
-}
-
-QList<int> AndroidCamera::getZoomRatios()
-{
- Q_D(AndroidCamera);
- return d->getZoomRatios();
-}
-
-int AndroidCamera::getZoom()
-{
- Q_D(AndroidCamera);
- return d->getZoom();
-}
-
-void AndroidCamera::setZoom(int value)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setZoom", Q_ARG(int, value));
-}
-
-QStringList AndroidCamera::getSupportedFlashModes()
-{
- Q_D(AndroidCamera);
- return d->callParametersStringListMethod("getSupportedFlashModes");
-}
-
-QString AndroidCamera::getFlashMode()
-{
- Q_D(AndroidCamera);
- return d->getFlashMode();
-}
-
-void AndroidCamera::setFlashMode(const QString &value)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setFlashMode", Q_ARG(QString, value));
-}
-
-QStringList AndroidCamera::getSupportedFocusModes()
-{
- Q_D(AndroidCamera);
- return d->callParametersStringListMethod("getSupportedFocusModes");
-}
-
-QString AndroidCamera::getFocusMode()
-{
- Q_D(AndroidCamera);
- return d->getFocusMode();
-}
-
-void AndroidCamera::setFocusMode(const QString &value)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setFocusMode", Q_ARG(QString, value));
-}
-
-int AndroidCamera::getMaxNumFocusAreas()
-{
- Q_D(AndroidCamera);
- return d->getMaxNumFocusAreas();
-}
-
-QList<QRect> AndroidCamera::getFocusAreas()
-{
- Q_D(AndroidCamera);
- return d->getFocusAreas();
-}
-
-void AndroidCamera::setFocusAreas(const QList<QRect> &areas)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setFocusAreas", Q_ARG(QList<QRect>, areas));
-}
-
-void AndroidCamera::autoFocus()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "autoFocus");
-}
-
-void AndroidCamera::cancelAutoFocus()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "cancelAutoFocus", Qt::QueuedConnection);
-}
-
-bool AndroidCamera::isAutoExposureLockSupported()
-{
- Q_D(AndroidCamera);
- return d->isAutoExposureLockSupported();
-}
-
-bool AndroidCamera::getAutoExposureLock()
-{
- Q_D(AndroidCamera);
- return d->getAutoExposureLock();
-}
-
-void AndroidCamera::setAutoExposureLock(bool toggle)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setAutoExposureLock", Q_ARG(bool, toggle));
-}
-
-bool AndroidCamera::isAutoWhiteBalanceLockSupported()
-{
- Q_D(AndroidCamera);
- return d->isAutoWhiteBalanceLockSupported();
-}
-
-bool AndroidCamera::getAutoWhiteBalanceLock()
-{
- Q_D(AndroidCamera);
- return d->getAutoWhiteBalanceLock();
-}
-
-void AndroidCamera::setAutoWhiteBalanceLock(bool toggle)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setAutoWhiteBalanceLock", Q_ARG(bool, toggle));
-}
-
-int AndroidCamera::getExposureCompensation()
-{
- Q_D(AndroidCamera);
- return d->getExposureCompensation();
-}
-
-void AndroidCamera::setExposureCompensation(int value)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setExposureCompensation", Q_ARG(int, value));
-}
-
-float AndroidCamera::getExposureCompensationStep()
-{
- Q_D(AndroidCamera);
- return d->getExposureCompensationStep();
-}
-
-int AndroidCamera::getMinExposureCompensation()
-{
- Q_D(AndroidCamera);
- return d->getMinExposureCompensation();
-}
-
-int AndroidCamera::getMaxExposureCompensation()
-{
- Q_D(AndroidCamera);
- return d->getMaxExposureCompensation();
-}
-
-QStringList AndroidCamera::getSupportedSceneModes()
-{
- Q_D(AndroidCamera);
- return d->callParametersStringListMethod("getSupportedSceneModes");
-}
-
-QString AndroidCamera::getSceneMode()
-{
- Q_D(AndroidCamera);
- return d->getSceneMode();
-}
-
-void AndroidCamera::setSceneMode(const QString &value)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setSceneMode", Q_ARG(QString, value));
-}
-
-QStringList AndroidCamera::getSupportedWhiteBalance()
-{
- Q_D(AndroidCamera);
- return d->callParametersStringListMethod("getSupportedWhiteBalance");
-}
-
-QString AndroidCamera::getWhiteBalance()
-{
- Q_D(AndroidCamera);
- return d->getWhiteBalance();
-}
-
-void AndroidCamera::setWhiteBalance(const QString &value)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setWhiteBalance", Q_ARG(QString, value));
-}
-
-void AndroidCamera::setRotation(int rotation)
-{
- Q_D(AndroidCamera);
- //We need to do it here and not in worker class because we cache rotation
- d->m_parametersMutex.lock();
- bool areParametersValid = d->m_parameters.isValid();
- d->m_parametersMutex.unlock();
- if (!areParametersValid)
- return;
-
- d->m_rotation = rotation;
- QMetaObject::invokeMethod(d, "updateRotation");
-}
-
-int AndroidCamera::getRotation() const
-{
- Q_D(const AndroidCamera);
- return d->m_rotation;
-}
-
-QList<QSize> AndroidCamera::getSupportedPictureSizes()
-{
- Q_D(AndroidCamera);
- return d->getSupportedPictureSizes();
-}
-
-void AndroidCamera::setPictureSize(const QSize &size)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setPictureSize", Q_ARG(QSize, size));
-}
-
-void AndroidCamera::setJpegQuality(int quality)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setJpegQuality", Q_ARG(int, quality));
-}
-
-void AndroidCamera::takePicture()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "takePicture", Qt::BlockingQueuedConnection);
-}
-
-void AndroidCamera::setupPreviewFrameCallback()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "setupPreviewFrameCallback");
-}
-
-void AndroidCamera::notifyNewFrames(bool notify)
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "notifyNewFrames", Q_ARG(bool, notify));
-}
-
-void AndroidCamera::fetchLastPreviewFrame()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "fetchLastPreviewFrame");
-}
-
-QJniObject AndroidCamera::getCameraObject()
-{
- Q_D(AndroidCamera);
- return d->m_camera;
-}
-
-int AndroidCamera::getNumberOfCameras()
-{
- if (!qt_androidRequestCameraPermission())
- return 0;
-
- return QJniObject::callStaticMethod<jint>("android/hardware/Camera",
- "getNumberOfCameras");
-}
-
-void AndroidCamera::getCameraInfo(int id, QCameraDevicePrivate *info)
-{
- Q_ASSERT(info);
-
- QJniObject cameraInfo("android/hardware/Camera$CameraInfo");
- QJniObject::callStaticMethod<void>("android/hardware/Camera",
- "getCameraInfo",
- "(ILandroid/hardware/Camera$CameraInfo;)V",
- id, cameraInfo.object());
-
- AndroidCamera::CameraFacing facing = AndroidCamera::CameraFacing(cameraInfo.getField<jint>("facing"));
- // The orientation provided by Android is counter-clockwise, we need it clockwise
- info->orientation = (360 - cameraInfo.getField<jint>("orientation")) % 360;
-
- switch (facing) {
- case AndroidCamera::CameraFacingBack:
- info->id = QByteArray("back");
- info->description = QStringLiteral("Rear-facing camera");
- info->position = QCameraDevice::BackFace;
- info->isDefault = true;
- break;
- case AndroidCamera::CameraFacingFront:
- info->id = QByteArray("front");
- info->description = QStringLiteral("Front-facing camera");
- info->position = QCameraDevice::FrontFace;
- break;
- default:
- break;
- }
-}
-
-QVideoFrameFormat::PixelFormat AndroidCamera::QtPixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat format)
-{
- switch (format) {
- case AndroidCamera::NV21:
- return QVideoFrameFormat::Format_NV21;
- case AndroidCamera::YUY2:
- return QVideoFrameFormat::Format_YUYV;
- case AndroidCamera::JPEG:
- return QVideoFrameFormat::Format_Jpeg;
- case AndroidCamera::YV12:
- return QVideoFrameFormat::Format_YV12;
- default:
- return QVideoFrameFormat::Format_Invalid;
- }
-}
-
-AndroidCamera::ImageFormat AndroidCamera::AndroidImageFormatFromQtPixelFormat(QVideoFrameFormat::PixelFormat format)
-{
- switch (format) {
- case QVideoFrameFormat::Format_NV21:
- return AndroidCamera::NV21;
- case QVideoFrameFormat::Format_YUYV:
- return AndroidCamera::YUY2;
- case QVideoFrameFormat::Format_Jpeg:
- return AndroidCamera::JPEG;
- case QVideoFrameFormat::Format_YV12:
- return AndroidCamera::YV12;
- default:
- return AndroidCamera::UnknownImageFormat;
- }
-}
-
-void AndroidCamera::getSupportedFormats(int id, QList<QCameraFormat> &formats)
-{
- QJniObject camera = QJniObject::callStaticObjectMethod("android/hardware/Camera",
- "open",
- "(I)Landroid/hardware/Camera;",
- id);
- if (!camera.isValid())
- return;
-
- QJniObject cameraParams = camera.callObjectMethod("getParameters",
- "()Landroid/hardware/Camera$Parameters;");
- if (!cameraParams.isValid()) {
- camera.callMethod<void>("release");
- return;
- }
- AndroidCamera::FpsRange range = AndroidCameraPrivate::getPreviewFpsRange(cameraParams);
-
- for (const auto &previewSize : AndroidCameraPrivate::getSupportedPreviewSizes(cameraParams))
- {
- for (const auto &previewFormat : AndroidCameraPrivate::getSupportedPreviewFormats(cameraParams))
- {
- QCameraFormatPrivate * format = new QCameraFormatPrivate();
- format->pixelFormat = QtPixelFormatFromAndroidImageFormat(previewFormat);
- format->resolution = previewSize;
- format->minFrameRate = range.min;
- format->maxFrameRate = range.max;
- formats.append(format->create());
- }
- }
-
- camera.callMethod<void>("release");
-}
-
-void AndroidCamera::startPreview()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "startPreview");
-}
-
-void AndroidCamera::stopPreview()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "stopPreview");
-}
-
-void AndroidCamera::stopPreviewSynchronous()
-{
- Q_D(AndroidCamera);
- QMetaObject::invokeMethod(d, "stopPreview", Qt::BlockingQueuedConnection);
-}
-
-AndroidCameraPrivate::AndroidCameraPrivate()
- : QObject()
-{
-}
-
-AndroidCameraPrivate::~AndroidCameraPrivate()
-{
-}
-
-static qint32 s_activeCameras = 0;
-
-bool AndroidCameraPrivate::init(int cameraId)
-{
- m_cameraId = cameraId;
- QJniEnvironment env;
-
- const bool opened = s_activeCameras & (1 << cameraId);
- if (opened)
- return false;
-
- m_camera = QJniObject::callStaticObjectMethod("android/hardware/Camera",
- "open",
- "(I)Landroid/hardware/Camera;",
- cameraId);
- if (!m_camera.isValid())
- return false;
-
- m_cameraListener = QJniObject(QtCameraListenerClassName, "(I)V", m_cameraId);
- m_info = QJniObject("android/hardware/Camera$CameraInfo");
- m_camera.callStaticMethod<void>("android/hardware/Camera",
- "getCameraInfo",
- "(ILandroid/hardware/Camera$CameraInfo;)V",
- cameraId,
- m_info.object());
-
- QJniObject params = m_camera.callObjectMethod("getParameters",
- "()Landroid/hardware/Camera$Parameters;");
- m_parameters = QJniObject(params);
- s_activeCameras |= 1 << cameraId;
-
- return true;
-}
-
-void AndroidCameraPrivate::release()
-{
- m_previewSize = QSize();
- m_parametersMutex.lock();
- m_parameters = QJniObject();
- m_parametersMutex.unlock();
- if (m_camera.isValid()) {
- m_camera.callMethod<void>("release");
- s_activeCameras &= ~(1 << m_cameraId);
- }
-}
-
-bool AndroidCameraPrivate::lock()
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "lock", "()V");
- env->CallVoidMethod(m_camera.object(), methodId);
-
- if (env.checkAndClearExceptions())
- return false;
- return true;
-}
-
-bool AndroidCameraPrivate::unlock()
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "unlock", "()V");
- env->CallVoidMethod(m_camera.object(), methodId);
-
- if (env.checkAndClearExceptions())
- return false;
- return true;
-}
-
-bool AndroidCameraPrivate::reconnect()
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "reconnect", "()V");
- env->CallVoidMethod(m_camera.object(), methodId);
-
- if (env.checkAndClearExceptions())
- return false;
- return true;
-}
-
-AndroidCamera::CameraFacing AndroidCameraPrivate::getFacing()
-{
- return AndroidCamera::CameraFacing(m_info.getField<jint>("facing"));
-}
-
-int AndroidCameraPrivate::getNativeOrientation()
-{
- return m_info.getField<jint>("orientation");
-}
-
-QSize AndroidCameraPrivate::getPreferredPreviewSizeForVideo()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return QSize();
-
- QJniObject size = m_parameters.callObjectMethod("getPreferredPreviewSizeForVideo",
- "()Landroid/hardware/Camera$Size;");
-
- if (!size.isValid())
- return QSize();
-
- return QSize(size.getField<jint>("width"), size.getField<jint>("height"));
-}
-
-QList<QSize> AndroidCameraPrivate::getSupportedPreviewSizes()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
- return getSupportedPreviewSizes(m_parameters);
-}
-
-QList<QSize> AndroidCameraPrivate::getSupportedPreviewSizes(QJniObject &parameters)
-{
- QList<QSize> list;
-
- if (parameters.isValid()) {
- QJniObject sizeList = parameters.callObjectMethod("getSupportedPreviewSizes",
- "()Ljava/util/List;");
- int count = sizeList.callMethod<jint>("size");
- for (int i = 0; i < count; ++i) {
- QJniObject size = sizeList.callObjectMethod("get",
- "(I)Ljava/lang/Object;",
- i);
- list.append(QSize(size.getField<jint>("width"), size.getField<jint>("height")));
- }
-
- std::sort(list.begin(), list.end(), qt_sizeLessThan);
- }
-
- return list;
-}
-
-QList<AndroidCamera::FpsRange> AndroidCameraPrivate::getSupportedPreviewFpsRange()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QJniEnvironment env;
-
- QList<AndroidCamera::FpsRange> rangeList;
-
- if (m_parameters.isValid()) {
- QJniObject rangeListNative = m_parameters.callObjectMethod("getSupportedPreviewFpsRange",
- "()Ljava/util/List;");
- int count = rangeListNative.callMethod<jint>("size");
-
- rangeList.reserve(count);
-
- for (int i = 0; i < count; ++i) {
- QJniObject range = rangeListNative.callObjectMethod("get",
- "(I)Ljava/lang/Object;",
- i);
-
- jintArray jRange = static_cast<jintArray>(range.object());
- jint* rangeArray = env->GetIntArrayElements(jRange, 0);
-
- AndroidCamera::FpsRange fpsRange;
-
- fpsRange.min = rangeArray[0];
- fpsRange.max = rangeArray[1];
-
- env->ReleaseIntArrayElements(jRange, rangeArray, 0);
-
- rangeList << fpsRange;
- }
- }
-
- return rangeList;
-}
-
-AndroidCamera::FpsRange AndroidCameraPrivate::getPreviewFpsRange()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
- return getPreviewFpsRange(m_parameters);
-}
-
-AndroidCamera::FpsRange AndroidCameraPrivate::getPreviewFpsRange(QJniObject &parameters)
-{
- QJniEnvironment env;
-
- AndroidCamera::FpsRange range;
-
- if (!parameters.isValid())
- return range;
-
- jintArray jRangeArray = env->NewIntArray(2);
- parameters.callMethod<void>("getPreviewFpsRange", "([I)V", jRangeArray);
-
- jint* jRangeElements = env->GetIntArrayElements(jRangeArray, 0);
-
- range.min = jRangeElements[0];
- range.max = jRangeElements[1];
-
- env->ReleaseIntArrayElements(jRangeArray, jRangeElements, 0);
- env->DeleteLocalRef(jRangeArray);
-
- return range;
-}
-
-void AndroidCameraPrivate::setPreviewFpsRange(int min, int max)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- QJniEnvironment env;
- m_parameters.callMethod<void>("setPreviewFpsRange", "(II)V", min, max);
-}
-
-AndroidCamera::ImageFormat AndroidCameraPrivate::getPreviewFormat()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return AndroidCamera::UnknownImageFormat;
-
- return AndroidCamera::ImageFormat(m_parameters.callMethod<jint>("getPreviewFormat"));
-}
-
-void AndroidCameraPrivate::setPreviewFormat(AndroidCamera::ImageFormat fmt)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setPreviewFormat", "(I)V", jint(fmt));
- applyParameters();
-}
-
-QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
- return getSupportedPreviewFormats(m_parameters);
-}
-
-QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats(QJniObject &parameters)
-{
- QList<AndroidCamera::ImageFormat> list;
-
- if (parameters.isValid()) {
- QJniObject formatList = parameters.callObjectMethod("getSupportedPreviewFormats",
- "()Ljava/util/List;");
- int count = formatList.callMethod<jint>("size");
- for (int i = 0; i < count; ++i) {
- QJniObject format = formatList.callObjectMethod("get",
- "(I)Ljava/lang/Object;",
- i);
- list.append(AndroidCamera::ImageFormat(format.callMethod<jint>("intValue")));
- }
- }
-
- return list;
-}
-
-QSize AndroidCameraPrivate::getPreviewSize()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return QSize();
-
- QJniObject size = m_parameters.callObjectMethod("getPreviewSize",
- "()Landroid/hardware/Camera$Size;");
-
- if (!size.isValid())
- return QSize();
-
- return QSize(size.getField<jint>("width"), size.getField<jint>("height"));
-}
-
-void AndroidCameraPrivate::updatePreviewSize()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (m_previewSize.isValid()) {
- m_parameters.callMethod<void>("setPreviewSize", "(II)V", m_previewSize.width(), m_previewSize.height());
- applyParameters();
- }
-
- emit previewSizeChanged();
-}
-
-bool AndroidCameraPrivate::setPreviewTexture(void *surfaceTexture)
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "setPreviewTexture",
- "(Landroid/graphics/SurfaceTexture;)V");
- env->CallVoidMethod(m_camera.object(), methodId, static_cast<jobject>(surfaceTexture));
-
- if (env.checkAndClearExceptions())
- return false;
- return true;
-}
-
-bool AndroidCameraPrivate::setPreviewDisplay(void *surfaceHolder)
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "setPreviewDisplay",
- "(Landroid/view/SurfaceHolder;)V");
- env->CallVoidMethod(m_camera.object(), methodId, static_cast<jobject>(surfaceHolder));
-
- if (env.checkAndClearExceptions())
- return false;
- return true;
-}
-
-void AndroidCameraPrivate::setDisplayOrientation(int degrees)
-{
- m_camera.callMethod<void>("setDisplayOrientation", "(I)V", degrees);
-}
-
-bool AndroidCameraPrivate::isZoomSupported()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return false;
-
- return m_parameters.callMethod<jboolean>("isZoomSupported");
-}
-
-int AndroidCameraPrivate::getMaxZoom()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return 0;
-
- return m_parameters.callMethod<jint>("getMaxZoom");
-}
-
-QList<int> AndroidCameraPrivate::getZoomRatios()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QList<int> ratios;
-
- if (m_parameters.isValid()) {
- QJniObject ratioList = m_parameters.callObjectMethod("getZoomRatios",
- "()Ljava/util/List;");
- int count = ratioList.callMethod<jint>("size");
- for (int i = 0; i < count; ++i) {
- QJniObject zoomRatio = ratioList.callObjectMethod("get",
- "(I)Ljava/lang/Object;",
- i);
-
- ratios.append(zoomRatio.callMethod<jint>("intValue"));
- }
- }
-
- return ratios;
-}
-
-int AndroidCameraPrivate::getZoom()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return 0;
-
- return m_parameters.callMethod<jint>("getZoom");
-}
-
-void AndroidCameraPrivate::setZoom(int value)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setZoom", "(I)V", value);
- applyParameters();
-}
-
-QString AndroidCameraPrivate::getFlashMode()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QString value;
-
- if (m_parameters.isValid()) {
- QJniObject flashMode = m_parameters.callObjectMethod("getFlashMode",
- "()Ljava/lang/String;");
- if (flashMode.isValid())
- value = flashMode.toString();
- }
-
- return value;
-}
-
-void AndroidCameraPrivate::setFlashMode(const QString &value)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setFlashMode",
- "(Ljava/lang/String;)V",
- QJniObject::fromString(value).object());
- applyParameters();
-}
-
-QString AndroidCameraPrivate::getFocusMode()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QString value;
-
- if (m_parameters.isValid()) {
- QJniObject focusMode = m_parameters.callObjectMethod("getFocusMode",
- "()Ljava/lang/String;");
- if (focusMode.isValid())
- value = focusMode.toString();
- }
-
- return value;
-}
-
-void AndroidCameraPrivate::setFocusMode(const QString &value)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setFocusMode",
- "(Ljava/lang/String;)V",
- QJniObject::fromString(value).object());
- applyParameters();
-}
-
-int AndroidCameraPrivate::getMaxNumFocusAreas()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return 0;
-
- return m_parameters.callMethod<jint>("getMaxNumFocusAreas");
-}
-
-QList<QRect> AndroidCameraPrivate::getFocusAreas()
-{
- QList<QRect> areas;
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (m_parameters.isValid()) {
- QJniObject list = m_parameters.callObjectMethod("getFocusAreas",
- "()Ljava/util/List;");
-
- if (list.isValid()) {
- int count = list.callMethod<jint>("size");
- for (int i = 0; i < count; ++i) {
- QJniObject area = list.callObjectMethod("get",
- "(I)Ljava/lang/Object;",
- i);
-
- areas.append(areaToRect(area.object()));
- }
- }
- }
-
- return areas;
-}
-
-void AndroidCameraPrivate::setFocusAreas(const QList<QRect> &areas)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid() || areas.isEmpty())
- return;
-
- QJniObject list;
-
- if (!areas.isEmpty()) {
- QJniEnvironment env;
- QJniObject arrayList("java/util/ArrayList", "(I)V", areas.size());
- for (int i = 0; i < areas.size(); ++i) {
- arrayList.callMethod<jboolean>("add",
- "(Ljava/lang/Object;)Z",
- rectToArea(areas.at(i)).object());
- }
- list = arrayList;
- }
-
- m_parameters.callMethod<void>("setFocusAreas", "(Ljava/util/List;)V", list.object());
-
- applyParameters();
-}
-
-void AndroidCameraPrivate::autoFocus()
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "autoFocus",
- "(Landroid/hardware/Camera$AutoFocusCallback;)V");
- env->CallVoidMethod(m_camera.object(), methodId, m_cameraListener.object());
-
- if (!env.checkAndClearExceptions())
- emit autoFocusStarted();
-}
-
-void AndroidCameraPrivate::cancelAutoFocus()
-{
- QJniEnvironment env;
- m_camera.callMethod<void>("cancelAutoFocus");
-}
-
-bool AndroidCameraPrivate::isAutoExposureLockSupported()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return false;
-
- return m_parameters.callMethod<jboolean>("isAutoExposureLockSupported");
-}
-
-bool AndroidCameraPrivate::getAutoExposureLock()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return false;
-
- return m_parameters.callMethod<jboolean>("getAutoExposureLock");
-}
-
-void AndroidCameraPrivate::setAutoExposureLock(bool toggle)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setAutoExposureLock", "(Z)V", toggle);
- applyParameters();
-}
-
-bool AndroidCameraPrivate::isAutoWhiteBalanceLockSupported()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return false;
-
- return m_parameters.callMethod<jboolean>("isAutoWhiteBalanceLockSupported");
-}
-
-bool AndroidCameraPrivate::getAutoWhiteBalanceLock()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return false;
-
- return m_parameters.callMethod<jboolean>("getAutoWhiteBalanceLock");
-}
-
-void AndroidCameraPrivate::setAutoWhiteBalanceLock(bool toggle)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setAutoWhiteBalanceLock", "(Z)V", toggle);
- applyParameters();
-}
-
-int AndroidCameraPrivate::getExposureCompensation()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return 0;
-
- return m_parameters.callMethod<jint>("getExposureCompensation");
-}
-
-void AndroidCameraPrivate::setExposureCompensation(int value)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setExposureCompensation", "(I)V", value);
- applyParameters();
-}
-
-float AndroidCameraPrivate::getExposureCompensationStep()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return 0;
-
- return m_parameters.callMethod<jfloat>("getExposureCompensationStep");
-}
-
-int AndroidCameraPrivate::getMinExposureCompensation()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return 0;
-
- return m_parameters.callMethod<jint>("getMinExposureCompensation");
-}
-
-int AndroidCameraPrivate::getMaxExposureCompensation()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return 0;
-
- return m_parameters.callMethod<jint>("getMaxExposureCompensation");
-}
-
-QString AndroidCameraPrivate::getSceneMode()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QString value;
-
- if (m_parameters.isValid()) {
- QJniObject sceneMode = m_parameters.callObjectMethod("getSceneMode",
- "()Ljava/lang/String;");
- if (sceneMode.isValid())
- value = sceneMode.toString();
- }
-
- return value;
-}
-
-void AndroidCameraPrivate::setSceneMode(const QString &value)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setSceneMode",
- "(Ljava/lang/String;)V",
- QJniObject::fromString(value).object());
- applyParameters();
-}
-
-QString AndroidCameraPrivate::getWhiteBalance()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QString value;
-
- if (m_parameters.isValid()) {
- QJniObject wb = m_parameters.callObjectMethod("getWhiteBalance",
- "()Ljava/lang/String;");
- if (wb.isValid())
- value = wb.toString();
- }
-
- return value;
-}
-
-void AndroidCameraPrivate::setWhiteBalance(const QString &value)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setWhiteBalance",
- "(Ljava/lang/String;)V",
- QJniObject::fromString(value).object());
- applyParameters();
-
- emit whiteBalanceChanged();
-}
-
-void AndroidCameraPrivate::updateRotation()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- m_parameters.callMethod<void>("setRotation", "(I)V", m_rotation);
- applyParameters();
-}
-
-QList<QSize> AndroidCameraPrivate::getSupportedPictureSizes()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QList<QSize> list;
-
- if (m_parameters.isValid()) {
- QJniObject sizeList = m_parameters.callObjectMethod("getSupportedPictureSizes",
- "()Ljava/util/List;");
- int count = sizeList.callMethod<jint>("size");
- for (int i = 0; i < count; ++i) {
- QJniObject size = sizeList.callObjectMethod("get",
- "(I)Ljava/lang/Object;",
- i);
- list.append(QSize(size.getField<jint>("width"), size.getField<jint>("height")));
- }
-
- std::sort(list.begin(), list.end(), qt_sizeLessThan);
- }
-
- return list;
-}
-
-void AndroidCameraPrivate::setPictureSize(const QSize &size)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setPictureSize", "(II)V", size.width(), size.height());
- applyParameters();
-}
-
-void AndroidCameraPrivate::setJpegQuality(int quality)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- if (!m_parameters.isValid())
- return;
-
- m_parameters.callMethod<void>("setJpegQuality", "(I)V", quality);
- applyParameters();
-}
-
-void AndroidCameraPrivate::startPreview()
-{
- setupPreviewFrameCallback();
-
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "startPreview", "()V");
- env->CallVoidMethod(m_camera.object(), methodId);
-
- if (env.checkAndClearExceptions())
- emit previewFailedToStart();
- else
- emit previewStarted();
-}
-
-void AndroidCameraPrivate::stopPreview()
-{
- // cancel any pending new frame notification
- m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", false);
- m_camera.callMethod<void>("stopPreview");
- emit previewStopped();
-}
-
-void AndroidCameraPrivate::takePicture()
-{
- // We must clear the preview callback before calling takePicture(), otherwise the call will
- // block and the camera server will be frozen until the next device restart...
- // That problem only happens on some devices and on the emulator
- m_cameraListener.callMethod<void>("clearPreviewCallback", "(Landroid/hardware/Camera;)V", m_camera.object());
-
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_camera.objectClass(), "takePicture",
- "(Landroid/hardware/Camera$ShutterCallback;"
- "Landroid/hardware/Camera$PictureCallback;"
- "Landroid/hardware/Camera$PictureCallback;)V");
- env->CallVoidMethod(m_camera.object(), methodId, m_cameraListener.object(),
- jobject(0), m_cameraListener.object());
-
- if (env.checkAndClearExceptions())
- emit takePictureFailed();
-}
-
-void AndroidCameraPrivate::setupPreviewFrameCallback()
-{
- m_cameraListener.callMethod<void>("setupPreviewCallback", "(Landroid/hardware/Camera;)V", m_camera.object());
-}
-
-void AndroidCameraPrivate::notifyNewFrames(bool notify)
-{
- m_cameraListener.callMethod<void>("notifyNewFrames", "(Z)V", notify);
-}
-
-void AndroidCameraPrivate::fetchLastPreviewFrame()
-{
- QJniEnvironment env;
- QJniObject data = m_cameraListener.callObjectMethod("lastPreviewBuffer", "()[B");
-
- if (!data.isValid()) {
- // If there's no buffer received yet, retry when the next one arrives
- m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", true);
- return;
- }
-
- const int arrayLength = env->GetArrayLength(static_cast<jbyteArray>(data.object()));
- if (arrayLength == 0)
- return;
-
- QByteArray bytes(arrayLength, Qt::Uninitialized);
- env->GetByteArrayRegion(static_cast<jbyteArray>(data.object()),
- 0,
- arrayLength,
- reinterpret_cast<jbyte *>(bytes.data()));
-
- const int width = m_cameraListener.callMethod<jint>("previewWidth");
- const int height = m_cameraListener.callMethod<jint>("previewHeight");
- const int format = m_cameraListener.callMethod<jint>("previewFormat");
- const int bpl = m_cameraListener.callMethod<jint>("previewBytesPerLine");
-
- QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl),
- QVideoFrameFormat(QSize(width, height),
- qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format))));
-
- emit lastPreviewFrameFetched(frame);
-}
-
-void AndroidCameraPrivate::applyParameters()
-{
- QJniEnvironment env;
- m_camera.callMethod<void>("setParameters",
- "(Landroid/hardware/Camera$Parameters;)V",
- m_parameters.object());
-}
-
-QStringList AndroidCameraPrivate::callParametersStringListMethod(const QByteArray &methodName)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
-
- QStringList stringList;
-
- if (m_parameters.isValid()) {
- QJniObject list = m_parameters.callObjectMethod(methodName.constData(),
- "()Ljava/util/List;");
-
- if (list.isValid()) {
- int count = list.callMethod<jint>("size");
- for (int i = 0; i < count; ++i) {
- QJniObject string = list.callObjectMethod("get",
- "(I)Ljava/lang/Object;",
- i);
- stringList.append(string.toString());
- }
- }
- }
-
- return stringList;
-}
-
-bool AndroidCamera::registerNativeMethods()
-{
- static const JNINativeMethod methods[] = {
- {"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
- {"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
- {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
- {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame},
- {"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable}
- };
-
- const int size = std::size(methods);
- return QJniEnvironment().registerNativeMethods(QtCameraListenerClassName, methods, size);
-}
-
-QT_END_NAMESPACE
-
-#include "androidcamera.moc"
diff --git a/src/multimedia/platform/android/wrappers/jni/androidcamera_p.h b/src/multimedia/platform/android/wrappers/jni/androidcamera_p.h
deleted file mode 100644
index 94c2d3c46..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidcamera_p.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Ruslan Baratov
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef ANDROIDCAMERA_H
-#define ANDROIDCAMERA_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 <qsize.h>
-#include <qrect.h>
-#include <QtMultimedia/qcamera.h>
-#include <QtCore/qjniobject.h>
-#include <private/qcameradevice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QThread;
-
-class AndroidCameraPrivate;
-class AndroidSurfaceTexture;
-class AndroidSurfaceHolder;
-
-class AndroidCamera : public QObject
-{
- Q_OBJECT
-public:
- enum CameraFacing {
- CameraFacingBack = 0,
- CameraFacingFront = 1
- };
- Q_ENUM(CameraFacing)
-
- enum ImageFormat { // same values as in android.graphics.ImageFormat Java class
- UnknownImageFormat = 0,
- RGB565 = 4,
- NV16 = 16,
- NV21 = 17,
- YUY2 = 20,
- JPEG = 256,
- YV12 = 842094169
- };
- Q_ENUM(ImageFormat)
-
- // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getSupportedPreviewFpsRange%28%29
- // "The values are multiplied by 1000 and represented in integers"
- struct FpsRange {
- int min;
- int max;
-
- FpsRange(): min(0), max(0) {}
-
- qreal getMinReal() const { return min / 1000.0; }
- qreal getMaxReal() const { return max / 1000.0; }
-
- static FpsRange makeFromQReal(qreal min, qreal max)
- {
- FpsRange range;
- range.min = static_cast<int>(min * 1000.0);
- range.max = static_cast<int>(max * 1000.0);
- return range;
- }
- };
-
- ~AndroidCamera();
-
- static AndroidCamera *open(int cameraId);
-
- int cameraId() const;
-
- bool lock();
- bool unlock();
- bool reconnect();
- void release();
-
- CameraFacing getFacing();
- int getNativeOrientation();
-
- QSize getPreferredPreviewSizeForVideo();
- QList<QSize> getSupportedPreviewSizes();
-
- QList<FpsRange> getSupportedPreviewFpsRange();
-
- FpsRange getPreviewFpsRange();
- void setPreviewFpsRange(FpsRange);
-
- ImageFormat getPreviewFormat();
- void setPreviewFormat(ImageFormat fmt);
- QList<ImageFormat> getSupportedPreviewFormats();
-
- QSize previewSize() const;
- QSize actualPreviewSize();
- void setPreviewSize(const QSize &size);
- bool setPreviewTexture(AndroidSurfaceTexture *surfaceTexture);
- bool setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder);
- void setDisplayOrientation(int degrees);
-
- bool isZoomSupported();
- int getMaxZoom();
- QList<int> getZoomRatios();
- int getZoom();
- void setZoom(int value);
-
- QStringList getSupportedFlashModes();
- QString getFlashMode();
- void setFlashMode(const QString &value);
-
- QStringList getSupportedFocusModes();
- QString getFocusMode();
- void setFocusMode(const QString &value);
-
- int getMaxNumFocusAreas();
- QList<QRect> getFocusAreas();
- void setFocusAreas(const QList<QRect> &areas);
-
- void autoFocus();
- void cancelAutoFocus();
-
- bool isAutoExposureLockSupported();
- bool getAutoExposureLock();
- void setAutoExposureLock(bool toggle);
-
- bool isAutoWhiteBalanceLockSupported();
- bool getAutoWhiteBalanceLock();
- void setAutoWhiteBalanceLock(bool toggle);
-
- int getExposureCompensation();
- void setExposureCompensation(int value);
- float getExposureCompensationStep();
- int getMinExposureCompensation();
- int getMaxExposureCompensation();
-
- QStringList getSupportedSceneModes();
- QString getSceneMode();
- void setSceneMode(const QString &value);
-
- QStringList getSupportedWhiteBalance();
- QString getWhiteBalance();
- void setWhiteBalance(const QString &value);
-
- void setRotation(int rotation);
- int getRotation() const;
-
- QList<QSize> getSupportedPictureSizes();
- void setPictureSize(const QSize &size);
- void setJpegQuality(int quality);
-
- void startPreview();
- void stopPreview();
- void stopPreviewSynchronous();
-
- void takePicture();
-
- void setupPreviewFrameCallback();
- void notifyNewFrames(bool notify);
- void fetchLastPreviewFrame();
- QJniObject getCameraObject();
-
- static int getNumberOfCameras();
- static void getCameraInfo(int id, QCameraDevicePrivate *info);
- static QVideoFrameFormat::PixelFormat QtPixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat);
- static AndroidCamera::ImageFormat AndroidImageFormatFromQtPixelFormat(QVideoFrameFormat::PixelFormat);
- static void getSupportedFormats(int id, QList<QCameraFormat> &formats);
- static bool requestCameraPermission();
-
- static bool registerNativeMethods();
-Q_SIGNALS:
- void previewSizeChanged();
- void previewStarted();
- void previewFailedToStart();
- void previewStopped();
-
- void autoFocusStarted();
- void autoFocusComplete(bool success);
-
- void whiteBalanceChanged();
-
- void takePictureFailed();
- void pictureExposed();
- void pictureCaptured(const QByteArray &data);
- void lastPreviewFrameFetched(const QVideoFrame &frame);
- void newPreviewFrame(const QVideoFrame &frame);
-
-private:
- AndroidCamera(AndroidCameraPrivate *d, QThread *worker);
-
- Q_DECLARE_PRIVATE(AndroidCamera)
- AndroidCameraPrivate *d_ptr;
- QScopedPointer<QThread> m_worker;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(AndroidCamera::ImageFormat)
-
-#endif // ANDROIDCAMERA_H
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever.cpp b/src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever.cpp
deleted file mode 100644
index 733717ae7..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "androidmediametadataretriever_p.h"
-
-#include <QtCore/QUrl>
-#include <qdebug.h>
-#include <QtCore/qcoreapplication.h>
-
-QT_BEGIN_NAMESPACE
-
-AndroidMediaMetadataRetriever::AndroidMediaMetadataRetriever()
-{
- m_metadataRetriever = QJniObject("android/media/MediaMetadataRetriever");
-}
-
-AndroidMediaMetadataRetriever::~AndroidMediaMetadataRetriever()
-{
- release();
-}
-
-QString AndroidMediaMetadataRetriever::extractMetadata(MetadataKey key)
-{
- QString value;
-
- QJniObject metadata = m_metadataRetriever.callObjectMethod("extractMetadata",
- "(I)Ljava/lang/String;",
- jint(key));
- if (metadata.isValid())
- value = metadata.toString();
-
- return value;
-}
-
-void AndroidMediaMetadataRetriever::release()
-{
- if (!m_metadataRetriever.isValid())
- return;
-
- m_metadataRetriever.callMethod<void>("release");
-}
-
-bool AndroidMediaMetadataRetriever::setDataSource(const QUrl &url)
-{
- if (!m_metadataRetriever.isValid())
- return false;
-
- QJniEnvironment env;
- if (url.isLocalFile()) { // also includes qrc files (copied to a temp file by QMediaPlayer)
- QJniObject string = QJniObject::fromString(url.path());
- QJniObject fileInputStream("java/io/FileInputStream",
- "(Ljava/lang/String;)V",
- string.object());
-
- if (!fileInputStream.isValid())
- return false;
-
- QJniObject fd = fileInputStream.callObjectMethod("getFD",
- "()Ljava/io/FileDescriptor;");
- if (!fd.isValid()) {
- fileInputStream.callMethod<void>("close");
- return false;
- }
-
- auto methodId = env->GetMethodID(m_metadataRetriever.objectClass(), "setDataSource",
- "(Ljava/io/FileDescriptor;)V");
- env->CallVoidMethod(m_metadataRetriever.object(), methodId, fd.object());
- bool ok = !env.checkAndClearExceptions();
- fileInputStream.callMethod<void>("close");
- if (!ok)
- return false;
- } else if (url.scheme() == QLatin1String("assets")) {
- QJniObject string = QJniObject::fromString(url.path().mid(1)); // remove first '/'
- QJniObject activity(QNativeInterface::QAndroidApplication::context());
- QJniObject assetManager = activity.callObjectMethod("getAssets",
- "()Landroid/content/res/AssetManager;");
- QJniObject assetFd = assetManager.callObjectMethod("openFd",
- "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;",
- string.object());
- if (!assetFd.isValid())
- return false;
-
- QJniObject fd = assetFd.callObjectMethod("getFileDescriptor",
- "()Ljava/io/FileDescriptor;");
- if (!fd.isValid()) {
- assetFd.callMethod<void>("close");
- return false;
- }
-
- auto methodId = env->GetMethodID(m_metadataRetriever.objectClass(), "setDataSource",
- "(Ljava/io/FileDescriptor;JJ)V");
- env->CallVoidMethod(m_metadataRetriever.object(), methodId,
- fd.object(),
- assetFd.callMethod<jlong>("getStartOffset"),
- assetFd.callMethod<jlong>("getLength"));
- bool ok = !env.checkAndClearExceptions();
- assetFd.callMethod<void>("close");
-
- if (!ok)
- return false;
- } else if (url.scheme() != QLatin1String("content")) {
- // On API levels >= 14, only setDataSource(String, Map<String, String>) accepts remote media
- QJniObject string = QJniObject::fromString(url.toString(QUrl::FullyEncoded));
- QJniObject hash("java/util/HashMap");
-
- auto methodId = env->GetMethodID(m_metadataRetriever.objectClass(), "setDataSource",
- "(Ljava/lang/String;Ljava/util/Map;)V");
- env->CallVoidMethod(m_metadataRetriever.object(), methodId,
- string.object(), hash.object());
- if (env.checkAndClearExceptions())
- return false;
- } else {
- // While on API levels < 14, only setDataSource(Context, Uri) is available and works for
- // remote media...
- QJniObject string = QJniObject::fromString(url.toString(QUrl::FullyEncoded));
- QJniObject uri = m_metadataRetriever.callStaticObjectMethod(
- "android/net/Uri",
- "parse",
- "(Ljava/lang/String;)Landroid/net/Uri;",
- string.object());
- if (!uri.isValid())
- return false;
-
- auto methodId = env->GetMethodID(m_metadataRetriever.objectClass(), "setDataSource",
- "(Landroid/content/Context;Landroid/net/Uri;)V");
- env->CallVoidMethod(m_metadataRetriever.object(), methodId,
- QNativeInterface::QAndroidApplication::context(), uri.object());
- if (env.checkAndClearExceptions())
- return false;
- }
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever_p.h b/src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever_p.h
deleted file mode 100644
index 69727bbd3..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmediametadataretriever_p.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef ANDROIDMEDIAMETADATARETRIEVER_H
-#define ANDROIDMEDIAMETADATARETRIEVER_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/private/qglobal_p.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qjniobject.h>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidMediaMetadataRetriever
-{
-public:
- enum MetadataKey {
- Album = 1,
- AlbumArtist = 13,
- Artist = 2,
- Author = 3,
- Bitrate = 20,
- CDTrackNumber = 0,
- Compilation = 15,
- Composer = 4,
- Date = 5,
- DiscNumber = 14,
- Duration = 9,
- Genre = 6,
- HasAudio = 16,
- HasVideo = 17,
- Location = 23,
- MimeType = 12,
- NumTracks = 10,
- Title = 7,
- VideoHeight = 19,
- VideoWidth = 18,
- VideoRotation = 24,
- Writer = 11,
- Year = 8
- };
-
- AndroidMediaMetadataRetriever();
- ~AndroidMediaMetadataRetriever();
-
- QString extractMetadata(MetadataKey key);
- bool setDataSource(const QUrl &url);
-
-private:
- void release();
- QJniObject m_metadataRetriever;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDMEDIAMETADATARETRIEVER_H
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmediaplayer.cpp b/src/multimedia/platform/android/wrappers/jni/androidmediaplayer.cpp
deleted file mode 100644
index f28622d6c..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmediaplayer.cpp
+++ /dev/null
@@ -1,581 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "androidmediaplayer_p.h"
-#include "androidsurfacetexture_p.h"
-
-#include <QList>
-#include <QReadWriteLock>
-#include <QString>
-#include <QtCore/qcoreapplication.h>
-
-static const char QtAndroidMediaPlayerClassName[] = "org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer";
-typedef QList<AndroidMediaPlayer *> MediaPlayerList;
-Q_GLOBAL_STATIC(MediaPlayerList, mediaPlayers)
-Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcAudio, "qt.multimedia.audio")
-
-AndroidMediaPlayer::AndroidMediaPlayer()
- : QObject()
-{
- QWriteLocker locker(rwLock);
- auto context = QNativeInterface::QAndroidApplication::context();
- const jlong id = reinterpret_cast<jlong>(this);
- mMediaPlayer = QJniObject(QtAndroidMediaPlayerClassName,
- "(Landroid/content/Context;J)V",
- context,
- id);
- mediaPlayers->append(this);
-}
-
-AndroidMediaPlayer::~AndroidMediaPlayer()
-{
- QWriteLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(this);
- Q_ASSERT(i != -1);
- mediaPlayers->remove(i);
-}
-
-void AndroidMediaPlayer::release()
-{
- mMediaPlayer.callMethod<void>("release");
-}
-
-void AndroidMediaPlayer::reset()
-{
- mMediaPlayer.callMethod<void>("reset");
-}
-
-int AndroidMediaPlayer::getCurrentPosition()
-{
- return mMediaPlayer.callMethod<jint>("getCurrentPosition");
-}
-
-int AndroidMediaPlayer::getDuration()
-{
- return mMediaPlayer.callMethod<jint>("getDuration");
-}
-
-bool AndroidMediaPlayer::isPlaying()
-{
- return mMediaPlayer.callMethod<jboolean>("isPlaying");
-}
-
-int AndroidMediaPlayer::volume()
-{
- return mMediaPlayer.callMethod<jint>("getVolume");
-}
-
-bool AndroidMediaPlayer::isMuted()
-{
- return mMediaPlayer.callMethod<jboolean>("isMuted");
-}
-
-qreal AndroidMediaPlayer::playbackRate()
-{
- qreal rate(1.0);
-
- if (QNativeInterface::QAndroidApplication::sdkVersion() < 23)
- return rate;
-
- QJniObject player = mMediaPlayer.callObjectMethod("getMediaPlayerHandle",
- "()Landroid/media/MediaPlayer;");
- if (player.isValid()) {
- QJniObject playbackParams = player.callObjectMethod("getPlaybackParams",
- "()Landroid/media/PlaybackParams;");
- if (playbackParams.isValid()) {
- QJniEnvironment env;
- auto methodId = env->GetMethodID(playbackParams.objectClass(), "getSpeed", "()F");
- const qreal speed = env->CallFloatMethod(playbackParams.object(), methodId);
- if (!env.checkAndClearExceptions())
- rate = speed;
- }
- }
-
- return rate;
-}
-
-jobject AndroidMediaPlayer::display()
-{
- return mMediaPlayer.callObjectMethod("display", "()Landroid/view/SurfaceHolder;").object();
-}
-
-AndroidMediaPlayer::TrackInfo convertTrackInfo(int streamNumber, QJniObject androidTrackInfo)
-{
- const QLatin1String unknownMimeType("application/octet-stream");
- const QLatin1String undefinedLanguage("und");
-
- if (!androidTrackInfo.isValid())
- return { streamNumber, AndroidMediaPlayer::TrackType::Unknown, undefinedLanguage,
- unknownMimeType };
-
- QJniEnvironment env;
- auto methodId = env->GetMethodID(androidTrackInfo.objectClass(), "getType", "()I");
- const jint type = env->CallIntMethod(androidTrackInfo.object(), methodId);
- if (env.checkAndClearExceptions())
- return { streamNumber, AndroidMediaPlayer::TrackType::Unknown, undefinedLanguage,
- unknownMimeType };
-
- if (type < 0 || type > 5) {
- return { streamNumber, AndroidMediaPlayer::TrackType::Unknown, undefinedLanguage,
- unknownMimeType };
- }
-
- AndroidMediaPlayer::TrackType trackType = static_cast<AndroidMediaPlayer::TrackType>(type);
-
- auto languageObject = androidTrackInfo.callObjectMethod("getLanguage", "()Ljava/lang/String;");
- QString language = languageObject.isValid() ? languageObject.toString() : undefinedLanguage;
-
- auto mimeTypeObject = androidTrackInfo.callObjectMethod("getMime", "()Ljava/lang/String;");
- QString mimeType = mimeTypeObject.isValid() ? mimeTypeObject.toString() : unknownMimeType;
-
- return { streamNumber, trackType, language, mimeType };
-}
-
-QList<AndroidMediaPlayer::TrackInfo> AndroidMediaPlayer::tracksInfo()
-{
- auto androidTracksInfoObject = mMediaPlayer.callObjectMethod(
- "getAllTrackInfo",
- "()[Lorg/qtproject/qt/android/multimedia/QtAndroidMediaPlayer$TrackInfo;");
-
- if (!androidTracksInfoObject.isValid())
- return QList<AndroidMediaPlayer::TrackInfo>();
-
- auto androidTracksInfo = androidTracksInfoObject.object<jobjectArray>();
- if (!androidTracksInfo)
- return QList<AndroidMediaPlayer::TrackInfo>();
-
- QJniEnvironment environment;
- auto numberofTracks = environment->GetArrayLength(androidTracksInfo);
-
- QList<AndroidMediaPlayer::TrackInfo> tracksInformation;
-
- for (int index = 0; index < numberofTracks; index++) {
- auto androidTrackInformation = environment->GetObjectArrayElement(androidTracksInfo, index);
-
- if (environment.checkAndClearExceptions()) {
- continue;
- }
-
- auto trackInfo = convertTrackInfo(index, androidTrackInformation);
- tracksInformation.insert(index, trackInfo);
-
- environment->DeleteLocalRef(androidTrackInformation);
- }
-
- return tracksInformation;
-}
-
-int AndroidMediaPlayer::activeTrack(TrackType androidTrackType)
-{
- int type = static_cast<int>(androidTrackType);
- return mMediaPlayer.callMethod<jint>("getSelectedTrack", "(I)I", type);
-}
-
-void AndroidMediaPlayer::deselectTrack(int trackNumber)
-{
- mMediaPlayer.callMethod<void>("deselectTrack", "(I)V", trackNumber);
-}
-
-void AndroidMediaPlayer::selectTrack(int trackNumber)
-{
- mMediaPlayer.callMethod<void>("selectTrack", "(I)V", trackNumber);
-}
-
-void AndroidMediaPlayer::play()
-{
- mMediaPlayer.callMethod<void>("start");
-}
-
-void AndroidMediaPlayer::pause()
-{
- mMediaPlayer.callMethod<void>("pause");
-}
-
-void AndroidMediaPlayer::stop()
-{
- mMediaPlayer.callMethod<void>("stop");
-}
-
-void AndroidMediaPlayer::seekTo(qint32 msec)
-{
- mMediaPlayer.callMethod<void>("seekTo", "(I)V", jint(msec));
-}
-
-void AndroidMediaPlayer::setMuted(bool mute)
-{
- if (mAudioBlocked)
- return;
-
- mMediaPlayer.callMethod<void>("mute", "(Z)V", jboolean(mute));
-}
-
-void AndroidMediaPlayer::setDataSource(const QNetworkRequest &request)
-{
- QJniObject string = QJniObject::fromString(request.url().toString(QUrl::FullyEncoded));
-
- mMediaPlayer.callMethod<void>("initHeaders", "()V");
- for (auto &header : request.rawHeaderList()) {
- auto value = request.rawHeader(header);
- mMediaPlayer.callMethod<void>("setHeader", "(Ljava/lang/String;Ljava/lang/String;)V",
- QJniObject::fromString(QLatin1String(header)).object(),
- QJniObject::fromString(QLatin1String(value)).object());
- }
-
- mMediaPlayer.callMethod<void>("setDataSource", "(Ljava/lang/String;)V", string.object());
-}
-
-void AndroidMediaPlayer::prepareAsync()
-{
- mMediaPlayer.callMethod<void>("prepareAsync");
-}
-
-void AndroidMediaPlayer::setVolume(int volume)
-{
- if (mAudioBlocked)
- return;
-
- mMediaPlayer.callMethod<void>("setVolume", "(I)V", jint(volume));
-}
-
-void AndroidMediaPlayer::blockAudio()
-{
- mAudioBlocked = true;
-}
-
-void AndroidMediaPlayer::unblockAudio()
-{
- mAudioBlocked = false;
-}
-
-bool AndroidMediaPlayer::setPlaybackRate(qreal rate)
-{
- if (QNativeInterface::QAndroidApplication::sdkVersion() < 23) {
- qWarning() << "Setting the playback rate on a media player requires"
- << "Android 6.0 (API level 23) or later";
- return false;
- }
-
- QJniObject player = mMediaPlayer.callObjectMethod("getMediaPlayerHandle",
- "()Landroid/media/MediaPlayer;");
- if (player.isValid()) {
- QJniObject playbackParams = player.callObjectMethod("getPlaybackParams",
- "()Landroid/media/PlaybackParams;");
- if (playbackParams.isValid()) {
- playbackParams.callObjectMethod("setSpeed", "(F)Landroid/media/PlaybackParams;",
- jfloat(rate));
- // pitch can only be > 0
- if (!qFuzzyIsNull(rate))
- playbackParams.callObjectMethod("setPitch", "(F)Landroid/media/PlaybackParams;",
- jfloat(qAbs(rate)));
-
- QJniEnvironment env;
- auto methodId = env->GetMethodID(player.objectClass(), "setPlaybackParams",
- "(Landroid/media/PlaybackParams;)V");
- env->CallVoidMethod(player.object(), methodId, playbackParams.object());
-
- if (env.checkAndClearExceptions()) {
- qWarning() << "Invalid playback rate" << rate;
- return false;
- } else {
- return true;
- }
- }
- }
-
- return false;
-}
-
-void AndroidMediaPlayer::setDisplay(AndroidSurfaceTexture *surfaceTexture)
-{
- mMediaPlayer.callMethod<void>("setDisplay",
- "(Landroid/view/SurfaceHolder;)V",
- surfaceTexture ? surfaceTexture->surfaceHolder() : 0);
-}
-
-bool AndroidMediaPlayer::setAudioOutput(const QByteArray &deviceId)
-{
- const bool ret = QJniObject::callStaticMethod<jboolean>(
- "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
- "setAudioOutput",
- "(I)Z",
- deviceId.toInt());
-
- if (!ret)
- qCWarning(lcAudio) << "Output device not set";
-
- return ret;
-}
-
-#if 0
-void AndroidMediaPlayer::setAudioRole(QAudio::Role role)
-{
- QString r;
- switch (role) {
- case QAudio::MusicRole:
- r = QLatin1String("CONTENT_TYPE_MUSIC");
- break;
- case QAudio::VideoRole:
- r = QLatin1String("CONTENT_TYPE_MOVIE");
- break;
- case QAudio::VoiceCommunicationRole:
- r = QLatin1String("USAGE_VOICE_COMMUNICATION");
- break;
- case QAudio::AlarmRole:
- r = QLatin1String("USAGE_ALARM");
- break;
- case QAudio::NotificationRole:
- r = QLatin1String("USAGE_NOTIFICATION");
- break;
- case QAudio::RingtoneRole:
- r = QLatin1String("USAGE_NOTIFICATION_RINGTONE");
- break;
- case QAudio::AccessibilityRole:
- r = QLatin1String("USAGE_ASSISTANCE_ACCESSIBILITY");
- break;
- case QAudio::SonificationRole:
- r = QLatin1String("CONTENT_TYPE_SONIFICATION");
- break;
- case QAudio::GameRole:
- r = QLatin1String("USAGE_GAME");
- break;
- default:
- return;
- }
-
- int type = 0; // CONTENT_TYPE_UNKNOWN
- int usage = 0; // USAGE_UNKNOWN
-
- if (r == QLatin1String("CONTENT_TYPE_MOVIE"))
- type = 3;
- else if (r == QLatin1String("CONTENT_TYPE_MUSIC"))
- type = 2;
- else if (r == QLatin1String("CONTENT_TYPE_SONIFICATION"))
- type = 4;
- else if (r == QLatin1String("CONTENT_TYPE_SPEECH"))
- type = 1;
- else if (r == QLatin1String("USAGE_ALARM"))
- usage = 4;
- else if (r == QLatin1String("USAGE_ASSISTANCE_ACCESSIBILITY"))
- usage = 11;
- else if (r == QLatin1String("USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"))
- usage = 12;
- else if (r == QLatin1String("USAGE_ASSISTANCE_SONIFICATION"))
- usage = 13;
- else if (r == QLatin1String("USAGE_ASSISTANT"))
- usage = 16;
- else if (r == QLatin1String("USAGE_GAME"))
- usage = 14;
- else if (r == QLatin1String("USAGE_MEDIA"))
- usage = 1;
- else if (r == QLatin1String("USAGE_NOTIFICATION"))
- usage = 5;
- else if (r == QLatin1String("USAGE_NOTIFICATION_COMMUNICATION_DELAYED"))
- usage = 9;
- else if (r == QLatin1String("USAGE_NOTIFICATION_COMMUNICATION_INSTANT"))
- usage = 8;
- else if (r == QLatin1String("USAGE_NOTIFICATION_COMMUNICATION_REQUEST"))
- usage = 7;
- else if (r == QLatin1String("USAGE_NOTIFICATION_EVENT"))
- usage = 10;
- else if (r == QLatin1String("USAGE_NOTIFICATION_RINGTONE"))
- usage = 6;
- else if (r == QLatin1String("USAGE_VOICE_COMMUNICATION"))
- usage = 2;
- else if (r == QLatin1String("USAGE_VOICE_COMMUNICATION_SIGNALLING"))
- usage = 3;
-
- mMediaPlayer.callMethod<void>("setAudioAttributes", "(II)V", jint(type), jint(usage));
-}
-#endif
-
-static void onErrorNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- QReadLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(reinterpret_cast<AndroidMediaPlayer *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- Q_EMIT (*mediaPlayers)[i]->error(what, extra);
-}
-
-static void onBufferingUpdateNative(JNIEnv *env, jobject thiz, jint percent, jlong id)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- QReadLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(reinterpret_cast<AndroidMediaPlayer *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- Q_EMIT (*mediaPlayers)[i]->bufferingChanged(percent);
-}
-
-static void onProgressUpdateNative(JNIEnv *env, jobject thiz, jint progress, jlong id)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- QReadLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(reinterpret_cast<AndroidMediaPlayer *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- Q_EMIT (*mediaPlayers)[i]->progressChanged(progress);
-}
-
-static void onDurationChangedNative(JNIEnv *env, jobject thiz, jint duration, jlong id)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- QReadLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(reinterpret_cast<AndroidMediaPlayer *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- Q_EMIT (*mediaPlayers)[i]->durationChanged(duration);
-}
-
-static void onInfoNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- QReadLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(reinterpret_cast<AndroidMediaPlayer *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- Q_EMIT (*mediaPlayers)[i]->info(what, extra);
-}
-
-static void onStateChangedNative(JNIEnv *env, jobject thiz, jint state, jlong id)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- QReadLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(reinterpret_cast<AndroidMediaPlayer *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- Q_EMIT (*mediaPlayers)[i]->stateChanged(state);
-}
-
-static void onVideoSizeChangedNative(JNIEnv *env,
- jobject thiz,
- jint width,
- jint height,
- jlong id)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- QReadLocker locker(rwLock);
- const int i = mediaPlayers->indexOf(reinterpret_cast<AndroidMediaPlayer *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- Q_EMIT (*mediaPlayers)[i]->videoSizeChanged(width, height);
-}
-
-static AndroidMediaPlayer *getMediaPlayer(jlong ptr)
-{
- auto mediaplayer = reinterpret_cast<AndroidMediaPlayer *>(ptr);
- if (!mediaplayer || !mediaPlayers->contains(mediaplayer))
- return nullptr;
-
- return mediaplayer;
-}
-
-static void onTrackInfoChangedNative(JNIEnv *env, jobject thiz, jlong ptr)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
-
- QReadLocker locker(rwLock);
- auto mediaplayer = getMediaPlayer(ptr);
- if (!mediaplayer)
- return;
-
- emit mediaplayer->tracksInfoChanged();
-}
-
-static void onTimedTextChangedNative(JNIEnv *env, jobject thiz, jstring timedText, jint time,
- jlong ptr)
-{
- Q_UNUSED(env);
- Q_UNUSED(thiz);
- Q_UNUSED(time);
-
- QReadLocker locker(rwLock);
-
- auto mediaplayer = getMediaPlayer(ptr);
- if (!mediaplayer)
- return;
-
- QString subtitleText;
- if (timedText != nullptr)
- subtitleText = QString::fromUtf8(env->GetStringUTFChars(timedText, 0));
-
- emit mediaplayer->timedTextChanged(subtitleText);
-}
-
-bool AndroidMediaPlayer::registerNativeMethods()
-{
- static const JNINativeMethod methods[] = {
- { "onErrorNative", "(IIJ)V", reinterpret_cast<void *>(onErrorNative) },
- { "onBufferingUpdateNative", "(IJ)V", reinterpret_cast<void *>(onBufferingUpdateNative) },
- { "onProgressUpdateNative", "(IJ)V", reinterpret_cast<void *>(onProgressUpdateNative) },
- { "onDurationChangedNative", "(IJ)V", reinterpret_cast<void *>(onDurationChangedNative) },
- { "onInfoNative", "(IIJ)V", reinterpret_cast<void *>(onInfoNative) },
- { "onVideoSizeChangedNative", "(IIJ)V",
- reinterpret_cast<void *>(onVideoSizeChangedNative) },
- { "onStateChangedNative", "(IJ)V", reinterpret_cast<void *>(onStateChangedNative) },
- { "onTrackInfoChangedNative", "(J)V", reinterpret_cast<void *>(onTrackInfoChangedNative) },
- { "onTimedTextChangedNative", "(Ljava/lang/String;IJ)V",
- reinterpret_cast<void *>(onTimedTextChangedNative) }
- };
-
- const int size = std::size(methods);
- return QJniEnvironment().registerNativeMethods(QtAndroidMediaPlayerClassName, methods, size);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmediaplayer_p.h b/src/multimedia/platform/android/wrappers/jni/androidmediaplayer_p.h
deleted file mode 100644
index d5cf07f9c..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmediaplayer_p.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef ANDROIDMEDIAPLAYER_H
-#define ANDROIDMEDIAPLAYER_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>
-#include <QNetworkRequest>
-#include <QtCore/qjniobject.h>
-#include <QAudio>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidSurfaceTexture;
-
-class AndroidMediaPlayer : public QObject
-{
- Q_OBJECT
-public:
- AndroidMediaPlayer();
- ~AndroidMediaPlayer();
-
- enum MediaError
- {
- // What
- MEDIA_ERROR_UNKNOWN = 1,
- MEDIA_ERROR_SERVER_DIED = 100,
- MEDIA_ERROR_INVALID_STATE = -38, // Undocumented
- // Extra
- MEDIA_ERROR_IO = -1004,
- MEDIA_ERROR_MALFORMED = -1007,
- MEDIA_ERROR_UNSUPPORTED = -1010,
- MEDIA_ERROR_TIMED_OUT = -110,
- MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
- MEDIA_ERROR_BAD_THINGS_ARE_GOING_TO_HAPPEN = -2147483648 // Undocumented
- };
-
- enum MediaInfo
- {
- MEDIA_INFO_UNKNOWN = 1,
- MEDIA_INFO_VIDEO_TRACK_LAGGING = 700,
- MEDIA_INFO_VIDEO_RENDERING_START = 3,
- MEDIA_INFO_BUFFERING_START = 701,
- MEDIA_INFO_BUFFERING_END = 702,
- MEDIA_INFO_BAD_INTERLEAVING = 800,
- MEDIA_INFO_NOT_SEEKABLE = 801,
- MEDIA_INFO_METADATA_UPDATE = 802
- };
-
- enum MediaPlayerState {
- Uninitialized = 0x1, /* End */
- Idle = 0x2,
- Preparing = 0x4,
- Prepared = 0x8,
- Initialized = 0x10,
- Started = 0x20,
- Stopped = 0x40,
- Paused = 0x80,
- PlaybackCompleted = 0x100,
- Error = 0x200
- };
-
- enum TrackType { Unknown = 0, Video, Audio, TimedText, Subtitle, Metadata };
-
- struct TrackInfo
- {
- int trackNumber;
- TrackType trackType;
- QString language;
- QString mimeType;
- };
-
- void release();
- void reset();
-
- int getCurrentPosition();
- int getDuration();
- bool isPlaying();
- int volume();
- bool isMuted();
- qreal playbackRate();
- jobject display();
-
- void play();
- void pause();
- void stop();
- void seekTo(qint32 msec);
- void setMuted(bool mute);
- void setDataSource(const QNetworkRequest &request);
- void prepareAsync();
- void setVolume(int volume);
- bool setPlaybackRate(qreal rate);
- void setDisplay(AndroidSurfaceTexture *surfaceTexture);
- static bool setAudioOutput(const QByteArray &deviceId);
- QList<TrackInfo> tracksInfo();
- int activeTrack(TrackType trackType);
- void deselectTrack(int trackNumber);
- void selectTrack(int trackNumber);
-
- static bool registerNativeMethods();
-
- void blockAudio();
- void unblockAudio();
-Q_SIGNALS:
- void error(qint32 what, qint32 extra);
- void bufferingChanged(qint32 percent);
- void durationChanged(qint64 duration);
- void progressChanged(qint64 progress);
- void stateChanged(qint32 state);
- void info(qint32 what, qint32 extra);
- void videoSizeChanged(qint32 width, qint32 height);
- void timedTextChanged(QString text);
- void tracksInfoChanged();
-
-private:
- QJniObject mMediaPlayer;
- bool mAudioBlocked = false;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDMEDIAPLAYER_H
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmediarecorder.cpp b/src/multimedia/platform/android/wrappers/jni/androidmediarecorder.cpp
deleted file mode 100644
index c5cdadbfd..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmediarecorder.cpp
+++ /dev/null
@@ -1,344 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "androidmediarecorder_p.h"
-
-#include "androidcamera_p.h"
-#include "androidsurfacetexture_p.h"
-#include "androidsurfaceview_p.h"
-#include "qandroidglobal_p.h"
-#include "qandroidmultimediautils_p.h"
-#include <qmap.h>
-#include <QtCore/qlogging.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcMediaRecorder, "qt.multimedia.mediarecorder.android")
-
-typedef QMap<QString, QJniObject> CamcorderProfiles;
-Q_GLOBAL_STATIC(CamcorderProfiles, g_camcorderProfiles)
-
-static QString profileKey()
-{
- return QStringLiteral("%1-%2");
-}
-
-bool AndroidCamcorderProfile::hasProfile(jint cameraId, Quality quality)
-{
- if (g_camcorderProfiles->contains(profileKey().arg(cameraId).arg(quality)))
- return true;
-
- return QJniObject::callStaticMethod<jboolean>("android/media/CamcorderProfile",
- "hasProfile",
- "(II)Z",
- cameraId,
- quality);
-}
-
-AndroidCamcorderProfile AndroidCamcorderProfile::get(jint cameraId, Quality quality)
-{
- const QString key = profileKey().arg(cameraId).arg(quality);
- QMap<QString, QJniObject>::const_iterator it = g_camcorderProfiles->constFind(key);
-
- if (it != g_camcorderProfiles->constEnd())
- return AndroidCamcorderProfile(*it);
-
- QJniObject camProfile = QJniObject::callStaticObjectMethod("android/media/CamcorderProfile",
- "get",
- "(II)Landroid/media/CamcorderProfile;",
- cameraId,
- quality);
-
- return AndroidCamcorderProfile((*g_camcorderProfiles)[key] = camProfile);
-}
-
-int AndroidCamcorderProfile::getValue(AndroidCamcorderProfile::Field field) const
-{
- switch (field) {
- case audioBitRate:
- return m_camcorderProfile.getField<jint>("audioBitRate");
- case audioChannels:
- return m_camcorderProfile.getField<jint>("audioChannels");
- case audioCodec:
- return m_camcorderProfile.getField<jint>("audioCodec");
- case audioSampleRate:
- return m_camcorderProfile.getField<jint>("audioSampleRate");
- case duration:
- return m_camcorderProfile.getField<jint>("duration");
- case fileFormat:
- return m_camcorderProfile.getField<jint>("fileFormat");
- case quality:
- return m_camcorderProfile.getField<jint>("quality");
- case videoBitRate:
- return m_camcorderProfile.getField<jint>("videoBitRate");
- case videoCodec:
- return m_camcorderProfile.getField<jint>("videoCodec");
- case videoFrameHeight:
- return m_camcorderProfile.getField<jint>("videoFrameHeight");
- case videoFrameRate:
- return m_camcorderProfile.getField<jint>("videoFrameRate");
- case videoFrameWidth:
- return m_camcorderProfile.getField<jint>("videoFrameWidth");
- }
-
- return 0;
-}
-
-AndroidCamcorderProfile::AndroidCamcorderProfile(const QJniObject &camcorderProfile)
-{
- m_camcorderProfile = camcorderProfile;
-}
-
-static const char QtMediaRecorderListenerClassName[] =
- "org/qtproject/qt/android/multimedia/QtMediaRecorderListener";
-typedef QMap<jlong, AndroidMediaRecorder*> MediaRecorderMap;
-Q_GLOBAL_STATIC(MediaRecorderMap, mediaRecorders)
-
-static void notifyError(JNIEnv* , jobject, jlong id, jint what, jint extra)
-{
- AndroidMediaRecorder *obj = mediaRecorders->value(id, 0);
- if (obj)
- emit obj->error(what, extra);
-}
-
-static void notifyInfo(JNIEnv* , jobject, jlong id, jint what, jint extra)
-{
- AndroidMediaRecorder *obj = mediaRecorders->value(id, 0);
- if (obj)
- emit obj->info(what, extra);
-}
-
-AndroidMediaRecorder::AndroidMediaRecorder()
- : QObject()
- , m_id(reinterpret_cast<jlong>(this))
-{
- m_mediaRecorder = QJniObject("android/media/MediaRecorder");
- if (m_mediaRecorder.isValid()) {
- QJniObject listener(QtMediaRecorderListenerClassName, "(J)V", m_id);
- m_mediaRecorder.callMethod<void>("setOnErrorListener",
- "(Landroid/media/MediaRecorder$OnErrorListener;)V",
- listener.object());
- m_mediaRecorder.callMethod<void>("setOnInfoListener",
- "(Landroid/media/MediaRecorder$OnInfoListener;)V",
- listener.object());
- mediaRecorders->insert(m_id, this);
- }
-}
-
-AndroidMediaRecorder::~AndroidMediaRecorder()
-{
- mediaRecorders->remove(m_id);
-}
-
-void AndroidMediaRecorder::release()
-{
- m_mediaRecorder.callMethod<void>("release");
-}
-
-bool AndroidMediaRecorder::prepare()
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "prepare", "()V");
- env->CallVoidMethod(m_mediaRecorder.object(), methodId);
-
- if (env.checkAndClearExceptions())
- return false;
- return true;
-}
-
-void AndroidMediaRecorder::reset()
-{
- m_mediaRecorder.callMethod<void>("reset");
- m_isAudioSourceSet = false; // Now setAudioSource can be used again.
-}
-
-bool AndroidMediaRecorder::start()
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "start", "()V");
- env->CallVoidMethod(m_mediaRecorder.object(), methodId);
-
- if (env.checkAndClearExceptions())
- return false;
- return true;
-}
-
-void AndroidMediaRecorder::stop()
-{
- m_mediaRecorder.callMethod<void>("stop");
-}
-
-void AndroidMediaRecorder::setAudioChannels(int numChannels)
-{
- m_mediaRecorder.callMethod<void>("setAudioChannels", "(I)V", numChannels);
-}
-
-void AndroidMediaRecorder::setAudioEncoder(AudioEncoder encoder)
-{
- QJniEnvironment env;
- m_mediaRecorder.callMethod<void>("setAudioEncoder", "(I)V", int(encoder));
-}
-
-void AndroidMediaRecorder::setAudioEncodingBitRate(int bitRate)
-{
- m_mediaRecorder.callMethod<void>("setAudioEncodingBitRate", "(I)V", bitRate);
-}
-
-void AndroidMediaRecorder::setAudioSamplingRate(int samplingRate)
-{
- m_mediaRecorder.callMethod<void>("setAudioSamplingRate", "(I)V", samplingRate);
-}
-
-void AndroidMediaRecorder::setAudioSource(AudioSource source)
-{
- if (!m_isAudioSourceSet) {
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "setAudioSource", "(I)V");
- env->CallVoidMethod(m_mediaRecorder.object(), methodId, source);
- if (!env.checkAndClearExceptions())
- m_isAudioSourceSet = true;
- } else {
- qCWarning(lcMediaRecorder) << "Audio source already set. Not setting a new source.";
- }
-}
-
-bool AndroidMediaRecorder::isAudioSourceSet() const
-{
- return m_isAudioSourceSet;
-}
-
-bool AndroidMediaRecorder::setAudioInput(const QByteArray &id)
-{
- const bool ret = QJniObject::callStaticMethod<jboolean>(
- "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
- "setAudioInput",
- "(Landroid/media/MediaRecorder;I)Z",
- m_mediaRecorder.object(),
- id.toInt());
- if (!ret)
- qCWarning(lcMediaRecorder) << "No default input device was set.";
-
- return ret;
-}
-
-void AndroidMediaRecorder::setCamera(AndroidCamera *camera)
-{
- QJniObject cam = camera->getCameraObject();
- m_mediaRecorder.callMethod<void>("setCamera", "(Landroid/hardware/Camera;)V", cam.object());
-}
-
-void AndroidMediaRecorder::setVideoEncoder(VideoEncoder encoder)
-{
- m_mediaRecorder.callMethod<void>("setVideoEncoder", "(I)V", int(encoder));
-}
-
-void AndroidMediaRecorder::setVideoEncodingBitRate(int bitRate)
-{
- m_mediaRecorder.callMethod<void>("setVideoEncodingBitRate", "(I)V", bitRate);
-}
-
-void AndroidMediaRecorder::setVideoFrameRate(int rate)
-{
- m_mediaRecorder.callMethod<void>("setVideoFrameRate", "(I)V", rate);
-}
-
-void AndroidMediaRecorder::setVideoSize(const QSize &size)
-{
- m_mediaRecorder.callMethod<void>("setVideoSize", "(II)V", size.width(), size.height());
-}
-
-void AndroidMediaRecorder::setVideoSource(VideoSource source)
-{
- m_mediaRecorder.callMethod<void>("setVideoSource", "(I)V", int(source));
-}
-
-void AndroidMediaRecorder::setOrientationHint(int degrees)
-{
- m_mediaRecorder.callMethod<void>("setOrientationHint", "(I)V", degrees);
-}
-
-void AndroidMediaRecorder::setOutputFormat(OutputFormat format)
-{
- QJniEnvironment env;
- auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "setOutputFormat", "(I)V");
- env->CallVoidMethod(m_mediaRecorder.object(), methodId, format);
- // setAudioSource cannot be set after outputFormat is set.
- if (!env.checkAndClearExceptions())
- m_isAudioSourceSet = true;
-}
-
-void AndroidMediaRecorder::setOutputFile(const QString &path)
-{
- m_mediaRecorder.callMethod<void>("setOutputFile",
- "(Ljava/lang/String;)V",
- QJniObject::fromString(path).object());
-}
-
-void AndroidMediaRecorder::setSurfaceTexture(AndroidSurfaceTexture *texture)
-{
- m_mediaRecorder.callMethod<void>("setPreviewDisplay",
- "(Landroid/view/Surface;)V",
- texture->surface());
-}
-
-void AndroidMediaRecorder::setSurfaceHolder(AndroidSurfaceHolder *holder)
-{
- QJniObject surfaceHolder(holder->surfaceHolder());
- QJniObject surface = surfaceHolder.callObjectMethod("getSurface",
- "()Landroid/view/Surface;");
- if (!surface.isValid())
- return;
-
- m_mediaRecorder.callMethod<void>("setPreviewDisplay",
- "(Landroid/view/Surface;)V",
- surface.object());
-}
-
-bool AndroidMediaRecorder::registerNativeMethods()
-{
- static const JNINativeMethod methods[] = {
- {"notifyError", "(JII)V", (void *)notifyError},
- {"notifyInfo", "(JII)V", (void *)notifyInfo}
- };
-
- const int size = std::size(methods);
- return QJniEnvironment().registerNativeMethods(QtMediaRecorderListenerClassName, methods, size);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmediarecorder_p.h b/src/multimedia/platform/android/wrappers/jni/androidmediarecorder_p.h
deleted file mode 100644
index b0f65dd1d..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmediarecorder_p.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef ANDROIDMEDIARECORDER_H
-#define ANDROIDMEDIARECORDER_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 <QtCore/qjniobject.h>
-#include <qsize.h>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidCamera;
-class AndroidSurfaceTexture;
-class AndroidSurfaceHolder;
-
-class AndroidCamcorderProfile
-{
-public:
- enum Quality { // Needs to match CamcorderProfile
- QUALITY_LOW,
- QUALITY_HIGH,
- QUALITY_QCIF,
- QUALITY_CIF,
- QUALITY_480P,
- QUALITY_720P,
- QUALITY_1080P,
- QUALITY_QVGA
- };
-
- enum Field {
- audioBitRate,
- audioChannels,
- audioCodec,
- audioSampleRate,
- duration,
- fileFormat,
- quality,
- videoBitRate,
- videoCodec,
- videoFrameHeight,
- videoFrameRate,
- videoFrameWidth
- };
-
- static bool hasProfile(jint cameraId, Quality quality);
- static AndroidCamcorderProfile get(jint cameraId, Quality quality);
- int getValue(Field field) const;
-
-private:
- AndroidCamcorderProfile(const QJniObject &camcorderProfile);
- QJniObject m_camcorderProfile;
-};
-
-class AndroidMediaRecorder : public QObject
-{
- Q_OBJECT
-public:
- enum AudioEncoder {
- DefaultAudioEncoder = 0,
- AMR_NB_Encoder = 1,
- AMR_WB_Encoder = 2,
- AAC = 3,
- OPUS = 7,
- VORBIS = 6
- };
-
- enum AudioSource {
- DefaultAudioSource = 0,
- Mic = 1,
- VoiceUplink = 2,
- VoiceDownlink = 3,
- VoiceCall = 4,
- Camcorder = 5,
- VoiceRecognition = 6
- };
-
- enum VideoEncoder {
- DefaultVideoEncoder = 0,
- H263 = 1,
- H264 = 2,
- MPEG_4_SP = 3,
- HEVC = 5
- };
-
- enum VideoSource {
- DefaultVideoSource = 0,
- Camera = 1
- };
-
- enum OutputFormat {
- DefaultOutputFormat = 0,
- THREE_GPP = 1,
- MPEG_4 = 2,
- AMR_NB_Format = 3,
- AMR_WB_Format = 4,
- AAC_ADTS = 6,
- OGG = 11,
- WEBM = 9
- };
-
- AndroidMediaRecorder();
- ~AndroidMediaRecorder();
-
- void release();
- bool prepare();
- void reset();
-
- bool start();
- void stop();
-
- void setAudioChannels(int numChannels);
- void setAudioEncoder(AudioEncoder encoder);
- void setAudioEncodingBitRate(int bitRate);
- void setAudioSamplingRate(int samplingRate);
- void setAudioSource(AudioSource source);
- bool isAudioSourceSet() const;
- bool setAudioInput(const QByteArray &id);
-
- void setCamera(AndroidCamera *camera);
- void setVideoEncoder(VideoEncoder encoder);
- void setVideoEncodingBitRate(int bitRate);
- void setVideoFrameRate(int rate);
- void setVideoSize(const QSize &size);
- void setVideoSource(VideoSource source);
-
- void setOrientationHint(int degrees);
-
- void setOutputFormat(OutputFormat format);
- void setOutputFile(const QString &path);
-
- void setSurfaceTexture(AndroidSurfaceTexture *texture);
- void setSurfaceHolder(AndroidSurfaceHolder *holder);
-
- static bool registerNativeMethods();
-
-Q_SIGNALS:
- void error(int what, int extra);
- void info(int what, int extra);
-
-private:
- jlong m_id;
- QJniObject m_mediaRecorder;
- bool m_isAudioSourceSet = false;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDMEDIARECORDER_H
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmultimediautils.cpp b/src/multimedia/platform/android/wrappers/jni/androidmultimediautils.cpp
deleted file mode 100644
index 1fe482f30..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmultimediautils.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "androidmultimediautils_p.h"
-
-#include <QtCore/qjniobject.h>
-
-QT_BEGIN_NAMESPACE
-
-
-void AndroidMultimediaUtils::enableOrientationListener(bool enable)
-{
- QJniObject::callStaticMethod<void>("org/qtproject/qt/android/multimedia/QtMultimediaUtils",
- "enableOrientationListener",
- "(Z)V",
- enable);
-}
-
-int AndroidMultimediaUtils::getDeviceOrientation()
-{
- return QJniObject::callStaticMethod<jint>("org/qtproject/qt/android/multimedia/QtMultimediaUtils",
- "getDeviceOrientation");
-}
-
-QString AndroidMultimediaUtils::getDefaultMediaDirectory(MediaType type)
-{
- QJniObject path = QJniObject::callStaticObjectMethod(
- "org/qtproject/qt/android/multimedia/QtMultimediaUtils",
- "getDefaultMediaDirectory",
- "(I)Ljava/lang/String;",
- jint(type));
- return path.toString();
-}
-
-void AndroidMultimediaUtils::registerMediaFile(const QString &file)
-{
- QJniObject::callStaticMethod<void>("org/qtproject/qt/android/multimedia/QtMultimediaUtils",
- "registerMediaFile",
- "(Ljava/lang/String;)V",
- QJniObject::fromString(file).object());
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/wrappers/jni/androidmultimediautils_p.h b/src/multimedia/platform/android/wrappers/jni/androidmultimediautils_p.h
deleted file mode 100644
index 8a1fd7328..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidmultimediautils_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef ANDROIDMULTIMEDIAUTILS_H
-#define ANDROIDMULTIMEDIAUTILS_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>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidMultimediaUtils
-{
-public:
- enum MediaType {
- Music = 0,
- Movies = 1,
- DCIM = 2,
- Sounds = 3
- };
-
- static void enableOrientationListener(bool enable);
- static int getDeviceOrientation();
- static QString getDefaultMediaDirectory(MediaType type);
- static void registerMediaFile(const QString &file);
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDMULTIMEDIAUTILS_H
diff --git a/src/multimedia/platform/android/wrappers/jni/androidsurfacetexture.cpp b/src/multimedia/platform/android/wrappers/jni/androidsurfacetexture.cpp
deleted file mode 100644
index d3a5b56ff..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidsurfacetexture.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "androidsurfacetexture_p.h"
-#include <QtCore/qmutex.h>
-#include <QtCore/qcoreapplication.h>
-
-QT_BEGIN_NAMESPACE
-
-static const char QtSurfaceTextureListenerClassName[] = "org/qtproject/qt/android/multimedia/QtSurfaceTextureListener";
-typedef QList<jlong> SurfaceTextures;
-Q_GLOBAL_STATIC(SurfaceTextures, g_surfaceTextures);
-Q_GLOBAL_STATIC(QMutex, g_textureMutex);
-
-// native method for QtSurfaceTexture.java
-static void notifyFrameAvailable(JNIEnv* , jobject, jlong id)
-{
- const QMutexLocker lock(g_textureMutex());
- const int idx = g_surfaceTextures->indexOf(id);
- if (idx == -1)
- return;
-
- AndroidSurfaceTexture *obj = reinterpret_cast<AndroidSurfaceTexture *>(g_surfaceTextures->at(idx));
- if (obj)
- Q_EMIT obj->frameAvailable();
-}
-
-AndroidSurfaceTexture::AndroidSurfaceTexture(quint32 texName)
- : QObject()
-{
- Q_STATIC_ASSERT(sizeof (jlong) >= sizeof (void *));
- m_surfaceTexture = QJniObject("android/graphics/SurfaceTexture", "(I)V", jint(texName));
-
- if (!m_surfaceTexture.isValid())
- return;
-
- const QMutexLocker lock(g_textureMutex());
- g_surfaceTextures->append(jlong(this));
- QJniObject listener(QtSurfaceTextureListenerClassName, "(J)V", jlong(this));
- setOnFrameAvailableListener(listener);
-}
-
-AndroidSurfaceTexture::~AndroidSurfaceTexture()
-{
- if (m_surface.isValid())
- m_surface.callMethod<void>("release");
-
- if (m_surfaceTexture.isValid()) {
- release();
- const QMutexLocker lock(g_textureMutex());
- const int idx = g_surfaceTextures->indexOf(jlong(this));
- if (idx != -1)
- g_surfaceTextures->remove(idx);
- }
-}
-
-QMatrix4x4 AndroidSurfaceTexture::getTransformMatrix()
-{
- QMatrix4x4 matrix;
- if (!m_surfaceTexture.isValid())
- return matrix;
-
- QJniEnvironment env;
- jfloatArray array = env->NewFloatArray(16);
- m_surfaceTexture.callMethod<void>("getTransformMatrix", "([F)V", array);
- env->GetFloatArrayRegion(array, 0, 16, matrix.data());
- env->DeleteLocalRef(array);
-
- return matrix;
-}
-
-void AndroidSurfaceTexture::release()
-{
- m_surfaceTexture.callMethod<void>("release");
-}
-
-void AndroidSurfaceTexture::updateTexImage()
-{
- if (!m_surfaceTexture.isValid())
- return;
-
- m_surfaceTexture.callMethod<void>("updateTexImage");
-}
-
-jobject AndroidSurfaceTexture::surfaceTexture()
-{
- return m_surfaceTexture.object();
-}
-
-jobject AndroidSurfaceTexture::surface()
-{
- if (!m_surface.isValid()) {
- m_surface = QJniObject("android/view/Surface",
- "(Landroid/graphics/SurfaceTexture;)V",
- m_surfaceTexture.object());
- }
-
- return m_surface.object();
-}
-
-jobject AndroidSurfaceTexture::surfaceHolder()
-{
- if (!m_surfaceHolder.isValid()) {
- m_surfaceHolder = QJniObject("org/qtproject/qt/android/multimedia/QtSurfaceTextureHolder",
- "(Landroid/view/Surface;)V",
- surface());
- }
-
- return m_surfaceHolder.object();
-}
-
-void AndroidSurfaceTexture::attachToGLContext(quint32 texName)
-{
- if (!m_surfaceTexture.isValid())
- return;
-
- m_surfaceTexture.callMethod<void>("attachToGLContext", "(I)V", texName);
-}
-
-void AndroidSurfaceTexture::detachFromGLContext()
-{
- if (!m_surfaceTexture.isValid())
- return;
-
- m_surfaceTexture.callMethod<void>("detachFromGLContext");
-}
-
-bool AndroidSurfaceTexture::registerNativeMethods()
-{
- static const JNINativeMethod methods[] = {
- {"notifyFrameAvailable", "(J)V", (void *)notifyFrameAvailable}
- };
- const int size = std::size(methods);
- if (QJniEnvironment().registerNativeMethods(QtSurfaceTextureListenerClassName, methods, size))
- return false;
-
- return true;
-}
-
-void AndroidSurfaceTexture::setOnFrameAvailableListener(const QJniObject &listener)
-{
- m_surfaceTexture.callMethod<void>("setOnFrameAvailableListener",
- "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V",
- listener.object());
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/wrappers/jni/androidsurfacetexture_p.h b/src/multimedia/platform/android/wrappers/jni/androidsurfacetexture_p.h
deleted file mode 100644
index d31df972b..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidsurfacetexture_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef ANDROIDSURFACETEXTURE_H
-#define ANDROIDSURFACETEXTURE_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 <QtCore/qjniobject.h>
-
-#include <QMatrix4x4>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidSurfaceTexture : public QObject
-{
- Q_OBJECT
-public:
- explicit AndroidSurfaceTexture(quint32 texName);
- ~AndroidSurfaceTexture();
-
- jobject surfaceTexture();
- jobject surface();
- jobject surfaceHolder();
- inline bool isValid() const { return m_surfaceTexture.isValid(); }
-
- QMatrix4x4 getTransformMatrix();
- void release(); // API level 14
- void updateTexImage();
-
- void attachToGLContext(quint32 texName); // API level 16
- void detachFromGLContext(); // API level 16
-
- static bool registerNativeMethods();
-
-Q_SIGNALS:
- void frameAvailable();
-
-private:
- void setOnFrameAvailableListener(const QJniObject &listener);
-
- QJniObject m_surfaceTexture;
- QJniObject m_surface;
- QJniObject m_surfaceHolder;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDSURFACETEXTURE_H
diff --git a/src/multimedia/platform/android/wrappers/jni/androidsurfaceview.cpp b/src/multimedia/platform/android/wrappers/jni/androidsurfaceview.cpp
deleted file mode 100644
index 33d15a91b..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidsurfaceview.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "androidsurfaceview_p.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmutex.h>
-#include <QtGui/qwindow.h>
-
-QT_BEGIN_NAMESPACE
-
-static const char QtSurfaceHolderCallbackClassName[] = "org/qtproject/qt/android/multimedia/QtSurfaceHolderCallback";
-typedef QList<AndroidSurfaceHolder *> SurfaceHolders;
-Q_GLOBAL_STATIC(SurfaceHolders, surfaceHolders)
-Q_GLOBAL_STATIC(QMutex, shLock)
-
-AndroidSurfaceHolder::AndroidSurfaceHolder(QJniObject object)
- : m_surfaceHolder(object)
- , m_surfaceCreated(false)
-{
- if (!m_surfaceHolder.isValid())
- return;
-
- {
- QMutexLocker locker(shLock());
- surfaceHolders->append(this);
- }
-
- QJniObject callback(QtSurfaceHolderCallbackClassName, "(J)V", reinterpret_cast<jlong>(this));
- m_surfaceHolder.callMethod<void>("addCallback",
- "(Landroid/view/SurfaceHolder$Callback;)V",
- callback.object());
-}
-
-AndroidSurfaceHolder::~AndroidSurfaceHolder()
-{
- QMutexLocker locker(shLock());
- const int i = surfaceHolders->indexOf(this);
- if (Q_UNLIKELY(i == -1))
- return;
-
- surfaceHolders->remove(i);
-}
-
-jobject AndroidSurfaceHolder::surfaceHolder() const
-{
- return m_surfaceHolder.object();
-}
-
-bool AndroidSurfaceHolder::isSurfaceCreated() const
-{
- QMutexLocker locker(shLock());
- return m_surfaceCreated;
-}
-
-void AndroidSurfaceHolder::handleSurfaceCreated(JNIEnv*, jobject, jlong id)
-{
- QMutexLocker locker(shLock());
- const int i = surfaceHolders->indexOf(reinterpret_cast<AndroidSurfaceHolder *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- (*surfaceHolders)[i]->m_surfaceCreated = true;
- Q_EMIT (*surfaceHolders)[i]->surfaceCreated();
-}
-
-void AndroidSurfaceHolder::handleSurfaceDestroyed(JNIEnv*, jobject, jlong id)
-{
- QMutexLocker locker(shLock());
- const int i = surfaceHolders->indexOf(reinterpret_cast<AndroidSurfaceHolder *>(id));
- if (Q_UNLIKELY(i == -1))
- return;
-
- (*surfaceHolders)[i]->m_surfaceCreated = false;
-}
-
-bool AndroidSurfaceHolder::registerNativeMethods()
-{
- static const JNINativeMethod methods[] = {
- {"notifySurfaceCreated", "(J)V", (void *)AndroidSurfaceHolder::handleSurfaceCreated},
- {"notifySurfaceDestroyed", "(J)V", (void *)AndroidSurfaceHolder::handleSurfaceDestroyed}
- };
-
- const int size = std::size(methods);
- return QJniEnvironment().registerNativeMethods(QtSurfaceHolderCallbackClassName, methods, size);
-}
-
-AndroidSurfaceView::AndroidSurfaceView()
- : m_window(0)
- , m_surfaceHolder(0)
- , m_pendingVisible(-1)
-{
- QNativeInterface::QAndroidApplication::runOnAndroidMainThread([this] {
- m_surfaceView = QJniObject("android/view/SurfaceView",
- "(Landroid/content/Context;)V",
- QNativeInterface::QAndroidApplication::context());
- }).waitForFinished();
-
- Q_ASSERT(m_surfaceView.isValid());
-
- QJniObject holder = m_surfaceView.callObjectMethod("getHolder",
- "()Landroid/view/SurfaceHolder;");
- if (!holder.isValid()) {
- m_surfaceView = QJniObject();
- } else {
- m_surfaceHolder = new AndroidSurfaceHolder(holder);
- connect(m_surfaceHolder, &AndroidSurfaceHolder::surfaceCreated,
- this, &AndroidSurfaceView::surfaceCreated);
- { // Lock now to avoid a race with handleSurfaceCreated()
- QMutexLocker locker(shLock());
- m_window = QWindow::fromWinId(WId(m_surfaceView.object()));
-
- if (m_pendingVisible != -1)
- m_window->setVisible(m_pendingVisible);
- if (m_pendingGeometry.isValid())
- m_window->setGeometry(m_pendingGeometry);
- }
- }
-}
-
-AndroidSurfaceView::~AndroidSurfaceView()
-{
- delete m_surfaceHolder;
- delete m_window;
-}
-
-AndroidSurfaceHolder *AndroidSurfaceView::holder() const
-{
- return m_surfaceHolder;
-}
-
-void AndroidSurfaceView::setVisible(bool v)
-{
- if (m_window)
- m_window->setVisible(v);
- else
- m_pendingVisible = int(v);
-}
-
-void AndroidSurfaceView::setGeometry(int x, int y, int width, int height)
-{
- if (m_window)
- m_window->setGeometry(x, y, width, height);
- else
- m_pendingGeometry = QRect(x, y, width, height);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/android/wrappers/jni/androidsurfaceview_p.h b/src/multimedia/platform/android/wrappers/jni/androidsurfaceview_p.h
deleted file mode 100644
index cd0badc34..000000000
--- a/src/multimedia/platform/android/wrappers/jni/androidsurfaceview_p.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef ANDROIDSURFACEVIEW_H
-#define ANDROIDSURFACEVIEW_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/qjniobject.h>
-#include <qrect.h>
-#include <QtCore/qrunnable.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindow;
-
-class AndroidSurfaceHolder : public QObject
-{
- Q_OBJECT
-public:
- ~AndroidSurfaceHolder();
-
- jobject surfaceHolder() const;
- bool isSurfaceCreated() const;
-
- static bool registerNativeMethods();
-
-Q_SIGNALS:
- void surfaceCreated();
-
-private:
- AndroidSurfaceHolder(QJniObject object);
-
- static void handleSurfaceCreated(JNIEnv*, jobject, jlong id);
- static void handleSurfaceDestroyed(JNIEnv*, jobject, jlong id);
-
- QJniObject m_surfaceHolder;
- bool m_surfaceCreated;
-
- friend class AndroidSurfaceView;
-};
-
-class AndroidSurfaceView : public QObject
-{
- Q_OBJECT
-public:
- AndroidSurfaceView();
- ~AndroidSurfaceView();
-
- AndroidSurfaceHolder *holder() const;
-
- void setVisible(bool v);
- void setGeometry(int x, int y, int width, int height);
-
-Q_SIGNALS:
- void surfaceCreated();
-
-private:
- QJniObject m_surfaceView;
- QWindow *m_window;
- AndroidSurfaceHolder *m_surfaceHolder;
- int m_pendingVisible;
- QRect m_pendingGeometry;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDSURFACEVIEW_H
diff --git a/src/multimedia/platform/darwin/audio/avfaudiodecoder.mm b/src/multimedia/platform/darwin/audio/avfaudiodecoder.mm
deleted file mode 100644
index 079c4b39e..000000000
--- a/src/multimedia/platform/darwin/audio/avfaudiodecoder.mm
+++ /dev/null
@@ -1,529 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfaudiodecoder_p.h"
-
-#include <QtCore/qmutex.h>
-#include <QtCore/qiodevice.h>
-#include <QMimeDatabase>
-#include "qcoreaudioutils_p.h"
-
-#include <AVFoundation/AVFoundation.h>
-
-#define MAX_BUFFERS_IN_QUEUE 10
-
-QT_USE_NAMESPACE
-
-@interface AVFResourceReaderDelegate : NSObject <AVAssetResourceLoaderDelegate>
-{
- AVFAudioDecoder *m_decoder;
- QMutex m_mutex;
-}
-
--(void)handleNextSampleBuffer:(CMSampleBufferRef)sampleBuffer;
-
--(BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader
- shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest;
-
-@end
-
-@implementation AVFResourceReaderDelegate
-
--(id)initWithDecoder: (AVFAudioDecoder *)decoder {
- if (!(self = [super init]))
- return nil;
-
- m_decoder = decoder;
-
- return self;
-}
-
--(void)dealloc {
- m_decoder = nil;
- [super dealloc];
-}
-
--(void)handleNextSampleBuffer:(CMSampleBufferRef)sampleBuffer
-{
- if (!sampleBuffer)
- return;
-
- // Check format
- CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
- if (!formatDescription)
- return;
- const AudioStreamBasicDescription* const asbd = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription);
- QAudioFormat qtFormat = CoreAudioUtils::toQAudioFormat(*asbd);
- if (qtFormat.sampleFormat() == QAudioFormat::Unknown && asbd->mBitsPerChannel == 8)
- qtFormat.setSampleFormat(QAudioFormat::UInt8);
- if (!qtFormat.isValid())
- return;
-
- // Get the required size to allocate to audioBufferList
- size_t audioBufferListSize = 0;
- OSStatus err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer,
- &audioBufferListSize,
- NULL,
- 0,
- NULL,
- NULL,
- kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
- NULL);
- if (err != noErr)
- return;
-
- CMBlockBufferRef blockBuffer = NULL;
- AudioBufferList* audioBufferList = (AudioBufferList*) malloc(audioBufferListSize);
- // This ensures the buffers placed in audioBufferList are contiguous
- err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer,
- NULL,
- audioBufferList,
- audioBufferListSize,
- NULL,
- NULL,
- kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
- &blockBuffer);
- if (err != noErr) {
- free(audioBufferList);
- return;
- }
-
- QByteArray abuf;
- for (UInt32 i = 0; i < audioBufferList->mNumberBuffers; i++)
- {
- AudioBuffer audioBuffer = audioBufferList->mBuffers[i];
- abuf.push_back(QByteArray((const char*)audioBuffer.mData, audioBuffer.mDataByteSize));
- }
-
- free(audioBufferList);
- CFRelease(blockBuffer);
-
- CMTime sampleStartTime = (CMSampleBufferGetPresentationTimeStamp(sampleBuffer));
- float sampleStartTimeSecs = CMTimeGetSeconds(sampleStartTime);
-
- QAudioBuffer audioBuffer;
- audioBuffer = QAudioBuffer(abuf, qtFormat, qint64(sampleStartTimeSecs * 1000000));
- if (!audioBuffer.isValid())
- return;
-
- emit m_decoder->newAudioBuffer(audioBuffer);
-}
-
--(BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader
- shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
-{
- Q_UNUSED(resourceLoader);
-
- if (![loadingRequest.request.URL.scheme isEqualToString:@"iodevice"])
- return NO;
-
- QMutexLocker locker(&m_mutex);
-
- QIODevice *device = m_decoder->sourceDevice();
- if (!device)
- return NO;
-
- device->seek(loadingRequest.dataRequest.requestedOffset);
- if (loadingRequest.contentInformationRequest) {
- loadingRequest.contentInformationRequest.contentLength = device->size();
- loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
- }
-
- if (loadingRequest.dataRequest) {
- NSInteger requestedLength = loadingRequest.dataRequest.requestedLength;
- int maxBytes = qMin(32 * 1024, int(requestedLength));
- char buffer[maxBytes];
- NSInteger submitted = 0;
- while (submitted < requestedLength) {
- qint64 len = device->read(buffer, maxBytes);
- if (len < 1)
- break;
-
- [loadingRequest.dataRequest respondWithData:[NSData dataWithBytes:buffer length:len]];
- submitted += len;
- }
-
- // Finish loading even if not all bytes submitted.
- [loadingRequest finishLoading];
- }
-
- return YES;
-}
-
-@end
-
-namespace {
-
-NSDictionary *av_audio_settings_for_format(const QAudioFormat &format)
-{
- float sampleRate = format.sampleRate();
- int nChannels = format.channelCount();
- int sampleSize = format.bytesPerSample() * 8;
- BOOL isFloat = format.sampleFormat() == QAudioFormat::Float;
-
- NSDictionary *audioSettings = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
- [NSNumber numberWithFloat:sampleRate], AVSampleRateKey,
- [NSNumber numberWithInt:nChannels], AVNumberOfChannelsKey,
- [NSNumber numberWithInt:sampleSize], AVLinearPCMBitDepthKey,
- [NSNumber numberWithBool:isFloat], AVLinearPCMIsFloatKey,
- [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
- [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
- nil];
-
- return audioSettings;
-}
-
-QAudioFormat qt_format_for_audio_track(AVAssetTrack *track)
-{
- QAudioFormat format;
- CMFormatDescriptionRef desc = (__bridge CMFormatDescriptionRef)track.formatDescriptions[0];
- const AudioStreamBasicDescription* const asbd =
- CMAudioFormatDescriptionGetStreamBasicDescription(desc);
- format = CoreAudioUtils::toQAudioFormat(*asbd);
- // AudioStreamBasicDescription's mBitsPerChannel is 0 for compressed formats
- // In this case set default Int16 sample format
- if (asbd->mBitsPerChannel == 0)
- format.setSampleFormat(QAudioFormat::Int16);
- return format;
-}
-
-}
-
-AVFAudioDecoder::AVFAudioDecoder(QAudioDecoder *parent)
- : QPlatformAudioDecoder(parent)
-{
- m_readingQueue = dispatch_queue_create("reader_queue", DISPATCH_QUEUE_SERIAL);
- m_decodingQueue = dispatch_queue_create("decoder_queue", DISPATCH_QUEUE_SERIAL);
-
- m_readerDelegate = [[AVFResourceReaderDelegate alloc] initWithDecoder:this];
-
- connect(this, &AVFAudioDecoder::readyToRead, this, &AVFAudioDecoder::startReading);
- connect(this, &AVFAudioDecoder::newAudioBuffer, this, &AVFAudioDecoder::handleNewAudioBuffer);
-}
-
-AVFAudioDecoder::~AVFAudioDecoder()
-{
- stop();
-
- [m_readerOutput release];
- m_readerOutput = nil;
-
- [m_reader release];
- m_reader = nil;
-
- [m_readerDelegate release];
- m_readerDelegate = nil;
-
- [m_asset release];
- m_asset = nil;
-
- if (m_readingQueue)
- dispatch_release(m_readingQueue);
- if (m_decodingQueue)
- dispatch_release(m_decodingQueue);
-}
-
-QUrl AVFAudioDecoder::source() const
-{
- return m_source;
-}
-
-void AVFAudioDecoder::setSource(const QUrl &fileName)
-{
- if (!m_device && m_source == fileName)
- return;
-
- stop();
- m_device = nullptr;
- [m_asset release];
- m_asset = nil;
-
- m_source = fileName;
-
- if (!m_source.isEmpty()) {
- NSURL *nsURL = m_source.toNSURL();
- m_asset = [[AVURLAsset alloc] initWithURL:nsURL options:nil];
- }
-
- emit sourceChanged();
-}
-
-QIODevice *AVFAudioDecoder::sourceDevice() const
-{
- return m_device;
-}
-
-void AVFAudioDecoder::setSourceDevice(QIODevice *device)
-{
- if (m_device == device && m_source.isEmpty())
- return;
-
- stop();
- m_source.clear();
- [m_asset release];
- m_asset = nil;
-
- m_device = device;
-
- if (m_device) {
- const QString ext = QMimeDatabase().mimeTypeForData(m_device).preferredSuffix();
- const QString url = "iodevice:///iodevice." + ext;
- NSString *urlString = url.toNSString();
- NSURL *nsURL = [NSURL URLWithString:urlString];
-
- m_asset = [[AVURLAsset alloc] initWithURL:nsURL options:nil];
- [m_asset.resourceLoader setDelegate:m_readerDelegate queue:m_readingQueue];
-
- m_loadingSource = true;
- }
-
- emit sourceChanged();
-}
-
-void AVFAudioDecoder::start()
-{
- Q_ASSERT(!m_buffersAvailable);
- if (isDecoding())
- return;
-
- if (m_position != -1) {
- m_position = -1;
- emit positionChanged(-1);
- }
-
- if (m_device && (!m_device->isOpen() || !m_device->isReadable())) {
- processInvalidMedia(QAudioDecoder::AccessDeniedError, tr("Unable to read from specified device"));
- return;
- }
-
- [m_asset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:
- ^{
- dispatch_async(m_readingQueue,
- ^{
- NSError *error = nil;
- AVKeyValueStatus status = [m_asset statusOfValueForKey:@"tracks" error:&error];
- if (status != AVKeyValueStatusLoaded) {
- if (status == AVKeyValueStatusFailed) {
- if (error.domain == NSURLErrorDomain)
- processInvalidMedia(QAudioDecoder::ResourceError, QString::fromNSString(error.localizedDescription));
- else
- processInvalidMedia(QAudioDecoder::FormatError, tr("Could not load media source's tracks"));
- }
- return;
- }
- initAssetReader();
- });
- }
- ];
-
- if (m_device && m_loadingSource) {
- setIsDecoding(true);
- return;
- }
-}
-
-void AVFAudioDecoder::stop()
-{
- m_cachedBuffers.clear();
-
- if (m_reader)
- [m_reader cancelReading];
-
- if (m_buffersAvailable != 0) {
- m_buffersAvailable = 0;
- emit bufferAvailableChanged(false);
- }
- if (m_position != -1) {
- m_position = -1;
- emit positionChanged(m_position);
- }
- if (m_duration != -1) {
- m_duration = -1;
- emit durationChanged(m_duration);
- }
- setIsDecoding(false);
-}
-
-QAudioFormat AVFAudioDecoder::audioFormat() const
-{
- return m_format;
-}
-
-void AVFAudioDecoder::setAudioFormat(const QAudioFormat &format)
-{
- if (m_format != format) {
- m_format = format;
- emit formatChanged(m_format);
- }
-}
-
-QAudioBuffer AVFAudioDecoder::read()
-{
- if (!m_buffersAvailable)
- return QAudioBuffer();
-
- Q_ASSERT(m_cachedBuffers.size() > 0);
- QAudioBuffer buffer = m_cachedBuffers.takeFirst();
-
- m_position = qint64(buffer.startTime() / 1000);
- emit positionChanged(m_position);
-
- m_buffersAvailable--;
- if (!m_buffersAvailable)
- emit bufferAvailableChanged(false);
- return buffer;
-}
-
-bool AVFAudioDecoder::bufferAvailable() const
-{
- return m_buffersAvailable > 0;
-}
-
-qint64 AVFAudioDecoder::position() const
-{
- return m_position;
-}
-
-qint64 AVFAudioDecoder::duration() const
-{
- return m_duration;
-}
-
-void AVFAudioDecoder::processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString)
-{
- stop();
- emit error(int(errorCode), errorString);
-}
-
-void AVFAudioDecoder::initAssetReader()
-{
- if (!m_asset)
- return;
-
- NSArray<AVAssetTrack *> *tracks = [m_asset tracksWithMediaType:AVMediaTypeAudio];
- if (!tracks.count) {
- processInvalidMedia(QAudioDecoder::FormatError, tr("No audio tracks found"));
- return;
- }
- AVAssetTrack *track = [tracks objectAtIndex:0];
-
- // Set format
- QAudioFormat format;
- if (m_format.isValid()) {
- format = m_format;
- } else {
- format = qt_format_for_audio_track(track);
- if (!format.isValid())
- {
- processInvalidMedia(QAudioDecoder::FormatError, tr("Unsupported source format"));
- return;
- }
- }
-
- // Set duration
- qint64 duration = CMTimeGetSeconds(track.timeRange.duration) * 1000;
- if (m_duration != duration) {
- m_duration = duration;
- emit durationChanged(m_duration);
- }
-
- // Initialize asset reader and output
- [m_reader release];
- m_reader = nil;
- [m_readerOutput release];
- m_readerOutput = nil;
-
- NSError *error = nil;
- NSDictionary *audioSettings = av_audio_settings_for_format(format);
- m_readerOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:audioSettings];
- m_reader = [[AVAssetReader alloc] initWithAsset:m_asset error:&error];
- if (error) {
- processInvalidMedia(QAudioDecoder::ResourceError, QString::fromNSString(error.localizedDescription));
- return;
- }
- if (![m_reader canAddOutput:m_readerOutput]) {
- processInvalidMedia(QAudioDecoder::ResourceError, tr("Failed to add asset reader output"));
- return;
- }
- [m_reader addOutput:m_readerOutput];
-
- emit readyToRead();
-}
-
-void AVFAudioDecoder::startReading()
-{
- m_loadingSource = false;
-
- // Prepares the receiver for obtaining sample buffers from the asset.
- if (!m_reader || ![m_reader startReading]) {
- processInvalidMedia(QAudioDecoder::ResourceError, tr("Could not start reading"));
- return;
- }
-
- setIsDecoding(true);
-
- // Since copyNextSampleBuffer is synchronous, submit it to an async dispatch queue
- // to run in a separate thread. Call the handleNextSampleBuffer "callback" on another
- // thread when new audio sample is read.
- dispatch_async(m_readingQueue, ^{
- CMSampleBufferRef sampleBuffer;
- while ((sampleBuffer = [m_readerOutput copyNextSampleBuffer])) {
- dispatch_async(m_decodingQueue, ^{
- if (CMSampleBufferDataIsReady(sampleBuffer))
- [m_readerDelegate handleNextSampleBuffer:sampleBuffer];
- CFRelease(sampleBuffer);
- });
- }
- if (m_reader.status == AVAssetReaderStatusCompleted)
- emit finished();
- });
-}
-
-void AVFAudioDecoder::handleNewAudioBuffer(QAudioBuffer buffer)
-{
- Q_ASSERT(m_cachedBuffers.size() <= MAX_BUFFERS_IN_QUEUE);
- m_cachedBuffers.push_back(buffer);
-
- m_buffersAvailable++;
- Q_ASSERT(m_buffersAvailable <= MAX_BUFFERS_IN_QUEUE);
-
- emit bufferAvailableChanged(true);
- emit bufferReady();
-}
diff --git a/src/multimedia/platform/darwin/audio/avfaudiodecoder_p.h b/src/multimedia/platform/darwin/audio/avfaudiodecoder_p.h
deleted file mode 100644
index 73a8cbd38..000000000
--- a/src/multimedia/platform/darwin/audio/avfaudiodecoder_p.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFAUDIODECODER_H
-#define AVFAUDIODECODER_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/qtmultimediaglobal_p.h>
-#include <QObject>
-#include <QtCore/qurl.h>
-
-#include "private/qplatformaudiodecoder_p.h"
-#include "qaudiodecoder.h"
-
-#include <dispatch/dispatch.h>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(AVURLAsset);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVAssetReader);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVAssetReaderTrackOutput);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVFResourceReaderDelegate);
-
-QT_BEGIN_NAMESPACE
-
-class AVFAudioDecoder : public QPlatformAudioDecoder
-{
- Q_OBJECT
-
-public:
- AVFAudioDecoder(QAudioDecoder *parent);
- virtual ~AVFAudioDecoder();
-
- QUrl source() const override;
- void setSource(const QUrl &fileName) override;
-
- QIODevice *sourceDevice() const override;
- void setSourceDevice(QIODevice *device) override;
-
- void start() override;
- void stop() override;
-
- QAudioFormat audioFormat() const override;
- void setAudioFormat(const QAudioFormat &format) override;
-
- QAudioBuffer read() override;
- bool bufferAvailable() const override;
-
- qint64 position() const override;
- qint64 duration() const override;
-
-private slots:
- void handleNewAudioBuffer(QAudioBuffer);
- void startReading();
-
-signals:
- void newAudioBuffer(QAudioBuffer);
- void readyToRead();
-
-private:
- void processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString);
- void initAssetReader();
-
- QUrl m_source;
- QIODevice *m_device = nullptr;
- QAudioFormat m_format;
-
- int m_buffersAvailable = 0;
- QList<QAudioBuffer> m_cachedBuffers;
-
- qint64 m_position = -1;
- qint64 m_duration = -1;
-
- bool m_loadingSource = false;
-
- AVURLAsset *m_asset = nullptr;
- AVAssetReader *m_reader = nullptr;
- AVAssetReaderTrackOutput *m_readerOutput = nullptr;
- AVFResourceReaderDelegate *m_readerDelegate = nullptr;
- dispatch_queue_t m_readingQueue;
- dispatch_queue_t m_decodingQueue;
-};
-
-QT_END_NAMESPACE
-
-#endif // AVFAUDIODECODER_H
diff --git a/src/multimedia/platform/darwin/audio/qcoreaudioutils.mm b/src/multimedia/platform/darwin/audio/qcoreaudioutils.mm
deleted file mode 100644
index 8faa353c7..000000000
--- a/src/multimedia/platform/darwin/audio/qcoreaudioutils.mm
+++ /dev/null
@@ -1,219 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qcoreaudioutils_p.h"
-#include <mach/mach_time.h>
-
-QT_BEGIN_NAMESPACE
-
-double CoreAudioUtils::sFrequency = 0.0;
-bool CoreAudioUtils::sIsInitialized = false;
-
-void CoreAudioUtils::initialize()
-{
- struct mach_timebase_info timeBaseInfo;
- mach_timebase_info(&timeBaseInfo);
- sFrequency = static_cast<double>(timeBaseInfo.denom) / static_cast<double>(timeBaseInfo.numer);
- sFrequency *= 1000000000.0;
-
- sIsInitialized = true;
-}
-
-
-quint64 CoreAudioUtils::currentTime()
-{
- return mach_absolute_time();
-}
-
-double CoreAudioUtils::frequency()
-{
- if (!sIsInitialized)
- initialize();
- return sFrequency;
-}
-
-QAudioFormat CoreAudioUtils::toQAudioFormat(AudioStreamBasicDescription const& sf)
-{
- QAudioFormat audioFormat;
- // all Darwin HW is little endian, we ignore those formats
- if ((sf.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0 && QSysInfo::ByteOrder != QSysInfo::LittleEndian)
- return audioFormat;
-
- // filter out the formats we're interested in
- QAudioFormat::SampleFormat format = QAudioFormat::Unknown;
- switch (sf.mBitsPerChannel) {
- case 8:
- if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) == 0)
- format = QAudioFormat::UInt8;
- break;
- case 16:
- if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
- format = QAudioFormat::Int16;
- break;
- case 32:
- if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
- format = QAudioFormat::Int32;
- else if ((sf.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
- format = QAudioFormat::Float;
- break;
- default:
- break;
- }
-
- audioFormat.setSampleFormat(format);
- audioFormat.setSampleRate(sf.mSampleRate);
- audioFormat.setChannelCount(sf.mChannelsPerFrame);
-
- return audioFormat;
-}
-
-AudioStreamBasicDescription CoreAudioUtils::toAudioStreamBasicDescription(QAudioFormat const& audioFormat)
-{
- AudioStreamBasicDescription sf;
-
- sf.mFormatFlags = kAudioFormatFlagIsPacked;
- sf.mSampleRate = audioFormat.sampleRate();
- sf.mFramesPerPacket = 1;
- sf.mChannelsPerFrame = audioFormat.channelCount();
- sf.mBitsPerChannel = audioFormat.bytesPerSample() * 8;
- sf.mBytesPerFrame = audioFormat.bytesPerFrame();
- sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame;
- sf.mFormatID = kAudioFormatLinearPCM;
-
- switch (audioFormat.sampleFormat()) {
- case QAudioFormat::Int16:
- case QAudioFormat::Int32:
- sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
- break;
- case QAudioFormat::Float:
- sf.mFormatFlags |= kAudioFormatFlagIsFloat;
- break;
- case QAudioFormat::UInt8:
- /* default */
- case QAudioFormat::Unknown:
- case QAudioFormat::NSampleFormats:
- break;
- }
-
- return sf;
-}
-
-// QAudioRingBuffer
-CoreAudioRingBuffer::CoreAudioRingBuffer(int bufferSize):
- m_bufferSize(bufferSize)
-{
- m_buffer = new char[m_bufferSize];
- reset();
-}
-
-CoreAudioRingBuffer::~CoreAudioRingBuffer()
-{
- delete[] m_buffer;
-}
-
-CoreAudioRingBuffer::Region CoreAudioRingBuffer::acquireReadRegion(int size)
-{
- const int used = m_bufferUsed.fetchAndAddAcquire(0);
-
- if (used > 0) {
- const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used));
-
- return readSize > 0 ? Region(m_buffer + m_readPos, readSize) : Region(0, 0);
- }
-
- return Region(0, 0);
-}
-
-void CoreAudioRingBuffer::releaseReadRegion(const CoreAudioRingBuffer::Region &region)
-{
- m_readPos = (m_readPos + region.second) % m_bufferSize;
-
- m_bufferUsed.fetchAndAddRelease(-region.second);
-}
-
-CoreAudioRingBuffer::Region CoreAudioRingBuffer::acquireWriteRegion(int size)
-{
- const int free = m_bufferSize - m_bufferUsed.fetchAndAddAcquire(0);
-
- Region output;
-
- if (free > 0) {
- const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free));
- output = writeSize > 0 ? Region(m_buffer + m_writePos, writeSize) : Region(0, 0);
- } else {
- output = Region(0, 0);
- }
-#ifdef QT_DEBUG_COREAUDIO
- qDebug("acquireWriteRegion(%d) free: %d returning Region(%p, %d)", size, free, output.first, output.second);
-#endif
- return output;
-}
-void CoreAudioRingBuffer::releaseWriteRegion(const CoreAudioRingBuffer::Region &region)
-{
- m_writePos = (m_writePos + region.second) % m_bufferSize;
-
- m_bufferUsed.fetchAndAddRelease(region.second);
-#ifdef QT_DEBUG_COREAUDIO
- qDebug("releaseWriteRegion(%p,%d): m_writePos:%d", region.first, region.second, m_writePos);
-#endif
-}
-
-int CoreAudioRingBuffer::used() const
-{
- return m_bufferUsed.loadRelaxed();
-}
-
-int CoreAudioRingBuffer::free() const
-{
- return m_bufferSize - m_bufferUsed.loadRelaxed();
-}
-
-int CoreAudioRingBuffer::size() const
-{
- return m_bufferSize;
-}
-
-void CoreAudioRingBuffer::reset()
-{
- m_readPos = 0;
- m_writePos = 0;
- m_bufferUsed.storeRelaxed(0);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/audio/qcoreaudioutils_p.h b/src/multimedia/platform/darwin/audio/qcoreaudioutils_p.h
deleted file mode 100644
index 4f9d5d327..000000000
--- a/src/multimedia/platform/darwin/audio/qcoreaudioutils_p.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef IOSAUDIOUTILS_H
-#define IOSAUDIOUTILS_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 <CoreAudio/CoreAudioTypes.h>
-
-#include <QtMultimedia/QAudioFormat>
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class CoreAudioUtils
-{
-public:
- static quint64 currentTime();
- static double frequency();
- static QAudioFormat toQAudioFormat(const AudioStreamBasicDescription& streamFormat);
- static AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat);
-
-private:
- static void initialize();
- static double sFrequency;
- static bool sIsInitialized;
-};
-
-class CoreAudioRingBuffer
-{
-public:
- typedef QPair<char*, int> Region;
-
- CoreAudioRingBuffer(int bufferSize);
- ~CoreAudioRingBuffer();
-
- Region acquireReadRegion(int size);
- void releaseReadRegion(Region const& region);
- Region acquireWriteRegion(int size);
- void releaseWriteRegion(Region const& region);
-
- int used() const;
- int free() const;
- int size() const;
-
- void reset();
-
-private:
- int m_bufferSize;
- int m_readPos;
- int m_writePos;
- char* m_buffer;
- QAtomicInt m_bufferUsed;
-};
-
-QT_END_NAMESPACE
-
-#endif // IOSAUDIOUTILS_H
diff --git a/src/multimedia/platform/darwin/audio/qdarwinaudiodevice.mm b/src/multimedia/platform/darwin/audio/qdarwinaudiodevice.mm
deleted file mode 100644
index 8fe6f1a2c..000000000
--- a/src/multimedia/platform/darwin/audio/qdarwinaudiodevice.mm
+++ /dev/null
@@ -1,153 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdarwinaudiodevice_p.h"
-#include "qcoreaudioutils_p.h"
-#include <private/qcore_mac_p.h>
-
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-# include "qcoreaudiosessionmanager_p.h"
-#endif
-
-#include <QtCore/QDataStream>
-#include <QtCore/QDebug>
-#include <QtCore/QSet>
-#include <QIODevice>
-
-QT_BEGIN_NAMESPACE
-
-#if defined(Q_OS_MACOS)
- QCoreAudioDeviceInfo::QCoreAudioDeviceInfo(AudioDeviceID id, const QByteArray &device, QAudioDevice::Mode mode)
- : QAudioDevicePrivate(device, mode),
- m_deviceId(id)
-#else
- QCoreAudioDeviceInfo::QCoreAudioDeviceInfo(const QByteArray &device, QAudioDevice::Mode mode)
- : QAudioDevicePrivate(device, mode)
-#endif
- {
- preferredFormat = determinePreferredFormat();
- description = getDescription();
- minimumSampleRate = 1;
- maximumSampleRate = 96000;
- minimumChannelCount = 1;
- maximumChannelCount = 16;
- supportedSampleFormats << QAudioFormat::UInt8 << QAudioFormat::Int16 << QAudioFormat::Int32 << QAudioFormat::Float;
- }
-
-
-QAudioFormat QCoreAudioDeviceInfo::determinePreferredFormat() const
-{
- QAudioFormat format;
-
-#if defined(Q_OS_MACOS)
- UInt32 propSize = 0;
- AudioObjectPropertyScope audioDevicePropertyScope = mode == QAudioDevice::Input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
- AudioObjectPropertyAddress audioDevicePropertyStreamsAddress = { kAudioDevicePropertyStreams,
- audioDevicePropertyScope,
- kAudioObjectPropertyElementMaster };
-
- if (AudioObjectGetPropertyDataSize(m_deviceId, &audioDevicePropertyStreamsAddress, 0, NULL, &propSize) == noErr) {
-
- const int sc = propSize / sizeof(AudioStreamID);
-
- if (sc > 0) {
- AudioStreamID* streams = new AudioStreamID[sc];
-
- if (AudioObjectGetPropertyData(m_deviceId, &audioDevicePropertyStreamsAddress, 0, NULL, &propSize, streams) == noErr) {
-
- AudioObjectPropertyAddress audioDevicePhysicalFormatPropertyAddress = { kAudioStreamPropertyPhysicalFormat,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- for (int i = 0; i < sc; ++i) {
- if (AudioObjectGetPropertyDataSize(streams[i], &audioDevicePhysicalFormatPropertyAddress, 0, NULL, &propSize) == noErr) {
- AudioStreamBasicDescription sf;
-
- if (AudioObjectGetPropertyData(streams[i], &audioDevicePhysicalFormatPropertyAddress, 0, NULL, &propSize, &sf) == noErr) {
- format = CoreAudioUtils::toQAudioFormat(sf);
- break;
- } else {
- qWarning() << "QAudioDevice: Unable to find perferedFormat for stream";
- }
- } else {
- qWarning() << "QAudioDevice: Unable to find size of perferedFormat for stream";
- }
- }
- }
-
- delete[] streams;
- }
- }
- if (!format.isValid())
-#endif
- {
- format.setSampleRate(44100);
- format.setSampleFormat(QAudioFormat::Int16);
- format.setChannelCount(mode == QAudioDevice::Input ? 1 : 2);
- }
-
- return format;
-}
-
-
-QString QCoreAudioDeviceInfo::getDescription() const
-{
-#ifdef Q_OS_MACOS
- CFStringRef name;
- UInt32 size = sizeof(CFStringRef);
- AudioObjectPropertyScope audioPropertyScope = mode == QAudioDevice::Input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
-
- AudioObjectPropertyAddress audioDeviceNamePropertyAddress = { kAudioObjectPropertyName,
- audioPropertyScope,
- kAudioObjectPropertyElementMaster };
-
- if (AudioObjectGetPropertyData(m_deviceId, &audioDeviceNamePropertyAddress, 0, NULL, &size, &name) != noErr) {
- qWarning() << "QAudioDevice: Unable to find device description";
- return QString();
- }
-
- QString s = QString::fromCFString(name);
- CFRelease(name);
- return s;
-#else
- return QString::fromUtf8(id);
-#endif
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/audio/qdarwinaudiodevice_p.h b/src/multimedia/platform/darwin/audio/qdarwinaudiodevice_p.h
deleted file mode 100644
index 8a1ad502d..000000000
--- a/src/multimedia/platform/darwin/audio/qdarwinaudiodevice_p.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef IOSAUDIODEVICEINFO_H
-#define IOSAUDIODEVICEINFO_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 <qaudiosystem_p.h>
-#include <private/qaudiodevice_p.h>
-
-#if defined(Q_OS_MACOS)
-# include <CoreAudio/CoreAudio.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QCoreAudioDeviceInfo : public QAudioDevicePrivate
-{
-public:
-#if defined(Q_OS_MACOS)
- QCoreAudioDeviceInfo(AudioDeviceID id, const QByteArray &device, QAudioDevice::Mode mode);
-#else
- QCoreAudioDeviceInfo(const QByteArray &device, QAudioDevice::Mode mode);
-#endif
- ~QCoreAudioDeviceInfo() {}
-
- bool isFormatSupported(const QAudioFormat &format) const;
-
-#if defined(Q_OS_MACOS)
- AudioDeviceID deviceID() const { return m_deviceId; }
-#endif
-private:
- QAudioFormat determinePreferredFormat() const;
- QString getDescription() const;
-#if defined(Q_OS_MACOS)
- AudioDeviceID m_deviceId;
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/avfvideobuffer.mm b/src/multimedia/platform/darwin/avfvideobuffer.mm
deleted file mode 100644
index 67cd42d50..000000000
--- a/src/multimedia/platform/darwin/avfvideobuffer.mm
+++ /dev/null
@@ -1,315 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfvideobuffer_p.h"
-#include <private/qrhi_p.h>
-#include <private/qrhimetal_p.h>
-#include <private/qrhigles2_p.h>
-#include <CoreVideo/CVMetalTexture.h>
-#include <CoreVideo/CVMetalTextureCache.h>
-#include <QtGui/qopenglcontext.h>
-
-#include <private/qvideotexturehelper_p.h>
-
-#import <AVFoundation/AVFoundation.h>
-#import <Metal/Metal.h>
-
-QT_USE_NAMESPACE
-
-AVFVideoBuffer::AVFVideoBuffer(AVFVideoSinkInterface *sink, CVImageBufferRef buffer)
- : QAbstractVideoBuffer(sink->rhi() ? QVideoFrame::RhiTextureHandle : QVideoFrame::NoHandle, sink->rhi()),
- sink(sink),
- m_buffer(buffer)
-{
-// m_type = QVideoFrame::NoHandle;
-// qDebug() << "RHI" << rhi;
- CVPixelBufferRetain(m_buffer);
- m_pixelFormat = fromCVVideoPixelFormat(CVPixelBufferGetPixelFormatType(m_buffer));
-}
-
-AVFVideoBuffer::~AVFVideoBuffer()
-{
- AVFVideoBuffer::unmap();
- for (int i = 0; i < 3; ++i)
- if (cvMetalTexture[i])
- CFRelease(cvMetalTexture[i]);
-#if defined(Q_OS_MACOS)
- if (cvOpenGLTexture)
- CVOpenGLTextureRelease(cvOpenGLTexture);
-#elif defined(Q_OS_IOS)
- if (cvOpenGLESTexture)
- CFRelease(cvOpenGLESTexture);
-#endif
- CVPixelBufferRelease(m_buffer);
-}
-
-AVFVideoBuffer::MapData AVFVideoBuffer::map(QVideoFrame::MapMode mode)
-{
- MapData mapData;
-
- if (m_mode == QVideoFrame::NotMapped) {
- CVPixelBufferLockBaseAddress(m_buffer, mode == QVideoFrame::ReadOnly
- ? kCVPixelBufferLock_ReadOnly
- : 0);
- m_mode = mode;
- }
-
- mapData.nPlanes = CVPixelBufferGetPlaneCount(m_buffer);
- Q_ASSERT(mapData.nPlanes <= 3);
-
- if (!mapData.nPlanes) {
- // single plane
- mapData.bytesPerLine[0] = CVPixelBufferGetBytesPerRow(m_buffer);
- mapData.data[0] = static_cast<uchar*>(CVPixelBufferGetBaseAddress(m_buffer));
- mapData.size[0] = CVPixelBufferGetDataSize(m_buffer);
- mapData.nPlanes = mapData.data[0] ? 1 : 0;
- return mapData;
- }
-
- // For a bi-planar or tri-planar format we have to set the parameters correctly:
- for (int i = 0; i < mapData.nPlanes; ++i) {
- mapData.bytesPerLine[i] = CVPixelBufferGetBytesPerRowOfPlane(m_buffer, i);
- mapData.size[i] = mapData.bytesPerLine[i]*CVPixelBufferGetHeightOfPlane(m_buffer, i);
- mapData.data[i] = static_cast<uchar*>(CVPixelBufferGetBaseAddressOfPlane(m_buffer, i));
- }
-
- return mapData;
-}
-
-void AVFVideoBuffer::unmap()
-{
- if (m_mode != QVideoFrame::NotMapped) {
- CVPixelBufferUnlockBaseAddress(m_buffer, m_mode == QVideoFrame::ReadOnly
- ? kCVPixelBufferLock_ReadOnly
- : 0);
- m_mode = QVideoFrame::NotMapped;
- }
-}
-
-static MTLPixelFormat rhiTextureFormatToMetalFormat(QRhiTexture::Format f)
-{
- switch (f) {
- default:
- case QRhiTexture::UnknownFormat:
- return MTLPixelFormatInvalid;
- case QRhiTexture::RGBA8:
- return MTLPixelFormatRGBA8Unorm;
- case QRhiTexture::BGRA8:
- return MTLPixelFormatBGRA8Unorm;
- case QRhiTexture::R8:
- return MTLPixelFormatR8Unorm;
- case QRhiTexture::RG8:
- return MTLPixelFormatRG8Unorm;
- case QRhiTexture::R16:
- return MTLPixelFormatR16Unorm;
- case QRhiTexture::RG16:
- return MTLPixelFormatRG16Unorm;
-
- case QRhiTexture::RGBA16F:
- return MTLPixelFormatRGBA16Float;
- case QRhiTexture::RGBA32F:
- return MTLPixelFormatRGBA32Float;
- case QRhiTexture::R16F:
- return MTLPixelFormatR16Float;
- case QRhiTexture::R32F:
- return MTLPixelFormatR32Float;
- }
-}
-
-
-quint64 AVFVideoBuffer::textureHandle(int plane) const
-{
- auto *textureDescription = QVideoTextureHelper::textureDescription(m_pixelFormat);
- int bufferPlanes = CVPixelBufferGetPlaneCount(m_buffer);
-// qDebug() << "texture handle" << plane << rhi << (rhi->backend() == QRhi::Metal) << bufferPlanes;
- if (plane > 0 && plane >= bufferPlanes)
- return 0;
- if (!rhi)
- return 0;
- if (rhi->backend() == QRhi::Metal) {
- if (!cvMetalTexture[plane]) {
- size_t width = CVPixelBufferGetWidth(m_buffer);
- size_t height = CVPixelBufferGetHeight(m_buffer);
- width = textureDescription->widthForPlane(width, plane);
- height = textureDescription->heightForPlane(height, plane);
-
- // Create a CoreVideo pixel buffer backed Metal texture image from the texture cache.
- auto ret = CVMetalTextureCacheCreateTextureFromImage(
- kCFAllocatorDefault,
- sink->cvMetalTextureCache,
- m_buffer, nil,
- rhiTextureFormatToMetalFormat(textureDescription->textureFormat[plane]),
- width, height,
- plane,
- &cvMetalTexture[plane]);
-
- if (ret != kCVReturnSuccess)
- qWarning() << "texture creation failed" << ret;
-// auto t = CVMetalTextureGetTexture(cvMetalTexture[plane]);
-// qDebug() << " metal texture is" << quint64(cvMetalTexture[plane]) << width << height;
-// qDebug() << " " << t.iosurfacePlane << t.pixelFormat << t.width << t.height;
- }
-
- // Get a Metal texture using the CoreVideo Metal texture reference.
-// qDebug() << " -> " << quint64(CVMetalTextureGetTexture(cvMetalTexture[plane]));
- return cvMetalTexture[plane] ? quint64(CVMetalTextureGetTexture(cvMetalTexture[plane])) : 0;
- } else if (rhi->backend() == QRhi::OpenGLES2) {
-#ifdef Q_OS_MACOS
- CVOpenGLTextureCacheFlush(sink->cvOpenGLTextureCache, 0);
- CVReturn cvret;
- // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
- cvret = CVOpenGLTextureCacheCreateTextureFromImage(
- kCFAllocatorDefault,
- sink->cvOpenGLTextureCache,
- m_buffer,
- nil,
- &cvOpenGLTexture);
-
- Q_ASSERT(CVOpenGLTextureGetTarget(cvOpenGLTexture) == GL_TEXTURE_RECTANGLE);
- // Get an OpenGL texture name from the CVPixelBuffer-backed OpenGL texture image.
- return CVOpenGLTextureGetName(cvOpenGLTexture);
-#endif
-#ifdef Q_OS_IOS
- CVOpenGLESTextureCacheFlush(sink->cvOpenGLESTextureCache, 0);
- CVReturn cvret;
- // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
- cvret = CVOpenGLESTextureCacheCreateTextureFromImage(
- kCFAllocatorDefault,
- sink->cvOpenGLESTextureCache,
- m_buffer,
- nil,
- GL_TEXTURE_2D,
- GL_RGBA,
- CVPixelBufferGetWidth(m_buffer),
- CVPixelBufferGetHeight(m_buffer),
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- 0,
- &cvOpenGLESTexture);
-
- // Get an OpenGL texture name from the CVPixelBuffer-backed OpenGL texture image.
- return CVOpenGLESTextureGetName(cvOpenGLESTexture);
-#endif
- }
- return 0;
-}
-
-
-QVideoFrameFormat::PixelFormat AVFVideoBuffer::fromCVVideoPixelFormat(unsigned avPixelFormat) const
-{
-#ifdef Q_OS_MACOS
- if (sink->rhi() && sink->rhi()->backend() == QRhi::OpenGLES2) {
- if (avPixelFormat == kCVPixelFormatType_32BGRA)
- return QVideoFrameFormat::Format_SamplerRect;
- else
- qWarning() << "Accelerated macOS OpenGL video supports BGRA only, got CV pixel format" << avPixelFormat;
- }
-#endif
- return fromCVPixelFormat(avPixelFormat);
-}
-
-QVideoFrameFormat::PixelFormat AVFVideoBuffer::fromCVPixelFormat(unsigned avPixelFormat)
-{
- switch (avPixelFormat) {
- case kCVPixelFormatType_32ARGB:
- return QVideoFrameFormat::Format_ARGB8888;
- case kCVPixelFormatType_32BGRA:
- return QVideoFrameFormat::Format_BGRA8888;
- case kCVPixelFormatType_420YpCbCr8Planar:
- case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
- return QVideoFrameFormat::Format_YUV420P;
- case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
- case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
- return QVideoFrameFormat::Format_NV12;
- case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
- case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
- return QVideoFrameFormat::Format_P010;
- case kCVPixelFormatType_422YpCbCr8:
- return QVideoFrameFormat::Format_UYVY;
- case kCVPixelFormatType_422YpCbCr8_yuvs:
- return QVideoFrameFormat::Format_YUYV;
- case kCVPixelFormatType_OneComponent8:
- return QVideoFrameFormat::Format_Y8;
- case q_kCVPixelFormatType_OneComponent16:
- return QVideoFrameFormat::Format_Y16;
-
- case kCMVideoCodecType_JPEG:
- case kCMVideoCodecType_JPEG_OpenDML:
- return QVideoFrameFormat::Format_Jpeg;
- default:
- return QVideoFrameFormat::Format_Invalid;
- }
-}
-
-bool AVFVideoBuffer::toCVPixelFormat(QVideoFrameFormat::PixelFormat qtFormat, unsigned &conv)
-{
- switch (qtFormat) {
- case QVideoFrameFormat::Format_ARGB8888:
- conv = kCVPixelFormatType_32ARGB;
- break;
- case QVideoFrameFormat::Format_BGRA8888:
- conv = kCVPixelFormatType_32BGRA;
- break;
- case QVideoFrameFormat::Format_YUV420P:
- conv = kCVPixelFormatType_420YpCbCr8PlanarFullRange;
- break;
- case QVideoFrameFormat::Format_NV12:
- conv = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
- break;
- case QVideoFrameFormat::Format_P010:
- conv = kCVPixelFormatType_420YpCbCr10BiPlanarFullRange;
- break;
- case QVideoFrameFormat::Format_UYVY:
- conv = kCVPixelFormatType_422YpCbCr8;
- break;
- case QVideoFrameFormat::Format_YUYV:
- conv = kCVPixelFormatType_422YpCbCr8_yuvs;
- break;
- case QVideoFrameFormat::Format_Y8:
- conv = kCVPixelFormatType_OneComponent8;
- break;
- case QVideoFrameFormat::Format_Y16:
- conv = q_kCVPixelFormatType_OneComponent16;
- break;
- default:
- return false;
- }
-
- return true;
-}
diff --git a/src/multimedia/platform/darwin/avfvideobuffer_p.h b/src/multimedia/platform/darwin/avfvideobuffer_p.h
deleted file mode 100644
index 61590115b..000000000
--- a/src/multimedia/platform/darwin/avfvideobuffer_p.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFVIDEOBUFFER_H
-#define AVFVIDEOBUFFER_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/qvideoframe.h>
-#include <private/qabstractvideobuffer_p.h>
-
-#include <QtCore/qobject.h>
-#include <QtCore/qmutex.h>
-#include <private/avfvideosink_p.h>
-
-#include <CoreVideo/CVBase.h>
-#include <CoreVideo/CVPixelBuffer.h>
-#include <CoreVideo/CVImageBuffer.h>
-
-#import "Metal/Metal.h"
-#import "MetalKit/MetalKit.h"
-
-enum {
- // macOS 10.14 doesn't define this pixel format yet
- q_kCVPixelFormatType_OneComponent16 = 'L016'
-};
-
-QT_BEGIN_NAMESPACE
-
-struct AVFMetalTexture;
-class AVFVideoBuffer : public QAbstractVideoBuffer
-{
-public:
- AVFVideoBuffer(AVFVideoSinkInterface *sink, CVImageBufferRef buffer);
- ~AVFVideoBuffer();
-
- QVideoFrameFormat::PixelFormat fromCVVideoPixelFormat(unsigned avPixelFormat) const;
-
- static QVideoFrameFormat::PixelFormat fromCVPixelFormat(unsigned avPixelFormat);
- static bool toCVPixelFormat(QVideoFrameFormat::PixelFormat qtFormat, unsigned &conv);
-
-
- QVideoFrame::MapMode mapMode() const { return m_mode; }
- MapData map(QVideoFrame::MapMode mode);
- void unmap();
-
- virtual quint64 textureHandle(int plane) const;
-
-private:
- AVFVideoSinkInterface *sink = nullptr;
-
- mutable CVMetalTextureRef cvMetalTexture[3] = {};
-
-#if defined(Q_OS_MACOS)
- mutable CVOpenGLTextureRef cvOpenGLTexture = nullptr;
-#elif defined(Q_OS_IOS)
- mutable CVOpenGLESTextureRef cvOpenGLESTexture = nullptr;
-#endif
-
- CVImageBufferRef m_buffer = nullptr;
- QVideoFrame::MapMode m_mode = QVideoFrame::NotMapped;
- QVideoFrameFormat::PixelFormat m_pixelFormat = QVideoFrameFormat::Format_Invalid;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/avfvideosink.mm b/src/multimedia/platform/darwin/avfvideosink.mm
deleted file mode 100644
index ac4367140..000000000
--- a/src/multimedia/platform/darwin/avfvideosink.mm
+++ /dev/null
@@ -1,212 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfvideosink_p.h"
-
-#include <private/qrhi_p.h>
-#include <private/qrhimetal_p.h>
-#include <private/qrhigles2_p.h>
-#include <QtGui/qopenglcontext.h>
-
-#include <AVFoundation/AVFoundation.h>
-#import <QuartzCore/CATransaction.h>
-
-#if QT_HAS_INCLUDE(<AppKit/AppKit.h>)
-#include <AppKit/AppKit.h>
-#endif
-
-#if QT_HAS_INCLUDE(<UIKit/UIKit.h>)
-#include <UIKit/UIKit.h>
-#endif
-
-QT_USE_NAMESPACE
-
-AVFVideoSink::AVFVideoSink(QVideoSink *parent)
- : QPlatformVideoSink(parent)
-{
-}
-
-AVFVideoSink::~AVFVideoSink()
-{
-}
-
-void AVFVideoSink::setRhi(QRhi *rhi)
-{
- if (m_rhi == rhi)
- return;
- m_rhi = rhi;
- if (m_interface)
- m_interface->setRhi(rhi);
-}
-
-void AVFVideoSink::setNativeSize(QSize size)
-{
- if (size == nativeSize())
- return;
- QPlatformVideoSink::setNativeSize(size);
- if (m_interface)
- m_interface->nativeSizeChanged();
-}
-
-void AVFVideoSink::setVideoSinkInterface(AVFVideoSinkInterface *interface)
-{
- m_interface = interface;
- if (m_interface)
- m_interface->setRhi(m_rhi);
-}
-
-AVFVideoSinkInterface::~AVFVideoSinkInterface()
-{
- if (m_layer)
- [m_layer release];
- freeTextureCaches();
-}
-
-void AVFVideoSinkInterface::freeTextureCaches()
-{
- if (cvMetalTextureCache)
- CFRelease(cvMetalTextureCache);
- cvMetalTextureCache = nullptr;
-#if defined(Q_OS_MACOS)
- if (cvOpenGLTextureCache)
- CFRelease(cvOpenGLTextureCache);
- cvOpenGLTextureCache = nullptr;
-#elif defined(Q_OS_IOS)
- if (cvOpenGLESTextureCache)
- CFRelease(cvOpenGLESTextureCache);
- cvOpenGLESTextureCache = nullptr;
-#endif
-}
-
-void AVFVideoSinkInterface::setVideoSink(AVFVideoSink *sink)
-{
- if (sink == m_sink)
- return;
-
- m_sink = sink;
- if (m_sink) {
- m_sink->setVideoSinkInterface(this);
- reconfigure();
- }
-}
-
-void AVFVideoSinkInterface::setRhi(QRhi *rhi)
-{
- if (m_rhi == rhi)
- return;
- freeTextureCaches();
- m_rhi = rhi;
-
- if (!rhi)
- return;
- if (rhi->backend() == QRhi::Metal) {
- const auto *metal = static_cast<const QRhiMetalNativeHandles *>(rhi->nativeHandles());
-
- // Create a Metal Core Video texture cache from the pixel buffer.
- Q_ASSERT(!cvMetalTextureCache);
- if (CVMetalTextureCacheCreate(
- kCFAllocatorDefault,
- nil,
- (id<MTLDevice>)metal->dev,
- nil,
- &cvMetalTextureCache) != kCVReturnSuccess) {
- qWarning() << "Metal texture cache creation failed";
- m_rhi = nullptr;
- }
- } else if (rhi->backend() == QRhi::OpenGLES2) {
-#ifdef Q_OS_MACOS
- const auto *gl = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
-
- auto nsGLContext = gl->context->nativeInterface<QNativeInterface::QCocoaGLContext>()->nativeContext();
- auto nsGLPixelFormat = nsGLContext.pixelFormat.CGLPixelFormatObj;
-
- // Create an OpenGL CoreVideo texture cache from the pixel buffer.
- if (CVOpenGLTextureCacheCreate(
- kCFAllocatorDefault,
- nullptr,
- reinterpret_cast<CGLContextObj>(nsGLContext.CGLContextObj),
- nsGLPixelFormat,
- nil,
- &cvOpenGLTextureCache)) {
- qWarning() << "OpenGL texture cache creation failed";
- m_rhi = nullptr;
- }
-#endif
-#ifdef Q_OS_IOS
- // Create an OpenGL CoreVideo texture cache from the pixel buffer.
- if (CVOpenGLESTextureCacheCreate(
- kCFAllocatorDefault,
- nullptr,
- [EAGLContext currentContext],
- nullptr,
- &cvOpenGLESTextureCache)) {
- qWarning() << "OpenGL texture cache creation failed";
- m_rhi = nullptr;
- }
-#endif
- }
-}
-
-void AVFVideoSinkInterface::setLayer(CALayer *layer)
-{
- if (layer == m_layer)
- return;
-
- if (m_layer)
- [m_layer release];
-
- m_layer = layer;
- if (m_layer)
- [m_layer retain];
-
- reconfigure();
-}
-
-void AVFVideoSinkInterface::updateLayerBounds()
-{
- if (!m_layer)
- return;
- [CATransaction begin];
- [CATransaction setDisableActions: YES]; // disable animation/flicks
- m_layer.frame = QRectF(0, 0, nativeSize().width(), nativeSize().height()).toCGRect();
- m_layer.bounds = m_layer.frame;
- [CATransaction commit];
-}
-
-#include "moc_avfvideosink_p.cpp"
diff --git a/src/multimedia/platform/darwin/avfvideosink_p.h b/src/multimedia/platform/darwin/avfvideosink_p.h
deleted file mode 100644
index d25efdfc7..000000000
--- a/src/multimedia/platform/darwin/avfvideosink_p.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFVIDEOWINDOWCONTROL_H
-#define AVFVIDEOWINDOWCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "private/qplatformvideosink_p.h"
-
-Q_FORWARD_DECLARE_OBJC_CLASS(CALayer);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVPlayerLayer);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureVideoPreviewLayer);
-
-#include <CoreVideo/CVBase.h>
-#include <CoreVideo/CVPixelBuffer.h>
-#include <CoreVideo/CVImageBuffer.h>
-
-#import "Metal/Metal.h"
-#import "MetalKit/MetalKit.h"
-
-QT_BEGIN_NAMESPACE
-
-class AVFVideoSinkInterface;
-
-class AVFVideoSink : public QPlatformVideoSink
-{
- Q_OBJECT
-
-public:
- AVFVideoSink(QVideoSink *parent = nullptr);
- virtual ~AVFVideoSink();
-
- // QPlatformVideoSink interface
-public:
- void setRhi(QRhi *rhi) override;
-
- void setNativeSize(QSize size);
-
- void setVideoSinkInterface(AVFVideoSinkInterface *interface);
-
-private:
- AVFVideoSinkInterface *m_interface = nullptr;
- QRhi *m_rhi = nullptr;
-};
-
-class AVFVideoSinkInterface
-{
-public:
- ~AVFVideoSinkInterface();
-
- void setVideoSink(AVFVideoSink *sink);
-
-
- virtual void reconfigure() = 0;
- virtual void setRhi(QRhi *);
- QRhi *rhi() const { return m_rhi; }
-
- virtual void setLayer(CALayer *layer);
-
- void updateLayerBounds();
- void nativeSizeChanged() { updateLayerBounds(); }
- QSize nativeSize() const { return m_sink->nativeSize(); }
-
- CVMetalTextureCacheRef cvMetalTextureCache = nullptr;
-#if defined(Q_OS_MACOS)
- CVOpenGLTextureCacheRef cvOpenGLTextureCache = nullptr;
-#elif defined(Q_OS_IOS)
- CVOpenGLESTextureCacheRef cvOpenGLESTextureCache = nullptr;
-#endif
-private:
- void freeTextureCaches();
-
-protected:
-
- AVFVideoSink *m_sink = nullptr;
- QRhi *m_rhi = nullptr;
- CALayer *m_layer = nullptr;
-};
-
-
-QT_END_NAMESPACE
-
-#endif // AVFVIDEOWINDOWCONTROL_H
diff --git a/src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate.mm b/src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate.mm
deleted file mode 100644
index 27261b8a0..000000000
--- a/src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate.mm
+++ /dev/null
@@ -1,134 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfcamerasession_p.h"
-#include "avfaudiopreviewdelegate_p.h"
-
-QT_USE_NAMESPACE
-
-@implementation AVFAudioPreviewDelegate
-{
-@private
- AVSampleBufferAudioRenderer *m_audioRenderer;
- AVFCameraSession *m_session;
- AVSampleBufferRenderSynchronizer *m_audioBufferSynchronizer;
- dispatch_queue_t m_audioPreviewQueue;
-}
-
-- (id)init
-{
- if (self = [super init]) {
- m_session = nil;
- m_audioBufferSynchronizer = [[AVSampleBufferRenderSynchronizer alloc] init];
- m_audioRenderer = [[AVSampleBufferAudioRenderer alloc] init];
- [m_audioBufferSynchronizer addRenderer:m_audioRenderer];
- return self;
- }
- return nil;
-}
-
-- (void)captureOutput:(AVCaptureOutput *)captureOutput
- didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
- fromConnection:(AVCaptureConnection *)connection
-{
- Q_UNUSED(connection);
- Q_ASSERT(m_session);
-
- if (!CMSampleBufferDataIsReady(sampleBuffer)) {
- qWarning() << Q_FUNC_INFO << "sample buffer is not ready, skipping.";
- return;
- }
-
- CFRetain(sampleBuffer);
-
- dispatch_async(m_audioPreviewQueue, ^{
- [self renderAudioSampleBuffer:sampleBuffer];
- CFRelease(sampleBuffer);
- });
-}
-
-- (void)renderAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer
-{
- Q_ASSERT(sampleBuffer);
- Q_ASSERT(m_session);
-
- if (m_audioBufferSynchronizer && m_audioRenderer) {
- [m_audioRenderer enqueueSampleBuffer:sampleBuffer];
- if (m_audioBufferSynchronizer.rate == 0)
- [m_audioBufferSynchronizer setRate:1 time:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
- }
-}
-
-- (void)resetAudioPreviewDelegate
-{
- [m_session->audioOutput() setSampleBufferDelegate:self queue:m_audioPreviewQueue];
-}
-
-- (void)setupWithCaptureSession: (AVFCameraSession*)session
- audioOutputDevice: (NSString*)deviceId
-{
- m_session = session;
-
- m_audioPreviewQueue = dispatch_queue_create("audio-preview-queue", nullptr);
- [m_session->audioOutput() setSampleBufferDelegate:self queue:m_audioPreviewQueue];
-#ifdef Q_OS_MACOS
- m_audioRenderer.audioOutputDeviceUniqueID = deviceId;
-#endif
-}
-
-- (void)setVolume: (float)volume
-{
- m_audioRenderer.volume = volume;
-}
-
-- (void)setMuted: (bool)muted
-{
- m_audioRenderer.muted = muted;
-}
-
--(void)dealloc {
- m_session = nil;
- [m_audioRenderer release];
- [m_audioBufferSynchronizer release];
- dispatch_release(m_audioPreviewQueue);
-
- [super dealloc];
-}
-
-@end
diff --git a/src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate_p.h b/src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate_p.h
deleted file mode 100644
index e993637dd..000000000
--- a/src/multimedia/platform/darwin/camera/avfaudiopreviewdelegate_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFAUDIOPREVIEWDELEGATE_P_H
-#define AVFAUDIOPREVIEWDELEGATE_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/qglobal.h>
-
-#include <AVFoundation/AVFoundation.h>
-
-QT_BEGIN_NAMESPACE
-
-class AVFCameraSession;
-
-QT_END_NAMESPACE
-
-@interface AVFAudioPreviewDelegate : NSObject<AVCaptureAudioDataOutputSampleBufferDelegate>
-
-- (id)init;
-- (void)setupWithCaptureSession: (AVFCameraSession*)session
- audioOutputDevice: (NSString*)deviceId;
-- (void)renderAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer;
-- (void)resetAudioPreviewDelegate;
-- (void)setVolume: (float)volume;
-- (void)setMuted: (bool)muted;
-
-@end
-
-#endif // AVFAUDIOPREVIEWDELEGATE_P_H
diff --git a/src/multimedia/platform/darwin/camera/avfcamera.mm b/src/multimedia/platform/darwin/camera/avfcamera.mm
deleted file mode 100644
index ede3c49eb..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamera.mm
+++ /dev/null
@@ -1,1004 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfcameradebug_p.h"
-#include "avfcamera_p.h"
-#include "avfcamerasession_p.h"
-#include "avfcameraservice_p.h"
-#include "avfcamerautility_p.h"
-#include "avfcamerarenderer_p.h"
-#include <qmediacapturesession.h>
-
-QT_USE_NAMESPACE
-
-
-namespace {
-
-// All these methods to work with exposure/ISO/SS in custom mode do not support macOS.
-
-#ifdef Q_OS_IOS
-
-// Misc. helpers to check values/ranges:
-
-bool qt_check_ISO_conversion(float isoValue)
-{
- if (isoValue >= std::numeric_limits<int>::max())
- return false;
- if (isoValue <= std::numeric_limits<int>::min())
- return false;
- return true;
-}
-
-bool qt_check_ISO_range(AVCaptureDeviceFormat *format)
-{
- // Qt is using int for ISO, AVFoundation - float. It looks like the ISO range
- // at the moment can be represented by int (it's max - min > 100, etc.).
- Q_ASSERT(format);
- if (format.maxISO - format.minISO < 1.) {
- // ISO is in some strange units?
- return false;
- }
-
- return qt_check_ISO_conversion(format.minISO)
- && qt_check_ISO_conversion(format.maxISO);
-}
-
-bool qt_check_exposure_duration(AVCaptureDevice *captureDevice, CMTime duration)
-{
- Q_ASSERT(captureDevice);
-
- AVCaptureDeviceFormat *activeFormat = captureDevice.activeFormat;
- if (!activeFormat) {
- qDebugCamera() << Q_FUNC_INFO << "failed to obtain capture device format";
- return false;
- }
-
- return CMTimeCompare(duration, activeFormat.minExposureDuration) != -1
- && CMTimeCompare(activeFormat.maxExposureDuration, duration) != -1;
-}
-
-bool qt_check_ISO_value(AVCaptureDevice *captureDevice, int newISO)
-{
- Q_ASSERT(captureDevice);
-
- AVCaptureDeviceFormat *activeFormat = captureDevice.activeFormat;
- if (!activeFormat) {
- qDebugCamera() << Q_FUNC_INFO << "failed to obtain capture device format";
- return false;
- }
-
- return !(newISO < activeFormat.minISO || newISO > activeFormat.maxISO);
-}
-
-bool qt_exposure_duration_equal(AVCaptureDevice *captureDevice, qreal qDuration)
-{
- Q_ASSERT(captureDevice);
- const CMTime avDuration = CMTimeMakeWithSeconds(qDuration, captureDevice.exposureDuration.timescale);
- return !CMTimeCompare(avDuration, captureDevice.exposureDuration);
-}
-
-bool qt_iso_equal(AVCaptureDevice *captureDevice, int iso)
-{
- Q_ASSERT(captureDevice);
- return qFuzzyCompare(float(iso), captureDevice.ISO);
-}
-
-bool qt_exposure_bias_equal(AVCaptureDevice *captureDevice, qreal bias)
-{
- Q_ASSERT(captureDevice);
- return qFuzzyCompare(bias, qreal(captureDevice.exposureTargetBias));
-}
-
-// Converters:
-
-bool qt_convert_exposure_mode(AVCaptureDevice *captureDevice, QCamera::ExposureMode mode,
- AVCaptureExposureMode &avMode)
-{
- // Test if mode supported and convert.
- Q_ASSERT(captureDevice);
-
- if (mode == QCamera::ExposureAuto) {
- if ([captureDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
- avMode = AVCaptureExposureModeContinuousAutoExposure;
- return true;
- }
- }
-
- if (mode == QCamera::ExposureManual) {
- if ([captureDevice isExposureModeSupported:AVCaptureExposureModeCustom]) {
- avMode = AVCaptureExposureModeCustom;
- return true;
- }
- }
-
- return false;
-}
-
-#endif // defined(Q_OS_IOS)
-
-} // Unnamed namespace.
-
-
-AVFCamera::AVFCamera(QCamera *camera)
- : QPlatformCamera(camera)
-{
- Q_ASSERT(camera);
-}
-
-AVFCamera::~AVFCamera()
-{
-}
-
-bool AVFCamera::isActive() const
-{
- return m_active;
-}
-
-void AVFCamera::setActive(bool active)
-{
- if (m_active == active)
- return;
- if (m_cameraDevice.isNull() && active)
- return;
-
- m_active = active;
- if (m_session)
- m_session->setActive(active);
-
- if (active)
- updateCameraConfiguration();
- Q_EMIT activeChanged(m_active);
-}
-
-void AVFCamera::setCamera(const QCameraDevice &camera)
-{
- if (m_cameraDevice == camera)
- return;
- m_cameraDevice = camera;
- if (m_session)
- m_session->setActiveCamera(camera);
- setCameraFormat({});
-}
-
-bool AVFCamera::setCameraFormat(const QCameraFormat &format)
-{
- if (!format.isNull() && !m_cameraDevice.videoFormats().contains(format))
- return false;
-
- m_cameraFormat = format.isNull() ? findBestCameraFormat(m_cameraDevice) : format;
-
- if (m_session)
- m_session->setCameraFormat(m_cameraFormat);
-
- return true;
-}
-
-void AVFCamera::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- AVFCameraService *captureSession = static_cast<AVFCameraService *>(session);
- if (m_service == captureSession)
- return;
-
- if (m_session) {
- m_session->disconnect(this);
- m_session->setActiveCamera({});
- m_session->setCameraFormat({});
- }
-
- m_service = captureSession;
- if (!m_service) {
- m_session = nullptr;
- return;
- }
-
- m_session = m_service->session();
- Q_ASSERT(m_session);
-
- m_session->setActiveCamera(m_cameraDevice);
- m_session->setCameraFormat(m_cameraFormat);
- m_session->setActive(m_active);
-}
-
-AVCaptureConnection *AVFCamera::videoConnection() const
-{
- if (!m_session || !m_session->videoOutput() || !m_session->videoOutput()->videoDataOutput())
- return nil;
-
- return [m_session->videoOutput()->videoDataOutput() connectionWithMediaType:AVMediaTypeVideo];
-}
-
-AVCaptureDevice *AVFCamera::device() const
-{
- AVCaptureDevice *device = nullptr;
- QByteArray deviceId = m_cameraDevice.id();
- if (!deviceId.isEmpty()) {
- device = [AVCaptureDevice deviceWithUniqueID:
- [NSString stringWithUTF8String:
- deviceId.constData()]];
- }
- return device;
-}
-
-#ifdef Q_OS_IOS
-namespace
-{
-
-bool qt_focus_mode_supported(QCamera::FocusMode mode)
-{
- // Check if QCamera::FocusMode has counterpart in AVFoundation.
-
- // AVFoundation has 'Manual', 'Auto' and 'Continuous',
- // where 'Manual' is actually 'Locked' + writable property 'lensPosition'.
- return mode == QCamera::FocusModeAuto
- || mode == QCamera::FocusModeManual;
-}
-
-AVCaptureFocusMode avf_focus_mode(QCamera::FocusMode requestedMode)
-{
- switch (requestedMode) {
- case QCamera::FocusModeHyperfocal:
- case QCamera::FocusModeInfinity:
- case QCamera::FocusModeManual:
- return AVCaptureFocusModeLocked;
- default:
- return AVCaptureFocusModeContinuousAutoFocus;
- }
-
-}
-
-}
-#endif
-
-void AVFCamera::setFocusMode(QCamera::FocusMode mode)
-{
-#ifdef Q_OS_IOS
- if (focusMode() == mode)
- return;
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice) {
- if (qt_focus_mode_supported(mode)) {
- focusModeChanged(mode);
- } else {
- qDebugCamera() << Q_FUNC_INFO
- << "focus mode not supported";
- }
- return;
- }
-
- if (isFocusModeSupported(mode)) {
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO
- << "failed to lock for configuration";
- return;
- }
-
- captureDevice.focusMode = avf_focus_mode(mode);
- } else {
- qDebugCamera() << Q_FUNC_INFO << "focus mode not supported";
- return;
- }
-
- Q_EMIT focusModeChanged(mode);
-#else
- Q_UNUSED(mode);
-#endif
-}
-
-bool AVFCamera::isFocusModeSupported(QCamera::FocusMode mode) const
-{
-#ifdef Q_OS_IOS
- AVCaptureDevice *captureDevice = device();
- if (captureDevice) {
- AVCaptureFocusMode avMode = avf_focus_mode(mode);
- switch (mode) {
- case QCamera::FocusModeAuto:
- case QCamera::FocusModeHyperfocal:
- case QCamera::FocusModeInfinity:
- case QCamera::FocusModeManual:
- return [captureDevice isFocusModeSupported:avMode];
- case QCamera::FocusModeAutoNear:
- Q_FALLTHROUGH();
- case QCamera::FocusModeAutoFar:
- return captureDevice.autoFocusRangeRestrictionSupported
- && [captureDevice isFocusModeSupported:avMode];
- }
- }
-#endif
- return mode == QCamera::FocusModeAuto; // stupid builtin webcam doesn't do any focus handling, but hey it's usually focused :)
-}
-
-void AVFCamera::setCustomFocusPoint(const QPointF &point)
-{
- if (customFocusPoint() == point)
- return;
-
- if (!QRectF(0.f, 0.f, 1.f, 1.f).contains(point)) {
- // ### release custom focus point, tell the camera to focus where it wants...
- qDebugCamera() << Q_FUNC_INFO << "invalid focus point (out of range)";
- return;
- }
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice)
- return;
-
- if ([captureDevice isFocusPointOfInterestSupported]) {
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
- return;
- }
-
- const CGPoint focusPOI = CGPointMake(point.x(), point.y());
- [captureDevice setFocusPointOfInterest:focusPOI];
- if (focusMode() != QCamera::FocusModeAuto)
- [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];
-
- customFocusPointChanged(point);
- }
-}
-
-void AVFCamera::setFocusDistance(float d)
-{
-#ifdef Q_OS_IOS
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice)
- return;
-
- if (captureDevice.lockingFocusWithCustomLensPositionSupported) {
- qDebugCamera() << Q_FUNC_INFO << "Setting custom focus distance not supported\n";
- return;
- }
-
- {
- AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
- return;
- }
- [captureDevice setFocusModeLockedWithLensPosition:d completionHandler:nil];
- }
- focusDistanceChanged(d);
-#else
- Q_UNUSED(d);
-#endif
-}
-
-void AVFCamera::updateCameraConfiguration()
-{
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice) {
- qDebugCamera() << Q_FUNC_INFO << "capture device is nil in 'active' state";
- return;
- }
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
- return;
- }
-
- if ([captureDevice isFocusPointOfInterestSupported]) {
- auto point = customFocusPoint();
- const CGPoint focusPOI = CGPointMake(point.x(), point.y());
- [captureDevice setFocusPointOfInterest:focusPOI];
- }
-
-#ifdef Q_OS_IOS
- if (focusMode() != QCamera::FocusModeAuto) {
- const AVCaptureFocusMode avMode = avf_focus_mode(focusMode());
- if (captureDevice.focusMode != avMode) {
- if ([captureDevice isFocusModeSupported:avMode]) {
- [captureDevice setFocusMode:avMode];
- } else {
- qDebugCamera() << Q_FUNC_INFO << "focus mode not supported";
- }
- }
- }
-
- if (!captureDevice.activeFormat) {
- qDebugCamera() << Q_FUNC_INFO << "camera state is active, but active format is nil";
- return;
- }
-
- minimumZoomFactorChanged(captureDevice.minAvailableVideoZoomFactor);
- maximumZoomFactorChanged(captureDevice.maxAvailableVideoZoomFactor);
-
- captureDevice.videoZoomFactor = zoomFactor();
-
- CMTime newDuration = AVCaptureExposureDurationCurrent;
- bool setCustomMode = false;
-
- float exposureTime = manualExposureTime();
- if (exposureTime > 0
- && !qt_exposure_duration_equal(captureDevice, exposureTime)) {
- newDuration = CMTimeMakeWithSeconds(exposureTime, captureDevice.exposureDuration.timescale);
- if (!qt_check_exposure_duration(captureDevice, newDuration)) {
- qDebugCamera() << Q_FUNC_INFO << "requested exposure duration is out of range";
- return;
- }
- setCustomMode = true;
- }
-
- float newISO = AVCaptureISOCurrent;
- int iso = manualIsoSensitivity();
- if (iso > 0 && !qt_iso_equal(captureDevice, iso)) {
- newISO = iso;
- if (!qt_check_ISO_value(captureDevice, newISO)) {
- qDebugCamera() << Q_FUNC_INFO << "requested ISO value is out of range";
- return;
- }
- setCustomMode = true;
- }
-
- float bias = exposureCompensation();
- if (bias != 0 && !qt_exposure_bias_equal(captureDevice, bias)) {
- // TODO: mixed fpns.
- if (bias < captureDevice.minExposureTargetBias || bias > captureDevice.maxExposureTargetBias) {
- qDebugCamera() << Q_FUNC_INFO << "exposure compensation value is"
- << "out of range";
- return;
- }
- [captureDevice setExposureTargetBias:bias completionHandler:nil];
- }
-
- // Setting shutter speed (exposure duration) or ISO values
- // also reset exposure mode into Custom. With this settings
- // we ignore any attempts to set exposure mode.
-
- if (setCustomMode) {
- [captureDevice setExposureModeCustomWithDuration:newDuration
- ISO:newISO
- completionHandler:nil];
- return;
- }
-
- QCamera::ExposureMode qtMode = exposureMode();
- AVCaptureExposureMode avMode = AVCaptureExposureModeContinuousAutoExposure;
- if (!qt_convert_exposure_mode(captureDevice, qtMode, avMode)) {
- qDebugCamera() << Q_FUNC_INFO << "requested exposure mode is not supported";
- return;
- }
-
- captureDevice.exposureMode = avMode;
-#endif
-
- isFlashSupported = isFlashAutoSupported = false;
- isTorchSupported = isTorchAutoSupported = false;
-
- if (captureDevice.hasFlash) {
- if ([captureDevice isFlashModeSupported:AVCaptureFlashModeOn])
- isFlashSupported = true;
- if ([captureDevice isFlashModeSupported:AVCaptureFlashModeAuto])
- isFlashAutoSupported = true;
- }
-
- if (captureDevice.hasTorch) {
- if ([captureDevice isTorchModeSupported:AVCaptureTorchModeOn])
- isTorchSupported = true;
- if ([captureDevice isTorchModeSupported:AVCaptureTorchModeAuto])
- isTorchAutoSupported = true;
- }
-
- applyFlashSettings();
- flashReadyChanged(isFlashSupported);
-}
-
-void AVFCamera::updateCameraProperties()
-{
- QCamera::Features features;
- AVCaptureDevice *captureDevice = device();
-
-#ifdef Q_OS_IOS
- features = QCamera::Feature::ColorTemperature | QCamera::Feature::ExposureCompensation |
- QCamera::Feature::IsoSensitivity | QCamera::Feature::ManualExposureTime;
-
- if (captureDevice && [captureDevice isLockingFocusWithCustomLensPositionSupported])
- features |= QCamera::Feature::FocusDistance;
-#endif
-
- if (captureDevice && [captureDevice isFocusPointOfInterestSupported])
- features |= QCamera::Feature::CustomFocusPoint;
-
- supportedFeaturesChanged(features);
-}
-
-void AVFCamera::zoomTo(float factor, float rate)
-{
- Q_UNUSED(factor);
- Q_UNUSED(rate);
-
-#ifdef Q_OS_IOS
- if (zoomFactor() == factor)
- return;
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice || !captureDevice.activeFormat)
- return;
-
- factor = qBound(captureDevice.minAvailableVideoZoomFactor, factor, captureDevice.maxAvailableVideoZoomFactor);
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
- return;
- }
-
- if (rate < 0)
- captureDevice.videoZoomFactor = factor;
- else
- [AVCaptureDevice rampToVideoZoomFactor:factor withRate:rate];
-#endif
-}
-
-void AVFCamera::setFlashMode(QCamera::FlashMode mode)
-{
- if (flashMode() == mode)
- return;
-
- if (isActive() && !isFlashModeSupported(mode)) {
- qDebugCamera() << Q_FUNC_INFO << "unsupported mode" << mode;
- return;
- }
-
- flashModeChanged(mode);
-
- if (!isActive())
- return;
-
- applyFlashSettings();
-}
-
-bool AVFCamera::isFlashModeSupported(QCamera::FlashMode mode) const
-{
- if (mode == QCamera::FlashOff)
- return true;
- else if (mode == QCamera::FlashOn)
- return isFlashSupported;
- else //if (mode == QCamera::FlashAuto)
- return isFlashAutoSupported;
-}
-
-bool AVFCamera::isFlashReady() const
-{
- if (!isActive())
- return false;
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice)
- return false;
-
- if (!captureDevice.hasFlash)
- return false;
-
- if (!isFlashModeSupported(flashMode()))
- return false;
-
-#ifdef Q_OS_IOS
- // AVCaptureDevice's docs:
- // "The flash may become unavailable if, for example,
- // the device overheats and needs to cool off."
- return [captureDevice isFlashAvailable];
-#endif
-
- return true;
-}
-
-void AVFCamera::setTorchMode(QCamera::TorchMode mode)
-{
- if (torchMode() == mode)
- return;
-
- if (isActive() && !isTorchModeSupported(mode)) {
- qDebugCamera() << Q_FUNC_INFO << "unsupported torch mode" << mode;
- return;
- }
-
- torchModeChanged(mode);
-
- if (!isActive())
- return;
-
- applyFlashSettings();
-}
-
-bool AVFCamera::isTorchModeSupported(QCamera::TorchMode mode) const
-{
- if (mode == QCamera::TorchOff)
- return true;
- else if (mode == QCamera::TorchOn)
- return isTorchSupported;
- else //if (mode == QCamera::TorchAuto)
- return isTorchAutoSupported;
-}
-
-void AVFCamera::setExposureMode(QCamera::ExposureMode qtMode)
-{
-#ifdef Q_OS_IOS
- if (qtMode != QCamera::ExposureAuto && qtMode != QCamera::ExposureManual) {
- qDebugCamera() << Q_FUNC_INFO << "exposure mode not supported";
- return;
- }
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice) {
- exposureModeChanged(qtMode);
- return;
- }
-
- AVCaptureExposureMode avMode = AVCaptureExposureModeContinuousAutoExposure;
- if (!qt_convert_exposure_mode(captureDevice, qtMode, avMode)) {
- qDebugCamera() << Q_FUNC_INFO << "exposure mode not supported";
- return;
- }
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock a capture device"
- << "for configuration";
- return;
- }
-
- [captureDevice setExposureMode:avMode];
- exposureModeChanged(qtMode);
-#else
- Q_UNUSED(qtMode);
-#endif
-}
-
-bool AVFCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
-{
- if (mode == QCamera::ExposureAuto)
- return true;
- if (mode != QCamera::ExposureManual)
- return false;
-
- if (@available(macOS 10.15, *)) {
- AVCaptureDevice *captureDevice = device();
- return captureDevice && [captureDevice isExposureModeSupported:AVCaptureExposureModeCustom];
- }
-
- return false;
-}
-
-void AVFCamera::applyFlashSettings()
-{
- Q_ASSERT(isActive());
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice) {
- qDebugCamera() << Q_FUNC_INFO << "no capture device found";
- return;
- }
-
-
- const AVFConfigurationLock lock(captureDevice);
-
- if (captureDevice.hasFlash) {
- auto mode = flashMode();
- if (mode == QCamera::FlashOff) {
- captureDevice.flashMode = AVCaptureFlashModeOff;
- } else {
-#ifdef Q_OS_IOS
- if (![captureDevice isFlashAvailable]) {
- qDebugCamera() << Q_FUNC_INFO << "flash is not available at the moment";
- return;
- }
-#endif
- if (mode == QCamera::FlashOn)
- captureDevice.flashMode = AVCaptureFlashModeOn;
- else if (mode == QCamera::FlashAuto)
- captureDevice.flashMode = AVCaptureFlashModeAuto;
- }
- }
-
- if (captureDevice.hasTorch) {
- auto mode = torchMode();
- if (mode == QCamera::TorchOff) {
- captureDevice.torchMode = AVCaptureTorchModeOff;
- } else {
-#ifdef Q_OS_IOS
- if (![captureDevice isTorchAvailable]) {
- qDebugCamera() << Q_FUNC_INFO << "torch is not available at the moment";
- return;
- }
-#endif
- if (mode == QCamera::TorchOn)
- captureDevice.torchMode = AVCaptureTorchModeOn;
- else if (mode == QCamera::TorchAuto)
- captureDevice.torchMode = AVCaptureTorchModeAuto;
- }
- }
-}
-
-
-void AVFCamera::setExposureCompensation(float bias)
-{
-#ifdef Q_OS_IOS
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice) {
- exposureCompensationChanged(bias);
- return;
- }
-
- bias = qBound(captureDevice.minExposureTargetBias, bias, captureDevice.maxExposureTargetBias);
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
- return;
- }
-
- [captureDevice setExposureTargetBias:bias completionHandler:nil];
- exposureCompensationChanged(bias);
-#else
- Q_UNUSED(bias);
-#endif
-}
-
-void AVFCamera::setManualExposureTime(float value)
-{
-#ifdef Q_OS_IOS
- if (value < 0) {
- setExposureMode(QCamera::ExposureAuto);
- return;
- }
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice) {
- exposureTimeChanged(value);
- return;
- }
-
- const CMTime newDuration = CMTimeMakeWithSeconds(value, captureDevice.exposureDuration.timescale);
- if (!qt_check_exposure_duration(captureDevice, newDuration)) {
- qDebugCamera() << Q_FUNC_INFO << "shutter speed value is out of range";
- return;
- }
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
- return;
- }
-
- // Setting the shutter speed (exposure duration in Apple's terms,
- // since there is no shutter actually) will also reset
- // exposure mode into custom mode.
- [captureDevice setExposureModeCustomWithDuration:newDuration
- ISO:AVCaptureISOCurrent
- completionHandler:nil];
-
- exposureTimeChanged(value);
-
-#else
- Q_UNUSED(value);
-#endif
-}
-
-float AVFCamera::exposureTime() const
-{
-#ifdef Q_OS_IOS
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice)
- return -1.;
- auto duration = captureDevice.exposureDuration;
- return CMTimeGetSeconds(duration);
-#else
- return -1;
-#endif
-}
-
-#ifdef Q_OS_IOS
-namespace {
-
-void avf_convert_white_balance_mode(QCamera::WhiteBalanceMode qtMode,
- AVCaptureWhiteBalanceMode &avMode)
-{
- if (qtMode == QCamera::WhiteBalanceAuto)
- avMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance;
- else
- avMode = AVCaptureWhiteBalanceModeLocked;
-}
-
-bool avf_set_white_balance_mode(AVCaptureDevice *captureDevice,
- AVCaptureWhiteBalanceMode avMode)
-{
- Q_ASSERT(captureDevice);
-
- const bool lock = [captureDevice lockForConfiguration:nil];
- if (!lock) {
- qDebug() << "Failed to lock a capture device for configuration\n";
- return false;
- }
-
- captureDevice.whiteBalanceMode = avMode;
- [captureDevice unlockForConfiguration];
- return true;
-}
-
-bool avf_convert_temp_and_tint_to_wb_gains(AVCaptureDevice *captureDevice,
- float temp, float tint, AVCaptureWhiteBalanceGains &wbGains)
-{
- Q_ASSERT(captureDevice);
-
- AVCaptureWhiteBalanceTemperatureAndTintValues wbTTValues = {
- .temperature = temp,
- .tint = tint
- };
- wbGains = [captureDevice deviceWhiteBalanceGainsForTemperatureAndTintValues:wbTTValues];
-
- if (wbGains.redGain >= 1.0 && wbGains.redGain <= captureDevice.maxWhiteBalanceGain
- && wbGains.greenGain >= 1.0 && wbGains.greenGain <= captureDevice.maxWhiteBalanceGain
- && wbGains.blueGain >= 1.0 && wbGains.blueGain <= captureDevice.maxWhiteBalanceGain)
- return true;
-
- return false;
-}
-
-bool avf_set_white_balance_gains(AVCaptureDevice *captureDevice,
- AVCaptureWhiteBalanceGains wbGains)
-{
- const bool lock = [captureDevice lockForConfiguration:nil];
- if (!lock) {
- qDebug() << "Failed to lock a capture device for configuration\n";
- return false;
- }
-
- [captureDevice setWhiteBalanceModeLockedWithDeviceWhiteBalanceGains:wbGains
- completionHandler:nil];
- [captureDevice unlockForConfiguration];
- return true;
-}
-
-}
-
-bool AVFCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
-{
- if (mode == QCamera::WhiteBalanceAuto)
- return true;
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice)
- return false;
- return [captureDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeLocked];
-}
-
-void AVFCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
-{
- if (!isWhiteBalanceModeSupported(mode))
- return;
-
- AVCaptureDevice *captureDevice = device();
- Q_ASSERT(captureDevice);
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock a capture device"
- << "for configuration";
- return;
- }
-
- AVCaptureWhiteBalanceMode avMode;
- avf_convert_white_balance_mode(mode, avMode);
- avf_set_white_balance_mode(captureDevice, avMode);
-
- if (mode == QCamera::WhiteBalanceAuto || mode == QCamera::WhiteBalanceManual) {
- whiteBalanceModeChanged(mode);
- return;
- }
-
- const int colorTemp = colorTemperatureForWhiteBalance(mode);
- AVCaptureWhiteBalanceGains wbGains;
- if (avf_convert_temp_and_tint_to_wb_gains(captureDevice, colorTemp, 0., wbGains)
- && avf_set_white_balance_gains(captureDevice, wbGains))
- whiteBalanceModeChanged(mode);
-}
-
-void AVFCamera::setColorTemperature(int colorTemp)
-{
- if (colorTemp == 0) {
- colorTemperatureChanged(colorTemp);
- return;
- }
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice || ![captureDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeLocked])
- return;
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock a capture device"
- << "for configuration";
- return;
- }
-
- AVCaptureWhiteBalanceGains wbGains;
- if (avf_convert_temp_and_tint_to_wb_gains(captureDevice, colorTemp, 0., wbGains)
- && avf_set_white_balance_gains(captureDevice, wbGains))
- colorTemperatureChanged(colorTemp);
-}
-#endif
-
-void AVFCamera::setManualIsoSensitivity(int value)
-{
-#ifdef Q_OS_IOS
- if (value < 0) {
- setExposureMode(QCamera::ExposureAuto);
- return;
- }
-
- AVCaptureDevice *captureDevice = device();
- if (!captureDevice) {
- isoSensitivityChanged(value);
- return;
- }
-
- if (!qt_check_ISO_value(captureDevice, value)) {
- qDebugCamera() << Q_FUNC_INFO << "ISO value is out of range";
- return;
- }
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock a capture device"
- << "for configuration";
- return;
- }
-
- // Setting the ISO will also reset
- // exposure mode to the custom mode.
- [captureDevice setExposureModeCustomWithDuration:AVCaptureExposureDurationCurrent
- ISO:value
- completionHandler:nil];
-
- isoSensitivityChanged(value);
-#else
- Q_UNUSED(value);
-#endif
-}
-
-int AVFCamera::isoSensitivity() const
-{
- return manualIsoSensitivity();
-}
-
-
-#include "moc_avfcamera_p.cpp"
diff --git a/src/multimedia/platform/darwin/camera/avfcamera_p.h b/src/multimedia/platform/darwin/camera/avfcamera_p.h
deleted file mode 100644
index 950d0131b..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamera_p.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFCAMERA_H
-#define AVFCAMERA_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/qobject.h>
-
-#include <private/qplatformcamera_p.h>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureDeviceFormat);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureConnection);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureDevice);
-
-QT_BEGIN_NAMESPACE
-
-class AVFCameraSession;
-class AVFCameraService;
-class AVFCameraSession;
-
-class AVFCamera : public QPlatformCamera
-{
-Q_OBJECT
-public:
- AVFCamera(QCamera *camera);
- ~AVFCamera();
-
- bool isActive() const override;
- void setActive(bool activce) override;
-
- void setCamera(const QCameraDevice &camera) override;
- bool setCameraFormat(const QCameraFormat &format) override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *) override;
-
- void setFocusMode(QCamera::FocusMode mode) override;
- bool isFocusModeSupported(QCamera::FocusMode mode) const override;
-
- void setCustomFocusPoint(const QPointF &point) override;
-
- void setFocusDistance(float d) override;
- void zoomTo(float factor, float rate) override;
-
- void setFlashMode(QCamera::FlashMode mode) override;
- bool isFlashModeSupported(QCamera::FlashMode mode) const override;
- bool isFlashReady() const override;
-
- void setTorchMode(QCamera::TorchMode mode) override;
- bool isTorchModeSupported(QCamera::TorchMode mode) const override;
-
- void setExposureMode(QCamera::ExposureMode) override;
- bool isExposureModeSupported(QCamera::ExposureMode mode) const override;
-
- void setExposureCompensation(float bias) override;
- void setManualIsoSensitivity(int value) override;
- virtual int isoSensitivity() const override;
- void setManualExposureTime(float value) override;
- virtual float exposureTime() const override;
-
-#ifdef Q_OS_IOS
- // not supported on macOS
- bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override;
- void setWhiteBalanceMode(QCamera::WhiteBalanceMode /*mode*/) override;
- void setColorTemperature(int /*temperature*/) override;
-#endif
-
- AVCaptureConnection *videoConnection() const;
- AVCaptureDevice *device() const;
-
-private:
- void updateCameraConfiguration();
- void updateCameraProperties();
- void applyFlashSettings();
-
- friend class AVFCameraSession;
- AVFCameraService *m_service = nullptr;
- AVFCameraSession *m_session = nullptr;
-
- QCameraDevice m_cameraDevice;
- QCameraFormat m_cameraFormat;
-
- bool m_active = false;
-
- bool isFlashSupported = false;
- bool isFlashAutoSupported = false;
- bool isTorchSupported = false;
- bool isTorchAutoSupported = false;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/camera/avfcameradebug_p.h b/src/multimedia/platform/darwin/camera/avfcameradebug_p.h
deleted file mode 100644
index 616e53d99..000000000
--- a/src/multimedia/platform/darwin/camera/avfcameradebug_p.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFDEBUG_H
-#define AVFDEBUG_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 "qtmultimediaglobal.h"
-
-#include <QtCore/qdebug.h>
-
-QT_USE_NAMESPACE
-
-//#define AVF_DEBUG_CAMERA
-
-#ifdef AVF_DEBUG_CAMERA
-#define qDebugCamera qDebug
-#else
-#define qDebugCamera QT_NO_QDEBUG_MACRO
-#endif
-
-#endif
diff --git a/src/multimedia/platform/darwin/camera/avfcamerarenderer.mm b/src/multimedia/platform/darwin/camera/avfcamerarenderer.mm
deleted file mode 100644
index 016ee3333..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamerarenderer.mm
+++ /dev/null
@@ -1,298 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qabstractvideobuffer_p.h"
-#include "avfcamerarenderer_p.h"
-#include "avfcamerasession_p.h"
-#include "avfcameraservice_p.h"
-#include "avfcameradebug_p.h"
-#include "avfcamera_p.h"
-#include <private/avfvideosink_p.h>
-#include <private/avfvideobuffer_p.h>
-#include "qvideosink.h"
-
-#import <AVFoundation/AVFoundation.h>
-
-#ifdef Q_OS_IOS
-#include <QtGui/qopengl.h>
-#endif
-
-#include <private/qabstractvideobuffer_p.h>
-
-#include <QtMultimedia/qvideoframeformat.h>
-
-QT_USE_NAMESPACE
-
-@interface AVFCaptureFramesDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
-
-- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFCameraRenderer*)renderer;
-
-- (void) captureOutput:(AVCaptureOutput *)captureOutput
- didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
- fromConnection:(AVCaptureConnection *)connection;
-
-@end
-
-@implementation AVFCaptureFramesDelegate
-{
-@private
- AVFCameraRenderer *m_renderer;
-}
-
-- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFCameraRenderer*)renderer
-{
- if (!(self = [super init]))
- return nil;
-
- self->m_renderer = renderer;
- return self;
-}
-
-- (void)captureOutput:(AVCaptureOutput *)captureOutput
- didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
- fromConnection:(AVCaptureConnection *)connection
-{
- Q_UNUSED(connection);
- Q_UNUSED(captureOutput);
-
- // NB: on iOS captureOutput/connection can be nil (when recording a video -
- // avfmediaassetwriter).
-
- CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
-
- int width = CVPixelBufferGetWidth(imageBuffer);
- int height = CVPixelBufferGetHeight(imageBuffer);
- QVideoFrameFormat::PixelFormat format =
- AVFVideoBuffer::fromCVPixelFormat(CVPixelBufferGetPixelFormatType(imageBuffer));
- if (format == QVideoFrameFormat::Format_Invalid)
- return;
-
- QVideoFrame frame(new AVFVideoBuffer(m_renderer, imageBuffer),
- QVideoFrameFormat(QSize(width, height), format));
-
- m_renderer->syncHandleViewfinderFrame(frame);
-}
-
-@end
-
-AVFCameraRenderer::AVFCameraRenderer(QObject *parent)
- : QObject(parent)
-{
- m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this];
- connect(&m_orientationHandler, &QVideoOutputOrientationHandler::orientationChanged,
- this, &AVFCameraRenderer::deviceOrientationChanged);
-}
-
-AVFCameraRenderer::~AVFCameraRenderer()
-{
- [m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
- [m_viewfinderFramesDelegate release];
- if (m_delegateQueue)
- dispatch_release(m_delegateQueue);
-#ifdef Q_OS_IOS
- if (m_textureCache)
- CFRelease(m_textureCache);
-#endif
-}
-
-void AVFCameraRenderer::reconfigure()
-{
- QMutexLocker lock(&m_vfMutex);
-
- // ### This is a hack, need to use a reliable way to determine the size and not use the preview layer
- if (m_layer)
- m_sink->setNativeSize(QSize(m_layer.bounds.size.width, m_layer.bounds.size.height));
- nativeSizeChanged();
- deviceOrientationChanged();
-}
-
-void AVFCameraRenderer::configureAVCaptureSession(AVFCameraSession *cameraSession)
-{
- m_cameraSession = cameraSession;
- connect(m_cameraSession, SIGNAL(readyToConfigureConnections()),
- this, SLOT(updateCaptureConnection()));
-
- m_needsHorizontalMirroring = false;
-
- m_videoDataOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
-
- // Configure video output
- m_delegateQueue = dispatch_queue_create("vf_queue", nullptr);
- [m_videoDataOutput
- setSampleBufferDelegate:m_viewfinderFramesDelegate
- queue:m_delegateQueue];
-
- [m_cameraSession->captureSession() addOutput:m_videoDataOutput];
-}
-
-void AVFCameraRenderer::updateCaptureConnection()
-{
- AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
- if (connection == nil || !m_cameraSession->videoCaptureDevice())
- return;
-
- // Frames of front-facing cameras should be mirrored horizontally (it's the default when using
- // AVCaptureVideoPreviewLayer but not with AVCaptureVideoDataOutput)
- if (connection.isVideoMirroringSupported)
- connection.videoMirrored = m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront;
-
- // If the connection does't support mirroring, we'll have to do it ourselves
- m_needsHorizontalMirroring = !connection.isVideoMirrored
- && m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront;
-
- deviceOrientationChanged();
-}
-
-void AVFCameraRenderer::deviceOrientationChanged(int angle)
-{
- AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
- if (connection == nil || !m_cameraSession->videoCaptureDevice())
- return;
-
- if (!connection.supportsVideoOrientation)
- return;
-
- if (angle < 0)
- angle = m_orientationHandler.currentOrientation();
-
- AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationPortrait;
- switch (angle) {
- default:
- break;
- case 90:
- orientation = AVCaptureVideoOrientationLandscapeRight;
- break;
- case 180:
- // this keeps the last orientation, don't do anything
- return;
- case 270:
- orientation = AVCaptureVideoOrientationLandscapeLeft;
- break;
- }
-
- connection.videoOrientation = orientation;
-}
-
-//can be called from non main thread
-void AVFCameraRenderer::syncHandleViewfinderFrame(const QVideoFrame &frame)
-{
- Q_EMIT newViewfinderFrame(frame);
-
- QMutexLocker lock(&m_vfMutex);
-
- if (!m_lastViewfinderFrame.isValid()) {
- static QMetaMethod handleViewfinderFrameSlot = metaObject()->method(
- metaObject()->indexOfMethod("handleViewfinderFrame()"));
-
- handleViewfinderFrameSlot.invoke(this, Qt::QueuedConnection);
- }
-
- m_lastViewfinderFrame = frame;
-}
-
-AVCaptureVideoDataOutput *AVFCameraRenderer::videoDataOutput() const
-{
- return m_videoDataOutput;
-}
-
-AVFCaptureFramesDelegate *AVFCameraRenderer::captureDelegate() const
-{
- return m_viewfinderFramesDelegate;
-}
-
-void AVFCameraRenderer::resetCaptureDelegate() const
-{
- [m_videoDataOutput setSampleBufferDelegate:m_viewfinderFramesDelegate queue:m_delegateQueue];
-}
-
-void AVFCameraRenderer::handleViewfinderFrame()
-{
- QVideoFrame frame;
- {
- QMutexLocker lock(&m_vfMutex);
- frame = m_lastViewfinderFrame;
- m_lastViewfinderFrame = QVideoFrame();
- }
-
- if (m_sink && frame.isValid()) {
- // ### pass format to surface
- QVideoFrameFormat format = frame.surfaceFormat();
- if (m_needsHorizontalMirroring)
- format.setMirrored(true);
-
- m_sink->setVideoFrame(frame);
- }
-}
-
-void AVFCameraRenderer::setPixelFormat(const QVideoFrameFormat::PixelFormat pixelFormat)
-{
- // Default to 32ARGB/32BGRA pixel formats on the viewfinder, in case the requested
- // format can't be used (shouldn't happen unless the developers sets a wrong camera
- // format on the camera).
- unsigned avPixelFormat = kCVPixelFormatType_32ARGB;
-#ifdef Q_OS_IOS
- avPixelFormat = kCVPixelFormatType_32BGRA;
-#endif
- if (!AVFVideoBuffer::toCVPixelFormat(pixelFormat, avPixelFormat))
- qWarning() << "QCamera::setCameraFormat: couldn't convert requested pixel format, using ARGB32";
- qDebug() << "setPixelFormat" << pixelFormat << Qt::hex << avPixelFormat;
-
- bool isSupported = false;
- NSArray *supportedPixelFormats = m_videoDataOutput.availableVideoCVPixelFormatTypes;
- for (NSNumber *currentPixelFormat in supportedPixelFormats)
- {
- if ([currentPixelFormat unsignedIntValue] == avPixelFormat) {
- isSupported = true;
- break;
- }
- }
-
- if (isSupported) {
- NSDictionary* outputSettings = @{
- (NSString *)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithUnsignedInt:avPixelFormat],
- (NSString *)kCVPixelBufferMetalCompatibilityKey: @true
- };
- m_videoDataOutput.videoSettings = outputSettings;
- } else {
- qWarning() << "QCamera::setCameraFormat: requested pixel format not supported. Did you use a camera format from another camera?";
- }
-}
-
-#include "moc_avfcamerarenderer_p.cpp"
-
diff --git a/src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h b/src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h
deleted file mode 100644
index 9455f593d..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFCAMERARENDERER_H
-#define AVFCAMERARENDERER_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/qobject.h>
-#include <QtMultimedia/qvideoframe.h>
-#include <QtCore/qmutex.h>
-#include <private/avfvideosink_p.h>
-#include <private/qvideooutputorientationhandler_p.h>
-
-#include <CoreVideo/CVBase.h>
-#include <CoreVideo/CVPixelBuffer.h>
-#include <CoreVideo/CVImageBuffer.h>
-#ifdef Q_OS_IOS
-#include <CoreVideo/CVOpenGLESTexture.h>
-#include <CoreVideo/CVOpenGLESTextureCache.h>
-#endif
-
-#include <dispatch/dispatch.h>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(AVFCaptureFramesDelegate);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureVideoDataOutput);
-
-QT_BEGIN_NAMESPACE
-
-class AVFCameraSession;
-class AVFCameraService;
-class AVFCameraRenderer;
-class AVFVideoSink;
-
-class AVFCameraRenderer : public QObject, public AVFVideoSinkInterface
-{
-Q_OBJECT
-public:
- AVFCameraRenderer(QObject *parent = nullptr);
- ~AVFCameraRenderer();
-
- void reconfigure() override;
-
- void configureAVCaptureSession(AVFCameraSession *cameraSession);
- void syncHandleViewfinderFrame(const QVideoFrame &frame);
-
- AVCaptureVideoDataOutput *videoDataOutput() const;
-
- AVFCaptureFramesDelegate *captureDelegate() const;
- void resetCaptureDelegate() const;
-
- void setPixelFormat(const QVideoFrameFormat::PixelFormat format);
-
-Q_SIGNALS:
- void newViewfinderFrame(const QVideoFrame &frame);
-
-private Q_SLOTS:
- void handleViewfinderFrame();
- void updateCaptureConnection();
-public Q_SLOTS:
- void deviceOrientationChanged(int angle = -1);
-
-private:
- AVFCaptureFramesDelegate *m_viewfinderFramesDelegate = nullptr;
- AVFCameraSession *m_cameraSession = nullptr;
- AVCaptureVideoDataOutput *m_videoDataOutput = nullptr;
-
- bool m_needsHorizontalMirroring = false;
-
-#ifdef Q_OS_IOS
- CVOpenGLESTextureCacheRef m_textureCache = nullptr;
-#endif
-
- QVideoFrame m_lastViewfinderFrame;
- QMutex m_vfMutex;
- dispatch_queue_t m_delegateQueue;
- QVideoOutputOrientationHandler m_orientationHandler;
-
- friend class CVImageVideoBuffer;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/camera/avfcameraservice.mm b/src/multimedia/platform/darwin/camera/avfcameraservice.mm
deleted file mode 100644
index 2d37a4117..000000000
--- a/src/multimedia/platform/darwin/camera/avfcameraservice.mm
+++ /dev/null
@@ -1,201 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qvariant.h>
-#include <QtCore/qdebug.h>
-
-#include "avfcameraservice_p.h"
-#include "avfcamera_p.h"
-#include "avfcamerasession_p.h"
-#include "avfimagecapture_p.h"
-#include "avfcamerarenderer_p.h"
-#include "avfimagecapture_p.h"
-#include "avfmediaencoder_p.h"
-#include <qmediadevices.h>
-#include <private/qplatformaudioinput_p.h>
-#include <private/qplatformaudiooutput_p.h>
-#include <qaudioinput.h>
-#include <qaudiooutput.h>
-
-QT_USE_NAMESPACE
-
-AVFCameraService::AVFCameraService()
-{
- m_session = new AVFCameraSession(this);
-}
-
-AVFCameraService::~AVFCameraService()
-{
- if (m_session)
- delete m_session;
-}
-
-QPlatformCamera *AVFCameraService::camera()
-{
- return m_cameraControl;
-}
-
-void AVFCameraService::setCamera(QPlatformCamera *camera)
-{
- AVFCamera *control = static_cast<AVFCamera *>(camera);
- if (m_cameraControl == control)
- return;
-
- if (m_cameraControl)
- m_cameraControl->setCaptureSession(nullptr);
-
- m_cameraControl = control;
- emit cameraChanged();
-
- if (m_cameraControl)
- m_cameraControl->setCaptureSession(this);
-}
-
-QPlatformImageCapture *AVFCameraService::imageCapture()
-{
- return m_imageCaptureControl;
-}
-
-void AVFCameraService::setImageCapture(QPlatformImageCapture *imageCapture)
-{
- AVFImageCapture *control = static_cast<AVFImageCapture *>(imageCapture);
- if (m_imageCaptureControl == control)
- return;
-
- if (m_imageCaptureControl)
- m_imageCaptureControl->setCaptureSession(nullptr);
-
- m_imageCaptureControl = control;
- if (m_imageCaptureControl)
- m_imageCaptureControl->setCaptureSession(this);
-}
-
-QPlatformMediaEncoder *AVFCameraService::mediaEncoder()
-{
- return m_encoder;
-}
-
-void AVFCameraService::setMediaEncoder(QPlatformMediaEncoder *encoder)
-{
- AVFMediaEncoder *control = static_cast<AVFMediaEncoder *>(encoder);
- if (m_encoder == control)
- return;
-
- if (m_encoder)
- m_encoder->setCaptureSession(nullptr);
-
- m_encoder = control;
- if (m_encoder)
- m_encoder->setCaptureSession(this);
-
- emit encoderChanged();
-}
-
-void AVFCameraService::setAudioInput(QPlatformAudioInput *input)
-{
- if (m_audioInput == input)
- return;
- if (m_audioInput)
- m_audioInput->q->disconnect(this);
-
- m_audioInput = input;
-
- if (input) {
- connect(m_audioInput->q, &QAudioInput::destroyed, this, &AVFCameraService::audioInputDestroyed);
- connect(m_audioInput->q, &QAudioInput::deviceChanged, this, &AVFCameraService::audioInputChanged);
- connect(m_audioInput->q, &QAudioInput::mutedChanged, this, &AVFCameraService::setAudioInputMuted);
- connect(m_audioInput->q, &QAudioInput::volumeChanged, this, &AVFCameraService::setAudioInputVolume);
- }
- audioInputChanged();
-}
-
-void AVFCameraService::setAudioOutput(QPlatformAudioOutput *output)
-{
- if (m_audioOutput == output)
- return;
- if (m_audioOutput)
- m_audioOutput->q->disconnect(this);
-
- m_audioOutput = output;
-
- if (m_audioOutput) {
- connect(m_audioOutput->q, &QAudioOutput::destroyed, this, &AVFCameraService::audioOutputDestroyed);
- connect(m_audioOutput->q, &QAudioOutput::deviceChanged, this, &AVFCameraService::audioOutputChanged);
- connect(m_audioOutput->q, &QAudioOutput::mutedChanged, this, &AVFCameraService::setAudioOutputMuted);
- connect(m_audioOutput->q, &QAudioOutput::volumeChanged, this, &AVFCameraService::setAudioOutputVolume);
- }
- audioOutputChanged();
-}
-
-void AVFCameraService::audioInputChanged()
-{
- m_session->updateAudioInput();
-}
-
-void AVFCameraService::audioOutputChanged()
-{
- m_session->updateAudioOutput();
-}
-
-void AVFCameraService::setAudioInputMuted(bool muted)
-{
- m_session->setAudioInputMuted(muted);
-}
-
-void AVFCameraService::setAudioInputVolume(float volume)
-{
- m_session->setAudioInputVolume(volume);
-}
-
-void AVFCameraService::setAudioOutputMuted(bool muted)
-{
- m_session->setAudioOutputMuted(muted);
-}
-
-void AVFCameraService::setAudioOutputVolume(float volume)
-{
- m_session->setAudioOutputVolume(volume);
-}
-
-void AVFCameraService::setVideoPreview(QVideoSink *sink)
-{
- m_session->setVideoSink(sink);
-}
-
-#include "moc_avfcameraservice_p.cpp"
diff --git a/src/multimedia/platform/darwin/camera/avfcameraservice_p.h b/src/multimedia/platform/darwin/camera/avfcameraservice_p.h
deleted file mode 100644
index 462c957b4..000000000
--- a/src/multimedia/platform/darwin/camera/avfcameraservice_p.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFCAMERASERVICE_H
-#define AVFCAMERASERVICE_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/qobject.h>
-#include <QtCore/qset.h>
-#include <private/qplatformmediacapture_p.h>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureDevice);
-
-QT_BEGIN_NAMESPACE
-class QPlatformCamera;
-class QPlatformMediaEncoder;
-class AVFCamera;
-class AVFImageCapture;
-class AVFCameraSession;
-class AVFMediaEncoder;
-
-class AVFCameraService : public QPlatformMediaCaptureSession
-{
- Q_OBJECT
-public:
- AVFCameraService();
- ~AVFCameraService();
-
- QPlatformCamera *camera() override;
- void setCamera(QPlatformCamera *camera) override;
-
- QPlatformImageCapture *imageCapture() override;
- void setImageCapture(QPlatformImageCapture *imageCapture) override;
-
- QPlatformMediaEncoder *mediaEncoder() override;
- void setMediaEncoder(QPlatformMediaEncoder *encoder) override;
-
- void setAudioInput(QPlatformAudioInput *) override;
- void setAudioOutput(QPlatformAudioOutput *) override;
-
- void setVideoPreview(QVideoSink *sink) override;
-
- AVFCameraSession *session() const { return m_session; }
- AVFCamera *avfCameraControl() const { return m_cameraControl; }
- AVFMediaEncoder *recorderControl() const { return m_encoder; }
- AVFImageCapture *avfImageCaptureControl() const { return m_imageCaptureControl; }
-
- QPlatformAudioInput *audioInput() { return m_audioInput; }
- QPlatformAudioOutput *audioOutput() { return m_audioOutput; }
-
-public Q_SLOTS:
- void audioInputDestroyed() { setAudioInput(nullptr); }
- void audioInputChanged();
- void audioOutputDestroyed() { setAudioOutput(nullptr); }
- void audioOutputChanged();
-
- void setAudioInputMuted(bool muted);
- void setAudioInputVolume(float volume);
- void setAudioOutputMuted(bool muted);
- void setAudioOutputVolume(float volume);
-
-private:
- QPlatformAudioInput *m_audioInput = nullptr;
- QPlatformAudioOutput *m_audioOutput = nullptr;
-
- AVFCameraSession *m_session = nullptr;
- AVFCamera *m_cameraControl = nullptr;
- AVFMediaEncoder *m_encoder = nullptr;
- AVFImageCapture *m_imageCaptureControl = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/camera/avfcamerasession.mm b/src/multimedia/platform/darwin/camera/avfcamerasession.mm
deleted file mode 100644
index 4a6d4ddeb..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamerasession.mm
+++ /dev/null
@@ -1,521 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfcameradebug_p.h"
-#include "avfcamerasession_p.h"
-#include "avfcameraservice_p.h"
-#include "avfcamera_p.h"
-#include "avfcamerarenderer_p.h"
-#include "avfimagecapture_p.h"
-#include "avfmediaencoder_p.h"
-#include "avfcamerautility_p.h"
-#include <private/avfvideosink_p.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Foundation/Foundation.h>
-
-#include <QtCore/qdatetime.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qelapsedtimer.h>
-
-#include <private/qplatformaudioinput_p.h>
-#include <private/qplatformaudiooutput_p.h>
-
-#include <QtCore/qdebug.h>
-
-QT_USE_NAMESPACE
-
-@interface AVFCameraSessionObserver : NSObject
-
-- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session;
-- (void) processRuntimeError:(NSNotification *)notification;
-- (void) processSessionStarted:(NSNotification *)notification;
-- (void) processSessionStopped:(NSNotification *)notification;
-
-@end
-
-@implementation AVFCameraSessionObserver
-{
-@private
- AVFCameraSession *m_session;
- AVCaptureSession *m_captureSession;
-}
-
-- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session
-{
- if (!(self = [super init]))
- return nil;
-
- self->m_session = session;
- self->m_captureSession = session->captureSession();
-
- [m_captureSession retain];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(processRuntimeError:)
- name:AVCaptureSessionRuntimeErrorNotification
- object:m_captureSession];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(processSessionStarted:)
- name:AVCaptureSessionDidStartRunningNotification
- object:m_captureSession];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(processSessionStopped:)
- name:AVCaptureSessionDidStopRunningNotification
- object:m_captureSession];
-
- return self;
-}
-
-- (void) dealloc
-{
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:AVCaptureSessionRuntimeErrorNotification
- object:m_captureSession];
-
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:AVCaptureSessionDidStartRunningNotification
- object:m_captureSession];
-
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:AVCaptureSessionDidStopRunningNotification
- object:m_captureSession];
- [m_captureSession release];
- [super dealloc];
-}
-
-- (void) processRuntimeError:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- QMetaObject::invokeMethod(m_session, "processRuntimeError", Qt::AutoConnection);
-}
-
-- (void) processSessionStarted:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- QMetaObject::invokeMethod(m_session, "processSessionStarted", Qt::AutoConnection);
-}
-
-- (void) processSessionStopped:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- QMetaObject::invokeMethod(m_session, "processSessionStopped", Qt::AutoConnection);
-}
-
-@end
-
-AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent)
- : QObject(parent)
- , m_service(service)
- , m_defaultCodec(0)
-{
- m_captureSession = [[AVCaptureSession alloc] init];
- m_observer = [[AVFCameraSessionObserver alloc] initWithCameraSession:this];
-}
-
-AVFCameraSession::~AVFCameraSession()
-{
- if (m_videoInput) {
- [m_captureSession removeInput:m_videoInput];
- [m_videoInput release];
- }
-
- if (m_audioInput) {
- [m_captureSession removeInput:m_audioInput];
- [m_audioInput release];
- }
-
- if (m_audioOutput) {
- [m_captureSession removeOutput:m_audioOutput];
- [m_audioOutput release];
- }
-
- if (m_videoOutput)
- delete m_videoOutput;
-
- [m_observer release];
- [m_captureSession release];
-}
-
-void AVFCameraSession::setActiveCamera(const QCameraDevice &info)
-{
- if (m_activeCameraDevice != info) {
- m_activeCameraDevice = info;
-
- auto recorder = m_service->recorderControl();
- if (recorder && recorder->state() == QMediaRecorder::RecordingState)
- recorder->toggleRecord(false);
-
- [m_captureSession beginConfiguration];
-
- attachVideoInputDevice();
- if (!m_activeCameraDevice.isNull() && !m_videoOutput) {
- setVideoOutput(new AVFCameraRenderer(this));
- connect(m_videoOutput, &AVFCameraRenderer::newViewfinderFrame,
- this, &AVFCameraSession::newViewfinderFrame);
- updateVideoOutput();
- }
- m_videoOutput->deviceOrientationChanged();
-
- [m_captureSession commitConfiguration];
-
- if (recorder && recorder->state() == QMediaRecorder::RecordingState)
- recorder->toggleRecord(true);
- }
-}
-
-void AVFCameraSession::setCameraFormat(const QCameraFormat &format)
-{
- if (m_cameraFormat == format)
- return;
- m_cameraFormat = format;
-
- AVCaptureDevice *captureDevice = videoCaptureDevice();
- if (!captureDevice)
- return;
-
- AVCaptureDeviceFormat *newFormat = qt_convert_to_capture_device_format(captureDevice, format);
- if (newFormat) {
- qt_set_active_format(captureDevice, newFormat, false);
- if (m_videoOutput)
- m_videoOutput->setPixelFormat(format.pixelFormat());
- }
-}
-
-void AVFCameraSession::setVideoOutput(AVFCameraRenderer *output)
-{
- if (m_videoOutput == output)
- return;
-
- delete m_videoOutput;
- m_videoOutput = output;
- if (output)
- output->configureAVCaptureSession(this);
-}
-
-void AVFCameraSession::addAudioCapture()
-{
- if (!m_audioOutput) {
- m_audioOutput = [[AVCaptureAudioDataOutput alloc] init];
- if (m_audioOutput && [m_captureSession canAddOutput:m_audioOutput]) {
- [m_captureSession addOutput:m_audioOutput];
- } else {
- qWarning() << Q_FUNC_INFO << "failed to add audio output";
- }
- }
-}
-
-AVCaptureDevice *AVFCameraSession::videoCaptureDevice() const
-{
- if (m_videoInput)
- return m_videoInput.device;
-
- return nullptr;
-}
-
-AVCaptureDevice *AVFCameraSession::audioCaptureDevice() const
-{
- if (m_audioInput)
- return m_audioInput.device;
-
- return nullptr;
-}
-
-void AVFCameraSession::setAudioInputVolume(float volume)
-{
- m_inputVolume = volume;
-
- if (m_inputMuted)
- volume = 0.0;
-
-#ifdef Q_OS_MACOS
- AVCaptureConnection *audioInputConnection = [m_audioOutput connectionWithMediaType:AVMediaTypeAudio];
- NSArray<AVCaptureAudioChannel *> *audioChannels = audioInputConnection.audioChannels;
- if (audioChannels) {
- for (AVCaptureAudioChannel *channel in audioChannels) {
- channel.volume = volume;
- }
- }
-#endif
-}
-
-void AVFCameraSession::setAudioInputMuted(bool muted)
-{
- m_inputMuted = muted;
- setAudioInputVolume(m_inputVolume);
-}
-
-void AVFCameraSession::setAudioOutputVolume(float volume)
-{
- if (m_audioPreviewDelegate)
- [m_audioPreviewDelegate setVolume:volume];
-}
-
-void AVFCameraSession::setAudioOutputMuted(bool muted)
-{
- if (m_audioPreviewDelegate)
- [m_audioPreviewDelegate setMuted:muted];
-}
-
-bool AVFCameraSession::isActive() const
-{
- return m_active;
-}
-
-void AVFCameraSession::setActive(bool active)
-{
- if (m_active == active)
- return;
-
- m_active = active;
-
- qDebugCamera() << Q_FUNC_INFO << m_active << " -> " << active;
-
- if (active) {
- if (!m_activeCameraDevice.isNull()) {
- Q_EMIT readyToConfigureConnections();
- m_defaultCodec = 0;
- defaultCodec();
- }
-
- applyImageEncoderSettings();
-
- // According to the doc, the capture device must be locked before
- // startRunning to prevent the format we set to be overridden by the
- // session preset.
- [videoCaptureDevice() lockForConfiguration:nil];
- [m_captureSession startRunning];
- [videoCaptureDevice() unlockForConfiguration];
- } else {
- [m_captureSession stopRunning];
- }
-}
-
-void AVFCameraSession::processRuntimeError()
-{
- qWarning() << tr("Runtime camera error");
- m_active = false;
- Q_EMIT error(QCamera::CameraError, tr("Runtime camera error"));
-}
-
-void AVFCameraSession::processSessionStarted()
-{
- qDebugCamera() << Q_FUNC_INFO;
- if (!m_active) {
- m_active = true;
- Q_EMIT activeChanged(m_active);
- }
-}
-
-void AVFCameraSession::processSessionStopped()
-{
- qDebugCamera() << Q_FUNC_INFO;
- if (m_active) {
- m_active = false;
- Q_EMIT activeChanged(m_active);
- }
-}
-
-AVCaptureDevice *AVFCameraSession::createVideoCaptureDevice()
-{
- AVCaptureDevice *device = nullptr;
-
- QByteArray deviceId = m_activeCameraDevice.id();
- if (!deviceId.isEmpty()) {
- device = [AVCaptureDevice deviceWithUniqueID:
- [NSString stringWithUTF8String:
- deviceId.constData()]];
- }
-
- return device;
-}
-
-AVCaptureDevice *AVFCameraSession::createAudioCaptureDevice()
-{
- AVCaptureDevice *device = nullptr;
-
- QByteArray deviceId = m_service->audioInput() ? m_service->audioInput()->device.id()
- : QByteArray();
- if (!deviceId.isEmpty())
- device = [AVCaptureDevice deviceWithUniqueID: [NSString stringWithUTF8String:deviceId.constData()]];
-
- return device;
-}
-
-void AVFCameraSession::attachVideoInputDevice()
-{
- if (m_videoInput) {
- [m_captureSession removeInput:m_videoInput];
- [m_videoInput release];
- m_videoInput = nullptr;
- }
-
- AVCaptureDevice *videoDevice = createVideoCaptureDevice();
- if (videoDevice) {
- NSError *error = nil;
- m_videoInput = [AVCaptureDeviceInput
- deviceInputWithDevice:videoDevice
- error:&error];
-
- if (!m_videoInput) {
- qWarning() << "Failed to create video device input";
- } else {
- if ([m_captureSession canAddInput:m_videoInput]) {
- [m_videoInput retain];
- [m_captureSession addInput:m_videoInput];
- } else {
- qWarning() << "Failed to connect video device input";
- m_activeCameraDevice = QCameraDevice();
- }
- }
- } else {
- m_activeCameraDevice = QCameraDevice();
- }
-}
-
-void AVFCameraSession::attachAudioInputDevice()
-{
- if (m_audioInput) {
- [m_captureSession removeInput:m_audioInput];
- [m_audioInput release];
- m_audioInput = nullptr;
- }
-
- AVCaptureDevice *audioDevice = createAudioCaptureDevice();
- if (audioDevice) {
- NSError *error = nil;
- m_audioInput = [AVCaptureDeviceInput
- deviceInputWithDevice:audioDevice
- error:&error];
-
- if (!m_audioInput) {
- qWarning() << "Failed to create audio device input";
- } else {
- if ([m_captureSession canAddInput:m_audioInput]) {
- [m_audioInput retain];
- [m_captureSession addInput:m_audioInput];
- } else {
- qWarning() << "Failed to connect audio device input";
- }
- }
- }
-}
-
-bool AVFCameraSession::applyImageEncoderSettings()
-{
- if (AVFImageCapture *control = m_service->avfImageCaptureControl())
- return control->applySettings();
-
- return false;
-}
-
-FourCharCode AVFCameraSession::defaultCodec()
-{
- if (!m_defaultCodec) {
- if (AVCaptureDevice *device = videoCaptureDevice()) {
- AVCaptureDeviceFormat *format = device.activeFormat;
- if (!format || !format.formatDescription)
- return m_defaultCodec;
- m_defaultCodec = CMVideoFormatDescriptionGetCodecType(format.formatDescription);
- }
- }
- return m_defaultCodec;
-}
-
-void AVFCameraSession::setVideoSink(QVideoSink *sink)
-{
- auto *videoSink = sink ? static_cast<AVFVideoSink *>(sink->platformVideoSink()) : nullptr;
-
- if (m_videoSink == videoSink)
- return;
-
- m_videoSink = videoSink;
-
- updateVideoOutput();
-}
-
-void AVFCameraSession::updateAudioInput()
-{
- auto recorder = m_service->recorderControl();
- if (recorder && recorder->state() == QMediaRecorder::RecordingState)
- recorder->toggleRecord(false);
-
- [m_captureSession beginConfiguration];
- if (m_audioOutput) {
- AVCaptureConnection *lastConnection = [m_audioOutput connectionWithMediaType:AVMediaTypeAudio];
- [m_captureSession removeConnection:lastConnection];
- }
- attachAudioInputDevice();
- if (m_audioInput)
- addAudioCapture();
- [m_captureSession commitConfiguration];
-
- if (recorder && recorder->state() == QMediaRecorder::RecordingState)
- recorder->toggleRecord(true);
-}
-
-void AVFCameraSession::updateAudioOutput()
-{
- QByteArray deviceId = m_service->audioOutput()
- ? m_service->audioOutput()->device.id()
- : QByteArray();
-
- [m_audioPreviewDelegate release];
- m_audioPreviewDelegate = nil;
- if (!deviceId.isEmpty()) {
- m_audioPreviewDelegate = [[AVFAudioPreviewDelegate alloc] init];
- [m_audioPreviewDelegate setupWithCaptureSession:this
- audioOutputDevice:[NSString stringWithUTF8String:
- deviceId.constData()]];
- }
-}
-
-void AVFCameraSession::updateVideoOutput()
-{
- if (m_videoOutput) {
- m_videoOutput->setVideoSink(m_videoSink);
- if (m_videoSink) {
- AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:m_captureSession];
- m_videoOutput->setLayer(previewLayer);
- }
- }
-}
-
-#include "moc_avfcamerasession_p.cpp"
diff --git a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h b/src/multimedia/platform/darwin/camera/avfcamerasession_p.h
deleted file mode 100644
index e461b809c..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFCAMERASESSION_H
-#define AVFCAMERASESSION_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/qmutex.h>
-#include <QtMultimedia/qcamera.h>
-#include <QVideoFrame>
-#include <qcameradevice.h>
-#include "avfaudiopreviewdelegate_p.h"
-
-#import <AVFoundation/AVFoundation.h>
-
-@class AVFCameraSessionObserver;
-
-QT_BEGIN_NAMESPACE
-
-class AVFCamera;
-class AVFCameraService;
-class AVFCameraRenderer;
-class AVFVideoSink;
-class QVideoSink;
-
-class AVFCameraSession : public QObject
-{
- Q_OBJECT
-public:
- AVFCameraSession(AVFCameraService *service, QObject *parent = nullptr);
- ~AVFCameraSession();
-
- QCameraDevice activecameraDevice() const { return m_activeCameraDevice; }
- void setActiveCamera(const QCameraDevice &info);
-
- void setCameraFormat(const QCameraFormat &format);
-
- AVFCameraRenderer *videoOutput() const { return m_videoOutput; }
- AVCaptureAudioDataOutput *audioOutput() const { return m_audioOutput; }
- AVFAudioPreviewDelegate *audioPreviewDelegate() const { return m_audioPreviewDelegate; }
-
-
- AVCaptureSession *captureSession() const { return m_captureSession; }
- AVCaptureDevice *videoCaptureDevice() const;
- AVCaptureDevice *audioCaptureDevice() const;
-
- bool isActive() const;
-
- FourCharCode defaultCodec();
-
- AVCaptureDeviceInput *videoInput() const { return m_videoInput; }
- AVCaptureDeviceInput *audioInput() const { return m_audioInput; }
-
- void setVideoSink(QVideoSink *sink);
-
- void updateAudioInput();
- void updateAudioOutput();
-
-public Q_SLOTS:
- void setActive(bool active);
-
- void setAudioInputVolume(float volume);
- void setAudioInputMuted(bool muted);
- void setAudioOutputMuted(bool muted);
- void setAudioOutputVolume(float volume);
-
- void processRuntimeError();
- void processSessionStarted();
- void processSessionStopped();
-
-Q_SIGNALS:
- void readyToConfigureConnections();
- void activeChanged(bool);
- void error(int error, const QString &errorString);
- void newViewfinderFrame(const QVideoFrame &frame);
-
-private:
- void setVideoOutput(AVFCameraRenderer *output);
- void updateVideoOutput();
-
- void addAudioCapture();
-
- AVCaptureDevice *createVideoCaptureDevice();
- AVCaptureDevice *createAudioCaptureDevice();
- void attachVideoInputDevice();
- void attachAudioInputDevice();
-
- bool applyImageEncoderSettings();
-
- QCameraDevice m_activeCameraDevice;
- QCameraFormat m_cameraFormat;
-
- AVFCameraService *m_service;
- AVCaptureSession *m_captureSession;
- AVFCameraSessionObserver *m_observer;
-
- AVFCameraRenderer *m_videoOutput = nullptr;
- AVFVideoSink *m_videoSink = nullptr;
-
- AVCaptureDeviceInput *m_videoInput = nullptr;
- AVCaptureDeviceInput *m_audioInput = nullptr;
-
- AVCaptureAudioDataOutput *m_audioOutput = nullptr;
- AVFAudioPreviewDelegate *m_audioPreviewDelegate = nullptr;
-
- bool m_active = false;
-
- float m_inputVolume = 1.0;
- bool m_inputMuted = false;
-
- FourCharCode m_defaultCodec;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/camera/avfcamerautility.mm b/src/multimedia/platform/darwin/camera/avfcamerautility.mm
deleted file mode 100644
index 444162523..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamerautility.mm
+++ /dev/null
@@ -1,714 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfcamerautility_p.h"
-#include "avfcameradebug_p.h"
-
-#include <QtCore/qvector.h>
-#include <QtCore/qpair.h>
-#include <private/qmultimediautils_p.h>
-#include "private/avfvideobuffer_p.h"
-
-#include <functional>
-#include <algorithm>
-#include <limits>
-#include <tuple>
-
-QT_BEGIN_NAMESPACE
-
-AVFPSRange qt_connection_framerates(AVCaptureConnection *videoConnection)
-{
- Q_ASSERT(videoConnection);
-
- AVFPSRange newRange;
- // "The value in the videoMinFrameDuration is equivalent to the reciprocal
- // of the maximum framerate, the value in the videoMaxFrameDuration is equivalent
- // to the reciprocal of the minimum framerate."
- if (videoConnection.supportsVideoMinFrameDuration) {
- const CMTime cmMin = videoConnection.videoMinFrameDuration;
- if (CMTimeCompare(cmMin, kCMTimeInvalid)) { // Has some non-default value:
- if (const Float64 minSeconds = CMTimeGetSeconds(cmMin))
- newRange.second = 1. / minSeconds;
- }
- }
-
- if (videoConnection.supportsVideoMaxFrameDuration) {
- const CMTime cmMax = videoConnection.videoMaxFrameDuration;
- if (CMTimeCompare(cmMax, kCMTimeInvalid)) {
- if (const Float64 maxSeconds = CMTimeGetSeconds(cmMax))
- newRange.first = 1. / maxSeconds;
- }
- }
-
- return newRange;
-}
-
-namespace {
-
-inline bool qt_area_sane(const QSize &size)
-{
- return !size.isNull() && size.isValid()
- && std::numeric_limits<int>::max() / size.width() >= size.height();
-}
-
-template <template <typename...> class Comp> // std::less or std::greater (or std::equal_to)
-struct ByResolution
-{
- bool operator() (AVCaptureDeviceFormat *f1, AVCaptureDeviceFormat *f2)const
- {
- Q_ASSERT(f1 && f2);
- const QSize r1(qt_device_format_resolution(f1));
- const QSize r2(qt_device_format_resolution(f2));
- // use std::tuple for lexicograpical sorting:
- const Comp<std::tuple<int, int>> op = {};
- return op(std::make_tuple(r1.width(), r1.height()),
- std::make_tuple(r2.width(), r2.height()));
- }
-};
-
-struct FormatHasNoFPSRange : std::unary_function<AVCaptureDeviceFormat *, bool>
-{
- bool operator() (AVCaptureDeviceFormat *format)
- {
- Q_ASSERT(format);
- return !format.videoSupportedFrameRateRanges || !format.videoSupportedFrameRateRanges.count;
- }
-};
-
-Float64 qt_find_min_framerate_distance(AVCaptureDeviceFormat *format, Float64 fps)
-{
- Q_ASSERT(format && format.videoSupportedFrameRateRanges
- && format.videoSupportedFrameRateRanges.count);
-
- AVFrameRateRange *range = [format.videoSupportedFrameRateRanges objectAtIndex:0];
- Float64 distance = qAbs(range.maxFrameRate - fps);
- for (NSUInteger i = 1, e = format.videoSupportedFrameRateRanges.count; i < e; ++i) {
- range = [format.videoSupportedFrameRateRanges objectAtIndex:i];
- distance = qMin(distance, qAbs(range.maxFrameRate - fps));
- }
-
- return distance;
-}
-
-} // Unnamed namespace.
-
-AVCaptureDeviceFormat *qt_convert_to_capture_device_format(AVCaptureDevice *captureDevice,
- const QCameraFormat &cameraFormat)
-{
- AVCaptureDeviceFormat *newFormat = nil;
- NSArray<AVCaptureDeviceFormat *> *formats = captureDevice.formats;
- for (AVCaptureDeviceFormat *format in formats) {
- CMFormatDescriptionRef formatDesc = format.formatDescription;
- CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDesc);
- FourCharCode formatCodec = CMVideoFormatDescriptionGetCodecType(formatDesc);
- if (AVFVideoBuffer::fromCVPixelFormat(formatCodec) == cameraFormat.pixelFormat()
- && cameraFormat.resolution().width() == dim.width
- && cameraFormat.resolution().height() == dim.height) {
- for (AVFrameRateRange *frameRateRange in format.videoSupportedFrameRateRanges) {
- if (frameRateRange.minFrameRate >= cameraFormat.minFrameRate()
- && frameRateRange.maxFrameRate <= cameraFormat.maxFrameRate()) {
- newFormat = format;
- break;
- }
- }
- }
- if (newFormat)
- break;
- }
- return newFormat;
-}
-
-QVector<AVCaptureDeviceFormat *> qt_unique_device_formats(AVCaptureDevice *captureDevice, FourCharCode filter)
-{
- // 'filter' is the format we prefer if we have duplicates.
- Q_ASSERT(captureDevice);
-
- QVector<AVCaptureDeviceFormat *> formats;
-
- if (!captureDevice.formats || !captureDevice.formats.count)
- return formats;
-
- formats.reserve(captureDevice.formats.count);
- for (AVCaptureDeviceFormat *format in captureDevice.formats) {
- const QSize resolution(qt_device_format_resolution(format));
- if (resolution.isNull() || !resolution.isValid())
- continue;
- formats << format;
- }
-
- if (!formats.size())
- return formats;
-
- std::sort(formats.begin(), formats.end(), ByResolution<std::less>());
-
- QSize size(qt_device_format_resolution(formats[0]));
- FourCharCode codec = CMVideoFormatDescriptionGetCodecType(formats[0].formatDescription);
- int last = 0;
- for (int i = 1; i < formats.size(); ++i) {
- const QSize nextSize(qt_device_format_resolution(formats[i]));
- if (nextSize == size) {
- if (codec == filter)
- continue;
- formats[last] = formats[i];
- } else {
- ++last;
- formats[last] = formats[i];
- size = nextSize;
- }
- codec = CMVideoFormatDescriptionGetCodecType(formats[i].formatDescription);
- }
- formats.resize(last + 1);
-
- return formats;
-}
-
-QSize qt_device_format_resolution(AVCaptureDeviceFormat *format)
-{
- if (!format || !format.formatDescription)
- return QSize();
-
- const CMVideoDimensions res = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
- return QSize(res.width, res.height);
-}
-
-QSize qt_device_format_high_resolution(AVCaptureDeviceFormat *format)
-{
- Q_ASSERT(format);
- QSize res;
-#if defined(Q_OS_IOS)
- const CMVideoDimensions hrDim(format.highResolutionStillImageDimensions);
- res.setWidth(hrDim.width);
- res.setHeight(hrDim.height);
-#endif
- return res;
-}
-
-QVector<AVFPSRange> qt_device_format_framerates(AVCaptureDeviceFormat *format)
-{
- Q_ASSERT(format);
-
- QVector<AVFPSRange> qtRanges;
-
- if (!format.videoSupportedFrameRateRanges || !format.videoSupportedFrameRateRanges.count)
- return qtRanges;
-
- qtRanges.reserve(format.videoSupportedFrameRateRanges.count);
- for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges)
- qtRanges << AVFPSRange(range.minFrameRate, range.maxFrameRate);
-
- return qtRanges;
-}
-
-QSize qt_device_format_pixel_aspect_ratio(AVCaptureDeviceFormat *format)
-{
- Q_ASSERT(format);
-
- if (!format.formatDescription) {
- qDebugCamera() << Q_FUNC_INFO << "no format description found";
- return QSize();
- }
-
- const CMVideoDimensions res = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
- const CGSize resPAR = CMVideoFormatDescriptionGetPresentationDimensions(format.formatDescription, true, false);
-
- if (qAbs(resPAR.width - res.width) < 1.) {
- // "Pixel aspect ratio is used to adjust the width, leaving the height alone."
- return QSize(1, 1);
- }
-
- if (!res.width || !resPAR.width)
- return QSize();
-
- int n, d;
- qt_real_to_fraction(resPAR.width > res.width
- ? res.width / qreal(resPAR.width)
- : resPAR.width / qreal(res.width),
- &n, &d);
-
- return QSize(n, d);
-}
-
-AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice,
- const QSize &request,
- FourCharCode filter,
- bool stillImage)
-{
- Q_ASSERT(captureDevice);
- Q_ASSERT(!request.isNull() && request.isValid());
-
- if (!captureDevice.formats || !captureDevice.formats.count)
- return nullptr;
-
- QVector<AVCaptureDeviceFormat *> formats(qt_unique_device_formats(captureDevice, filter));
-
- for (int i = 0; i < formats.size(); ++i) {
- AVCaptureDeviceFormat *format = formats[i];
- if (qt_device_format_resolution(format) == request)
- return format;
- // iOS only (still images).
- if (stillImage && qt_device_format_high_resolution(format) == request)
- return format;
- }
-
- if (!qt_area_sane(request))
- return nullptr;
-
- typedef QPair<QSize, AVCaptureDeviceFormat *> FormatPair;
-
- QVector<FormatPair> pairs; // default|HR sizes
- pairs.reserve(formats.size());
-
- for (int i = 0; i < formats.size(); ++i) {
- AVCaptureDeviceFormat *format = formats[i];
- const QSize res(qt_device_format_resolution(format));
- if (!res.isNull() && res.isValid() && qt_area_sane(res))
- pairs << FormatPair(res, format);
- const QSize highRes(qt_device_format_high_resolution(format));
- if (stillImage && !highRes.isNull() && highRes.isValid() && qt_area_sane(highRes))
- pairs << FormatPair(highRes, format);
- }
-
- if (!pairs.size())
- return nullptr;
-
- AVCaptureDeviceFormat *best = pairs[0].second;
- QSize next(pairs[0].first);
- int wDiff = qAbs(request.width() - next.width());
- int hDiff = qAbs(request.height() - next.height());
- const int area = request.width() * request.height();
- int areaDiff = qAbs(area - next.width() * next.height());
- for (int i = 1; i < pairs.size(); ++i) {
- next = pairs[i].first;
- const int newWDiff = qAbs(next.width() - request.width());
- const int newHDiff = qAbs(next.height() - request.height());
- const int newAreaDiff = qAbs(area - next.width() * next.height());
-
- if ((newWDiff < wDiff && newHDiff < hDiff)
- || ((newWDiff <= wDiff || newHDiff <= hDiff) && newAreaDiff <= areaDiff)) {
- wDiff = newWDiff;
- hDiff = newHDiff;
- best = pairs[i].second;
- areaDiff = newAreaDiff;
- }
- }
-
- return best;
-}
-
-AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice,
- FourCharCode filter,
- Float64 fps)
-{
- Q_ASSERT(captureDevice);
- Q_ASSERT(fps > 0.);
-
- const qreal epsilon = 0.1;
-
- QVector<AVCaptureDeviceFormat *>sorted(qt_unique_device_formats(captureDevice, filter));
- // Sort formats by their resolution in decreasing order:
- std::sort(sorted.begin(), sorted.end(), ByResolution<std::greater>());
- // We can use only formats with framerate ranges:
- sorted.erase(std::remove_if(sorted.begin(), sorted.end(), FormatHasNoFPSRange()), sorted.end());
-
- if (!sorted.size())
- return nil;
-
- for (int i = 0; i < sorted.size(); ++i) {
- AVCaptureDeviceFormat *format = sorted[i];
- for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) {
- if (range.maxFrameRate - range.minFrameRate < epsilon) {
- // On OS X ranges are points (built-in camera).
- if (qAbs(fps - range.maxFrameRate) < epsilon)
- return format;
- }
-
- if (fps >= range.minFrameRate && fps <= range.maxFrameRate)
- return format;
- }
- }
-
- Float64 distance = qt_find_min_framerate_distance(sorted[0], fps);
- AVCaptureDeviceFormat *match = sorted[0];
- for (int i = 1; i < sorted.size(); ++i) {
- const Float64 newDistance = qt_find_min_framerate_distance(sorted[i], fps);
- if (newDistance < distance) {
- distance = newDistance;
- match = sorted[i];
- }
- }
-
- return match;
-}
-
-AVFrameRateRange *qt_find_supported_framerate_range(AVCaptureDeviceFormat *format, Float64 fps)
-{
- Q_ASSERT(format && format.videoSupportedFrameRateRanges
- && format.videoSupportedFrameRateRanges.count);
-
- const qreal epsilon = 0.1;
-
- for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) {
- if (range.maxFrameRate - range.minFrameRate < epsilon) {
- // On OS X ranges are points (built-in camera).
- if (qAbs(fps - range.maxFrameRate) < epsilon)
- return range;
- }
-
- if (fps >= range.minFrameRate && fps <= range.maxFrameRate)
- return range;
- }
-
- AVFrameRateRange *match = [format.videoSupportedFrameRateRanges objectAtIndex:0];
- Float64 distance = qAbs(match.maxFrameRate - fps);
- for (NSUInteger i = 1, e = format.videoSupportedFrameRateRanges.count; i < e; ++i) {
- AVFrameRateRange *range = [format.videoSupportedFrameRateRanges objectAtIndex:i];
- const Float64 newDistance = qAbs(range.maxFrameRate - fps);
- if (newDistance < distance) {
- distance = newDistance;
- match = range;
- }
- }
-
- return match;
-}
-
-bool qt_format_supports_framerate(AVCaptureDeviceFormat *format, qreal fps)
-{
- if (format && fps > qreal(0)) {
- const qreal epsilon = 0.1;
- for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) {
- if (fps >= range.minFrameRate - epsilon && fps <= range.maxFrameRate + epsilon)
- return true;
- }
- }
-
- return false;
-}
-
-bool qt_formats_are_equal(AVCaptureDeviceFormat *f1, AVCaptureDeviceFormat *f2)
-{
- if (f1 == f2)
- return true;
-
- if (![f1.mediaType isEqualToString:f2.mediaType])
- return false;
-
- return CMFormatDescriptionEqual(f1.formatDescription, f2.formatDescription);
-}
-
-bool qt_set_active_format(AVCaptureDevice *captureDevice, AVCaptureDeviceFormat *format, bool preserveFps)
-{
- static bool firstSet = true;
-
- if (!captureDevice || !format)
- return false;
-
- if (qt_formats_are_equal(captureDevice.activeFormat, format)) {
- if (firstSet) {
- // The capture device format is persistent. The first time we set a format, report that
- // it changed even if the formats are the same.
- // This prevents the session from resetting the format to the default value.
- firstSet = false;
- return true;
- }
- return false;
- }
-
- firstSet = false;
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qWarning("Failed to set active format (lock failed)");
- return false;
- }
-
- // Changing the activeFormat resets the frame rate.
- AVFPSRange fps;
- if (preserveFps)
- fps = qt_current_framerates(captureDevice, nil);
-
- captureDevice.activeFormat = format;
-
- if (preserveFps)
- qt_set_framerate_limits(captureDevice, nil, fps.first, fps.second);
-
- return true;
-}
-
-void qt_set_framerate_limits(AVCaptureConnection *videoConnection, qreal minFPS, qreal maxFPS)
-{
- Q_ASSERT(videoConnection);
-
- if (minFPS < 0. || maxFPS < 0. || (maxFPS && maxFPS < minFPS)) {
- qDebugCamera() << Q_FUNC_INFO << "invalid framerates (min, max):"
- << minFPS << maxFPS;
- return;
- }
-
- CMTime minDuration = kCMTimeInvalid;
- if (maxFPS > 0.) {
- if (!videoConnection.supportsVideoMinFrameDuration)
- qDebugCamera() << Q_FUNC_INFO << "maximum framerate is not supported";
- else
- minDuration = CMTimeMake(1, maxFPS);
- }
- if (videoConnection.supportsVideoMinFrameDuration)
- videoConnection.videoMinFrameDuration = minDuration;
-
- CMTime maxDuration = kCMTimeInvalid;
- if (minFPS > 0.) {
- if (!videoConnection.supportsVideoMaxFrameDuration)
- qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
- else
- maxDuration = CMTimeMake(1, minFPS);
- }
- if (videoConnection.supportsVideoMaxFrameDuration)
- videoConnection.videoMaxFrameDuration = maxDuration;
-}
-
-CMTime qt_adjusted_frame_duration(AVFrameRateRange *range, qreal fps)
-{
- Q_ASSERT(range);
- Q_ASSERT(fps > 0.);
-
- if (range.maxFrameRate - range.minFrameRate < 0.1) {
- // Can happen on OS X.
- return range.minFrameDuration;
- }
-
- if (fps <= range.minFrameRate)
- return range.maxFrameDuration;
- if (fps >= range.maxFrameRate)
- return range.minFrameDuration;
-
- int n, d;
- qt_real_to_fraction(1. / fps, &n, &d);
- return CMTimeMake(n, d);
-}
-
-void qt_set_framerate_limits(AVCaptureDevice *captureDevice, qreal minFPS, qreal maxFPS)
-{
- Q_ASSERT(captureDevice);
- if (!captureDevice.activeFormat) {
- qDebugCamera() << Q_FUNC_INFO << "no active capture device format";
- return;
- }
-
- if (minFPS < 0. || maxFPS < 0. || (maxFPS && maxFPS < minFPS)) {
- qDebugCamera() << Q_FUNC_INFO << "invalid framerates (min, max):"
- << minFPS << maxFPS;
- return;
- }
-
- CMTime minFrameDuration = kCMTimeInvalid;
- CMTime maxFrameDuration = kCMTimeInvalid;
- if (maxFPS || minFPS) {
- AVFrameRateRange *range = qt_find_supported_framerate_range(captureDevice.activeFormat,
- maxFPS ? maxFPS : minFPS);
- if (!range) {
- qDebugCamera() << Q_FUNC_INFO << "no framerate range found, (min, max):"
- << minFPS << maxFPS;
- return;
- }
-
- if (maxFPS)
- minFrameDuration = qt_adjusted_frame_duration(range, maxFPS);
- if (minFPS)
- maxFrameDuration = qt_adjusted_frame_duration(range, minFPS);
- }
-
- const AVFConfigurationLock lock(captureDevice);
- if (!lock) {
- qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
- return;
- }
-
- // While Apple's docs say kCMTimeInvalid will end in default
- // settings for this format, kCMTimeInvalid on OS X ends with a runtime
- // exception:
- // "The activeVideoMinFrameDuration passed is not supported by the device."
- // Instead, use the first item in the supported frame rates.
-#ifdef Q_OS_IOS
- [captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
- [captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
-#elif defined(Q_OS_MACOS)
- if (CMTimeCompare(minFrameDuration, kCMTimeInvalid) == 0
- && CMTimeCompare(maxFrameDuration, kCMTimeInvalid) == 0) {
- AVFrameRateRange *range = captureDevice.activeFormat.videoSupportedFrameRateRanges.firstObject;
- minFrameDuration = range.minFrameDuration;
- maxFrameDuration = range.maxFrameDuration;
- }
-
- if (CMTimeCompare(minFrameDuration, kCMTimeInvalid))
- [captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
-
- if (CMTimeCompare(maxFrameDuration, kCMTimeInvalid))
- [captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
-#endif // Q_OS_MACOS
-}
-
-void qt_set_framerate_limits(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection,
- qreal minFPS, qreal maxFPS)
-{
- Q_UNUSED(videoConnection);
- Q_ASSERT(captureDevice);
- qt_set_framerate_limits(captureDevice, minFPS, maxFPS);
-}
-
-AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection)
-{
- Q_UNUSED(videoConnection);
- Q_ASSERT(captureDevice);
-
- AVFPSRange fps;
- const CMTime minDuration = captureDevice.activeVideoMinFrameDuration;
- if (CMTimeCompare(minDuration, kCMTimeInvalid)) {
- if (const Float64 minSeconds = CMTimeGetSeconds(minDuration))
- fps.second = 1. / minSeconds; // Max FPS = 1 / MinDuration.
- }
-
- const CMTime maxDuration = captureDevice.activeVideoMaxFrameDuration;
- if (CMTimeCompare(maxDuration, kCMTimeInvalid)) {
- if (const Float64 maxSeconds = CMTimeGetSeconds(maxDuration))
- fps.first = 1. / maxSeconds; // Min FPS = 1 / MaxDuration.
- }
-
- return fps;
-}
-
-QList<AudioValueRange> qt_supported_sample_rates_for_format(int codecId)
-{
- QList<AudioValueRange> result;
- UInt32 format = codecId;
- UInt32 size;
- OSStatus err = AudioFormatGetPropertyInfo(
- kAudioFormatProperty_AvailableEncodeSampleRates,
- sizeof(format),
- &format,
- &size);
-
- if (err != noErr)
- return result;
-
- UInt32 numRanges = size / sizeof(AudioValueRange);
- AudioValueRange sampleRanges[numRanges];
-
- err = AudioFormatGetProperty(kAudioFormatProperty_AvailableEncodeSampleRates,
- sizeof(format),
- &format,
- &size,
- sampleRanges);
- if (err != noErr)
- return result;
-
- for (UInt32 i = 0; i < numRanges; i++)
- result << sampleRanges[i];
-
- return result;
-}
-
-QList<AudioValueRange> qt_supported_bit_rates_for_format(int codecId)
-{
- QList<AudioValueRange> result;
- UInt32 format = codecId;
- UInt32 size;
- OSStatus err = AudioFormatGetPropertyInfo(
- kAudioFormatProperty_AvailableEncodeBitRates,
- sizeof(format),
- &format,
- &size);
-
- if (err != noErr)
- return result;
-
- UInt32 numRanges = size / sizeof(AudioValueRange);
- AudioValueRange bitRanges[numRanges];
-
- err = AudioFormatGetProperty(kAudioFormatProperty_AvailableEncodeBitRates,
- sizeof(format),
- &format,
- &size,
- bitRanges);
- if (err != noErr)
- return result;
-
- for (UInt32 i = 0; i < numRanges; i++)
- result << bitRanges[i];
-
- return result;
-}
-
-std::optional<QList<UInt32>> qt_supported_channel_counts_for_format(int codecId)
-{
- QList<UInt32> result;
- AudioStreamBasicDescription sf = {};
- sf.mFormatID = codecId;
- UInt32 size;
- OSStatus err = AudioFormatGetPropertyInfo(
- kAudioFormatProperty_AvailableEncodeNumberChannels,
- sizeof(sf),
- &sf,
- &size);
-
- if (err != noErr)
- return result;
-
- // From Apple's docs:
- // A value of 0xFFFFFFFF indicates that any number of channels may be encoded.
- if (int(size) == -1)
- return std::nullopt;
-
- UInt32 numCounts = size / sizeof(UInt32);
- UInt32 channelCounts[numCounts];
-
- err = AudioFormatGetProperty(kAudioFormatProperty_AvailableEncodeNumberChannels,
- sizeof(sf),
- &sf,
- &size,
- channelCounts);
- if (err != noErr)
- return result;
-
- for (UInt32 i = 0; i < numCounts; i++)
- result << channelCounts[i];
-
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/camera/avfcamerautility_p.h b/src/multimedia/platform/darwin/camera/avfcamerautility_p.h
deleted file mode 100644
index 26a023be9..000000000
--- a/src/multimedia/platform/darwin/camera/avfcamerautility_p.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFCAMERAUTILITY_H
-#define AVFCAMERAUTILITY_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/qglobal.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
-#include <QtCore/qsize.h>
-
-#include "qcameradevice.h"
-
-#include <CoreAudio/CoreAudioTypes.h>
-
-#include <AVFoundation/AVFoundation.h>
-
-// In case we have SDK below 10.7/7.0:
-@class AVCaptureDeviceFormat;
-
-QT_BEGIN_NAMESPACE
-
-class AVFConfigurationLock
-{
-public:
- explicit AVFConfigurationLock(AVCaptureDevice *captureDevice)
- : m_captureDevice(captureDevice),
- m_locked(false)
- {
- Q_ASSERT(m_captureDevice);
- NSError *error = nil;
- m_locked = [m_captureDevice lockForConfiguration:&error];
- }
-
- ~AVFConfigurationLock()
- {
- if (m_locked)
- [m_captureDevice unlockForConfiguration];
- }
-
- operator bool() const
- {
- return m_locked;
- }
-
-private:
- Q_DISABLE_COPY(AVFConfigurationLock)
-
- AVCaptureDevice *m_captureDevice;
- bool m_locked;
-};
-
-struct AVFObjectDeleter {
- static void cleanup(NSObject *obj)
- {
- if (obj)
- [obj release];
- }
-};
-
-template<class T>
-class AVFScopedPointer : public QScopedPointer<NSObject, AVFObjectDeleter>
-{
-public:
- AVFScopedPointer() {}
- explicit AVFScopedPointer(T *ptr) : QScopedPointer(ptr) {}
- operator T*() const
- {
- // Quite handy operator to enable Obj-C messages: [ptr someMethod];
- return data();
- }
-
- T *data() const
- {
- return static_cast<T *>(QScopedPointer::data());
- }
-
- T *take()
- {
- return static_cast<T *>(QScopedPointer::take());
- }
-};
-
-template<>
-class AVFScopedPointer<dispatch_queue_t>
-{
-public:
- AVFScopedPointer() : m_queue(nullptr) {}
- explicit AVFScopedPointer(dispatch_queue_t q) : m_queue(q) {}
-
- ~AVFScopedPointer()
- {
- if (m_queue)
- dispatch_release(m_queue);
- }
-
- operator dispatch_queue_t() const
- {
- // Quite handy operator to enable Obj-C messages: [ptr someMethod];
- return m_queue;
- }
-
- dispatch_queue_t data() const
- {
- return m_queue;
- }
-
- void reset(dispatch_queue_t q = nullptr)
- {
- if (m_queue)
- dispatch_release(m_queue);
- m_queue = q;
- }
-
-private:
- dispatch_queue_t m_queue;
-
- Q_DISABLE_COPY(AVFScopedPointer)
-};
-
-typedef QPair<qreal, qreal> AVFPSRange;
-AVFPSRange qt_connection_framerates(AVCaptureConnection *videoConnection);
-
-AVCaptureDeviceFormat *qt_convert_to_capture_device_format(AVCaptureDevice *captureDevice,
- const QCameraFormat &format);
-QList<AVCaptureDeviceFormat *> qt_unique_device_formats(AVCaptureDevice *captureDevice,
- FourCharCode preferredFormat);
-QSize qt_device_format_resolution(AVCaptureDeviceFormat *format);
-QSize qt_device_format_high_resolution(AVCaptureDeviceFormat *format);
-QSize qt_device_format_pixel_aspect_ratio(AVCaptureDeviceFormat *format);
-QList<AVFPSRange> qt_device_format_framerates(AVCaptureDeviceFormat *format);
-AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice, const QSize &res,
- FourCharCode preferredFormat, bool stillImage = true);
-AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice,
- FourCharCode preferredFormat,
- Float64 fps);
-AVFrameRateRange *qt_find_supported_framerate_range(AVCaptureDeviceFormat *format, Float64 fps);
-bool qt_format_supports_framerate(AVCaptureDeviceFormat *format, qreal fps);
-
-bool qt_formats_are_equal(AVCaptureDeviceFormat *f1, AVCaptureDeviceFormat *f2);
-bool qt_set_active_format(AVCaptureDevice *captureDevice, AVCaptureDeviceFormat *format, bool preserveFps);
-
-AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection);
-void qt_set_framerate_limits(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection,
- qreal minFPS, qreal maxFPS);
-
-QList<AudioValueRange> qt_supported_sample_rates_for_format(int codecId);
-QList<AudioValueRange> qt_supported_bit_rates_for_format(int codecId);
-std::optional<QList<UInt32>> qt_supported_channel_counts_for_format(int codecId);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/camera/avfimagecapture.mm b/src/multimedia/platform/darwin/camera/avfimagecapture.mm
deleted file mode 100644
index a397fe418..000000000
--- a/src/multimedia/platform/darwin/camera/avfimagecapture.mm
+++ /dev/null
@@ -1,416 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfcameradebug_p.h"
-#include "avfimagecapture_p.h"
-#include "avfcameraservice_p.h"
-#include "avfcamerautility_p.h"
-#include "avfcamera_p.h"
-#include "avfcamerasession_p.h"
-#include "avfcamerarenderer_p.h"
-#include "qmediastoragelocation_p.h"
-#include <private/qplatformimagecapture_p.h>
-#include <private/qmemoryvideobuffer_p.h>
-
-#include <QtCore/qurl.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qbuffer.h>
-#include <QtConcurrent/qtconcurrentrun.h>
-#include <QtGui/qimagereader.h>
-
-#import <AVFoundation/AVFoundation.h>
-
-QT_USE_NAMESPACE
-
-AVFImageCapture::AVFImageCapture(QImageCapture *parent)
- : QPlatformImageCapture(parent)
-{
- m_stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
-
- NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
- AVVideoCodecTypeJPEG, AVVideoCodecKey, nil];
-
- [m_stillImageOutput setOutputSettings:outputSettings];
- [outputSettings release];
-}
-
-AVFImageCapture::~AVFImageCapture()
-{
- [m_stillImageOutput release];
-}
-
-bool AVFImageCapture::isReadyForCapture() const
-{
- return m_cameraControl && m_videoConnection && m_cameraControl->isActive();
-}
-
-void AVFImageCapture::updateReadyStatus()
-{
- if (m_ready != isReadyForCapture()) {
- m_ready = !m_ready;
- qDebugCamera() << "ReadyToCapture status changed:" << m_ready;
- Q_EMIT readyForCaptureChanged(m_ready);
- }
-}
-
-int AVFImageCapture::doCapture(const QString &actualFileName)
-{
- if (!m_session) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, m_lastCaptureId),
- Q_ARG(int, QImageCapture::ResourceError),
- Q_ARG(QString, QPlatformImageCapture::msgImageCaptureNotSet()));
- return m_lastCaptureId;
- }
- if (!isReadyForCapture()) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, m_lastCaptureId),
- Q_ARG(int, QImageCapture::NotReadyError),
- Q_ARG(QString, QPlatformImageCapture::msgCameraNotReady()));
- return m_lastCaptureId;
- }
- m_lastCaptureId++;
-
- bool captureToBuffer = actualFileName.isEmpty();
-
- CaptureRequest request = { m_lastCaptureId, QSharedPointer<QSemaphore>::create()};
- m_requestsMutex.lock();
- m_captureRequests.enqueue(request);
- m_requestsMutex.unlock();
-
- QString fileName(actualFileName);
-
- [m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection
- completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
-
- if (error) {
- QStringList messageParts;
- messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
- messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]);
- messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]);
-
- QString errorMessage = messageParts.join(QChar(u' '));
- qDebugCamera() << "Image capture failed:" << errorMessage;
-
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, request.captureId),
- Q_ARG(int, QImageCapture::ResourceError),
- Q_ARG(QString, errorMessage));
- return;
- }
-
- // Wait for the preview to be generated before saving the JPEG (but only
- // if we have AVFCameraRenderer attached).
- // It is possible to stop camera immediately after trying to capture an
- // image; this can result in a blocked callback's thread, waiting for a
- // new viewfinder's frame to arrive/semaphore to be released. It is also
- // unspecified on which thread this callback gets executed, (probably it's
- // not the same thread that initiated a capture and stopped the camera),
- // so we cannot reliably check the camera's status. Instead, we wait
- // with a timeout and treat a failure to acquire a semaphore as an error.
- if (!m_session->videoOutput() || request.previewReady->tryAcquire(1, 1000)) {
- qDebugCamera() << "Image capture completed";
-
- NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
- QByteArray jpgData = QByteArray::fromRawData((const char *)[nsJpgData bytes], [nsJpgData length]);
-
- if (captureToBuffer) {
- QBuffer data(&jpgData);
- QImageReader reader(&data, "JPEG");
- QSize size = reader.size();
- QVideoFrame frame(new QMemoryVideoBuffer(QByteArray(jpgData.constData(), jpgData.size()), -1),
- QVideoFrameFormat(size, QVideoFrameFormat::Format_Jpeg));
- QMetaObject::invokeMethod(this, "imageAvailable", Qt::QueuedConnection,
- Q_ARG(int, request.captureId),
- Q_ARG(QVideoFrame, frame));
- } else {
- QFile f(fileName);
- if (f.open(QFile::WriteOnly)) {
- if (f.write(jpgData) != -1) {
- QMetaObject::invokeMethod(this, "imageSaved", Qt::QueuedConnection,
- Q_ARG(int, request.captureId),
- Q_ARG(QString, fileName));
- } else {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, request.captureId),
- Q_ARG(int, QImageCapture::OutOfSpaceError),
- Q_ARG(QString, f.errorString()));
- }
- } else {
- QString errorMessage = tr("Could not open destination file:\n%1").arg(fileName);
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, request.captureId),
- Q_ARG(int, QImageCapture::ResourceError),
- Q_ARG(QString, errorMessage));
- }
- }
- } else {
- const QLatin1String errorMessage("Image capture failed: timed out waiting"
- " for a preview frame.");
- qDebugCamera() << errorMessage;
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, request.captureId),
- Q_ARG(int, QImageCapture::ResourceError),
- Q_ARG(QString, errorMessage));
- }
- }];
-
- return request.captureId;
-}
-
-int AVFImageCapture::capture(const QString &fileName)
-{
- auto actualFileName = QMediaStorageLocation::generateFileName(fileName, QStandardPaths::PicturesLocation, QLatin1String("jpg"));
-
- qDebugCamera() << "Capture image to" << actualFileName;
- return doCapture(actualFileName);
-}
-
-int AVFImageCapture::captureToBuffer()
-{
- return doCapture(QString());
-}
-
-void AVFImageCapture::onNewViewfinderFrame(const QVideoFrame &frame)
-{
- QMutexLocker locker(&m_requestsMutex);
-
- if (m_captureRequests.isEmpty())
- return;
-
- CaptureRequest request = m_captureRequests.dequeue();
- Q_EMIT imageExposed(request.captureId);
-
- (void) QtConcurrent::run(&AVFImageCapture::makeCapturePreview, this,
- request,
- frame,
- 0 /* rotation */);
-}
-
-void AVFImageCapture::onCameraChanged()
-{
- if (m_service)
- m_cameraControl = static_cast<AVFCamera *>(m_service->camera());
- else
- m_cameraControl = nullptr;
-
- if (m_cameraControl)
- connect(m_cameraControl, SIGNAL(activeChanged(bool)), this, SLOT(updateReadyStatus()));
-}
-
-void AVFImageCapture::makeCapturePreview(CaptureRequest request,
- const QVideoFrame &frame,
- int rotation)
-{
- QTransform transform;
- transform.rotate(rotation);
-
- Q_EMIT imageCaptured(request.captureId, frame.toImage().transformed(transform));
-
- request.previewReady->release();
-}
-
-void AVFImageCapture::updateCaptureConnection()
-{
- if (m_session && m_session->videoCaptureDevice()) {
- qDebugCamera() << Q_FUNC_INFO;
- AVCaptureSession *captureSession = m_session->captureSession();
-
- if (![captureSession.outputs containsObject:m_stillImageOutput]) {
- if ([captureSession canAddOutput:m_stillImageOutput]) {
- [captureSession beginConfiguration];
- // Lock the video capture device to make sure the active format is not reset
- const AVFConfigurationLock lock(m_session->videoCaptureDevice());
- [captureSession addOutput:m_stillImageOutput];
- m_videoConnection = [m_stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
- [captureSession commitConfiguration];
- updateReadyStatus();
- }
- } else {
- m_videoConnection = [m_stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
- }
- }
-}
-
-
-QImageEncoderSettings AVFImageCapture::imageSettings() const
-{
- QImageEncoderSettings settings;
-
- if (!videoCaptureDeviceIsValid())
- return settings;
-
- AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice();
- if (!captureDevice.activeFormat) {
- qDebugCamera() << Q_FUNC_INFO << "no active format";
- return settings;
- }
-
- QSize res(qt_device_format_resolution(captureDevice.activeFormat));
-#ifdef Q_OS_IOS
- if (!m_service->avfImageCaptureControl() || !m_service->avfImageCaptureControl()->stillImageOutput()) {
- qDebugCamera() << Q_FUNC_INFO << "no still image output";
- return settings;
- }
-
- AVCaptureStillImageOutput *stillImageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
- if (stillImageOutput.highResolutionStillImageOutputEnabled)
- res = qt_device_format_high_resolution(captureDevice.activeFormat);
-#endif
- if (res.isNull() || !res.isValid()) {
- qDebugCamera() << Q_FUNC_INFO << "failed to exctract the image resolution";
- return settings;
- }
-
- settings.setResolution(res);
- settings.setFormat(QImageCapture::JPEG);
-
- return settings;
-}
-
-void AVFImageCapture::setImageSettings(const QImageEncoderSettings &settings)
-{
- if (m_settings == settings)
- return;
-
- m_settings = settings;
- applySettings();
-}
-
-bool AVFImageCapture::applySettings()
-{
- if (!videoCaptureDeviceIsValid())
- return false;
-
- AVFCameraSession *session = m_service->session();
- if (!session)
- return false;
-
- if (!m_service->imageCapture()
- || !m_service->avfImageCaptureControl()->stillImageOutput()) {
- qDebugCamera() << Q_FUNC_INFO << "no still image output";
- return false;
- }
-
- if (m_settings.format() != QImageCapture::UnspecifiedFormat && m_settings.format() != QImageCapture::JPEG) {
- qDebugCamera() << Q_FUNC_INFO << "unsupported format:" << m_settings.format();
- return false;
- }
-
- QSize res(m_settings.resolution());
- if (res.isNull()) {
- qDebugCamera() << Q_FUNC_INFO << "invalid resolution:" << res;
- return false;
- }
-
- if (!res.isValid()) {
- // Invalid == default value.
- // Here we could choose the best format available, but
- // activeFormat is already equal to 'preset high' by default,
- // which is good enough, otherwise we can end in some format with low framerates.
- return false;
- }
-
- bool activeFormatChanged = false;
-
- AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice();
- AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res,
- m_service->session()->defaultCodec());
-
- if (!match) {
- qDebugCamera() << Q_FUNC_INFO << "unsupported resolution:" << res;
- return false;
- }
-
- activeFormatChanged = qt_set_active_format(captureDevice, match, true);
-
-#ifdef Q_OS_IOS
- AVCaptureStillImageOutput *imageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
- if (res == qt_device_format_high_resolution(captureDevice.activeFormat))
- imageOutput.highResolutionStillImageOutputEnabled = YES;
- else
- imageOutput.highResolutionStillImageOutputEnabled = NO;
-#endif
-
- return activeFormatChanged;
-}
-
-void AVFImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- AVFCameraService *captureSession = static_cast<AVFCameraService *>(session);
- if (m_service == captureSession)
- return;
-
- m_service = captureSession;
- if (!m_service) {
- m_session->disconnect(this);
- if (m_cameraControl)
- m_cameraControl->disconnect(this);
- m_session = nullptr;
- m_cameraControl = nullptr;
- m_videoConnection = nil;
- return;
- }
-
- m_session = m_service->session();
- Q_ASSERT(m_session);
-
- connect(m_service, &AVFCameraService::cameraChanged, this, &AVFImageCapture::onCameraChanged);
- connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection()));
- connect(m_session, &AVFCameraSession::newViewfinderFrame,
- this, &AVFImageCapture::onNewViewfinderFrame);
-
- updateCaptureConnection();
- updateReadyStatus();
- onCameraChanged();
-}
-
-bool AVFImageCapture::videoCaptureDeviceIsValid() const
-{
- if (!m_service || !m_service->session() || !m_service->session()->videoCaptureDevice())
- return false;
-
- AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice();
- if (!captureDevice.formats || !captureDevice.formats.count)
- return false;
-
- return true;
-}
-
-#include "moc_avfimagecapture_p.cpp"
diff --git a/src/multimedia/platform/darwin/camera/avfimagecapture_p.h b/src/multimedia/platform/darwin/camera/avfimagecapture_p.h
deleted file mode 100644
index ef11bd70f..000000000
--- a/src/multimedia/platform/darwin/camera/avfimagecapture_p.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFCAMERAIMAGECAPTURE_H
-#define AVFCAMERAIMAGECAPTURE_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.
-//
-
-#import <AVFoundation/AVFoundation.h>
-
-#include <QtCore/qqueue.h>
-#include <QtCore/qsemaphore.h>
-#include <QtCore/qsharedpointer.h>
-#include <private/qplatformimagecapture_p.h>
-#include "avfcamerasession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class AVFImageCapture : public QPlatformImageCapture
-{
-Q_OBJECT
-public:
- struct CaptureRequest {
- int captureId;
- QSharedPointer<QSemaphore> previewReady;
- };
-
- AVFImageCapture(QImageCapture *parent = nullptr);
- ~AVFImageCapture();
-
- bool isReadyForCapture() const override;
-
- AVCaptureStillImageOutput *stillImageOutput() const {return m_stillImageOutput;}
-
- int doCapture(const QString &fileName);
- int capture(const QString &fileName) override;
- int captureToBuffer() override;
-
- QImageEncoderSettings imageSettings() const override;
- void setImageSettings(const QImageEncoderSettings &settings) override;
- bool applySettings();
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
-private Q_SLOTS:
- void updateCaptureConnection();
- void updateReadyStatus();
- void onNewViewfinderFrame(const QVideoFrame &frame);
- void onCameraChanged();
-
-private:
- void makeCapturePreview(CaptureRequest request, const QVideoFrame &frame, int rotation);
- bool videoCaptureDeviceIsValid() const;
-
- AVFCameraService *m_service = nullptr;
- AVFCameraSession *m_session = nullptr;
- AVFCamera *m_cameraControl = nullptr;
- bool m_ready = false;
- int m_lastCaptureId = 0;
- AVCaptureStillImageOutput *m_stillImageOutput;
- AVCaptureConnection *m_videoConnection = nullptr;
-
- QMutex m_requestsMutex;
- QQueue<CaptureRequest> m_captureRequests;
- QImageEncoderSettings m_settings;
-};
-
-Q_DECLARE_TYPEINFO(AVFImageCapture::CaptureRequest, Q_PRIMITIVE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm b/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
deleted file mode 100644
index ed90dbd07..000000000
--- a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
+++ /dev/null
@@ -1,579 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfmediaencoder_p.h"
-#include "avfcamerarenderer_p.h"
-#include "avfmediaassetwriter_p.h"
-#include "avfcameraservice_p.h"
-#include "avfcamerasession_p.h"
-#include "avfcameradebug_p.h"
-#include <private/qdarwinformatsinfo_p.h>
-#include <private/avfmetadata_p.h>
-
-#include <QtCore/qmetaobject.h>
-#include <QtCore/qatomic.h>
-
-QT_USE_NAMESPACE
-
-namespace {
-
-bool qt_capture_session_isValid(AVFCameraService *service)
-{
- if (!service || !service->session())
- return false;
-
- AVFCameraSession *session = service->session();
- if (!session->captureSession())
- return false;
-
- return true;
-}
-
-enum WriterState
-{
- WriterStateIdle,
- WriterStateActive,
- WriterStatePaused,
- WriterStateAborted
-};
-
-using AVFAtomicInt64 = QAtomicInteger<qint64>;
-
-} // unnamed namespace
-
-@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) (PrivateAPI)
-- (bool)addWriterInputs;
-- (void)setQueues;
-- (void)updateDuration:(CMTime)newTimeStamp;
-- (CMSampleBufferRef)adjustTime:(CMSampleBufferRef)sample by:(CMTime)offset;
-@end
-
-@implementation QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)
-{
-@private
- AVFCameraService *m_service;
-
- AVFScopedPointer<AVAssetWriterInput> m_cameraWriterInput;
- AVFScopedPointer<AVAssetWriterInput> m_audioWriterInput;
-
- // Queue to write sample buffers:
- AVFScopedPointer<dispatch_queue_t> m_writerQueue;
- // High priority serial queue for video output:
- AVFScopedPointer<dispatch_queue_t> m_videoQueue;
- // Serial queue for audio output:
- AVFScopedPointer<dispatch_queue_t> m_audioQueue;
-
- AVFScopedPointer<AVAssetWriter> m_assetWriter;
-
- AVFMediaEncoder *m_delegate;
-
- bool m_setStartTime;
-
- QAtomicInt m_state;
-
- bool m_writeFirstAudioBuffer;
-
- CMTime m_startTime;
- CMTime m_lastTimeStamp;
- CMTime m_lastVideoTimestamp;
- CMTime m_lastAudioTimestamp;
- CMTime m_timeOffset;
- bool m_adjustTime;
-
- NSDictionary *m_audioSettings;
- NSDictionary *m_videoSettings;
-
- AVFAtomicInt64 m_durationInMs;
-}
-
-- (id)initWithDelegate:(AVFMediaEncoder *)delegate
-{
- Q_ASSERT(delegate);
-
- if (self = [super init]) {
- m_delegate = delegate;
- m_setStartTime = true;
- m_state.storeRelaxed(WriterStateIdle);
- m_startTime = kCMTimeInvalid;
- m_lastTimeStamp = kCMTimeInvalid;
- m_lastAudioTimestamp = kCMTimeInvalid;
- m_lastVideoTimestamp = kCMTimeInvalid;
- m_timeOffset = kCMTimeInvalid;
- m_adjustTime = false;
- m_durationInMs.storeRelaxed(0);
- m_audioSettings = nil;
- m_videoSettings = nil;
- m_writeFirstAudioBuffer = false;
- }
-
- return self;
-}
-
-- (bool)setupWithFileURL:(NSURL *)fileURL
- cameraService:(AVFCameraService *)service
- audioSettings:(NSDictionary *)audioSettings
- videoSettings:(NSDictionary *)videoSettings
- fileFormat:(QMediaFormat::FileFormat)fileFormat
- transform:(CGAffineTransform)transform
-{
- Q_ASSERT(fileURL);
-
- if (!qt_capture_session_isValid(service)) {
- qDebugCamera() << Q_FUNC_INFO << "invalid capture session";
- return false;
- }
-
- m_service = service;
- m_audioSettings = audioSettings;
- m_videoSettings = videoSettings;
-
- AVFCameraSession *session = m_service->session();
-
- m_writerQueue.reset(dispatch_queue_create("asset-writer-queue", DISPATCH_QUEUE_SERIAL));
- if (!m_writerQueue) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer's queue";
- return false;
- }
-
- if (session->videoOutput() && session->videoOutput()->videoDataOutput()) {
- m_videoQueue.reset(dispatch_queue_create("video-output-queue", DISPATCH_QUEUE_SERIAL));
- if (!m_videoQueue) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create video queue";
- return false;
- }
- dispatch_set_target_queue(m_videoQueue, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0));
- }
-
- m_audioQueue.reset(dispatch_queue_create("audio-output-queue", DISPATCH_QUEUE_SERIAL));
- if (!m_audioQueue) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create audio queue";
- if (!m_videoQueue)
- return false;
- // But we still can write video!
- }
-
- auto fileType = QDarwinFormatInfo::avFileTypeForContainerFormat(fileFormat);
- m_assetWriter.reset([[AVAssetWriter alloc] initWithURL:fileURL
- fileType:fileType
- error:nil]);
- if (!m_assetWriter) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create asset writer";
- return false;
- }
-
- bool audioCaptureOn = false;
- if (m_audioQueue)
- audioCaptureOn = session->audioOutput() != nil;
-
- if (!m_videoQueue)
- m_writeFirstAudioBuffer = true;
-
- if (![self addWriterInputs]) {
- m_assetWriter.reset();
- return false;
- }
-
- if (m_cameraWriterInput)
- m_cameraWriterInput.data().transform = transform;
-
- [self setMetaData:fileType];
-
- // Ready to start ...
- return true;
-}
-
-- (void)setMetaData:(AVFileType)fileType
-{
- m_assetWriter.data().metadata = AVFMetaData::toAVMetadataForFormat(m_delegate->metaData(), fileType);
-}
-
-- (void)start
-{
- [self setQueues];
-
- m_setStartTime = true;
-
- m_state.storeRelease(WriterStateActive);
-
- [m_assetWriter startWriting];
- AVCaptureSession *session = m_service->session()->captureSession();
- if (!session.running)
- [session startRunning];
-}
-
-- (void)stop
-{
- if (m_state.loadAcquire() != WriterStateActive && m_state.loadAcquire() != WriterStatePaused)
- return;
- if ([m_assetWriter status] != AVAssetWriterStatusWriting)
- return;
-
- // Do this here so that -
- // 1. '-abort' should not try calling finishWriting again and
- // 2. async block (see below) will know if recorder control was deleted
- // before the block's execution:
- m_state.storeRelease(WriterStateIdle);
- // Now, since we have to ensure no sample buffers are
- // appended after a call to finishWriting, we must
- // ensure writer's queue sees this change in m_state
- // _before_ we call finishWriting:
- dispatch_sync(m_writerQueue, ^{});
- // Done, but now we also want to prevent video queue
- // from updating our viewfinder:
- if (m_videoQueue)
- dispatch_sync(m_videoQueue, ^{});
-
- // Now we're safe to stop:
- [m_assetWriter finishWritingWithCompletionHandler:^{
- // This block is async, so by the time it's executed,
- // it's possible that render control was deleted already ...
- if (m_state.loadAcquire() == WriterStateAborted)
- return;
-
- AVCaptureSession *session = m_service->session()->captureSession();
- if (session.running)
- [session stopRunning];
- QMetaObject::invokeMethod(m_delegate, "assetWriterFinished", Qt::QueuedConnection);
- }];
-}
-
-- (void)abort
-{
- // -abort is to be called from recorder control's dtor.
-
- if (m_state.fetchAndStoreRelease(WriterStateAborted) != WriterStateActive) {
- // Not recording, nothing to stop.
- return;
- }
-
- // From Apple's docs:
- // "To guarantee that all sample buffers are successfully written,
- // you must ensure that all calls to appendSampleBuffer: and
- // appendPixelBuffer:withPresentationTime: have returned before
- // invoking this method."
- //
- // The only way we can ensure this is:
- dispatch_sync(m_writerQueue, ^{});
- // At this point next block (if any) on the writer's queue
- // will see m_state preventing it from any further processing.
- if (m_videoQueue)
- dispatch_sync(m_videoQueue, ^{});
- // After this point video queue will not try to modify our
- // viewfider, so we're safe to delete now.
-
- [m_assetWriter finishWritingWithCompletionHandler:^{
- }];
-}
-
-- (void)pause
-{
- if (m_state.loadAcquire() != WriterStateActive)
- return;
- if ([m_assetWriter status] != AVAssetWriterStatusWriting)
- return;
-
- m_state.storeRelease(WriterStatePaused);
- m_adjustTime = true;
-}
-
-- (void)resume
-{
- if (m_state.loadAcquire() != WriterStatePaused)
- return;
- if ([m_assetWriter status] != AVAssetWriterStatusWriting)
- return;
-
- m_state.storeRelease(WriterStateActive);
-}
-
-- (void)setStartTimeFrom:(CMSampleBufferRef)sampleBuffer
-{
- // Writer's queue only.
- Q_ASSERT(m_setStartTime);
- Q_ASSERT(sampleBuffer);
-
- if (m_state.loadAcquire() != WriterStateActive)
- return;
-
- QMetaObject::invokeMethod(m_delegate, "assetWriterStarted", Qt::QueuedConnection);
-
- m_durationInMs.storeRelease(0);
- m_startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
- m_lastTimeStamp = m_startTime;
- [m_assetWriter startSessionAtSourceTime:m_startTime];
- m_setStartTime = false;
-}
-
-- (CMSampleBufferRef)adjustTime:(CMSampleBufferRef)sample by:(CMTime)offset
-{
- CMItemCount count;
- CMSampleBufferGetSampleTimingInfoArray(sample, 0, nil, &count);
- CMSampleTimingInfo* timingInfo = (CMSampleTimingInfo*) malloc(sizeof(CMSampleTimingInfo) * count);
- CMSampleBufferGetSampleTimingInfoArray(sample, count, timingInfo, &count);
- for (CMItemCount i = 0; i < count; i++)
- {
- timingInfo[i].decodeTimeStamp = CMTimeSubtract(timingInfo[i].decodeTimeStamp, offset);
- timingInfo[i].presentationTimeStamp = CMTimeSubtract(timingInfo[i].presentationTimeStamp, offset);
- }
- CMSampleBufferRef updatedBuffer;
- CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, sample, count, timingInfo, &updatedBuffer);
- free(timingInfo);
- return updatedBuffer;
-}
-
-- (void)writeVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer
-{
- // This code is executed only on a writer's queue.
- Q_ASSERT(sampleBuffer);
-
- if (m_state.loadAcquire() == WriterStateActive) {
- if (m_setStartTime)
- [self setStartTimeFrom:sampleBuffer];
-
- if (m_cameraWriterInput.data().readyForMoreMediaData) {
- [self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
- [m_cameraWriterInput appendSampleBuffer:sampleBuffer];
- }
- }
-}
-
-- (void)writeAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer
-{
- Q_ASSERT(sampleBuffer);
-
- // This code is executed only on a writer's queue.
- if (m_state.loadAcquire() == WriterStateActive) {
- if (m_setStartTime)
- [self setStartTimeFrom:sampleBuffer];
-
- if (m_audioWriterInput.data().readyForMoreMediaData) {
- [self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
- [m_audioWriterInput appendSampleBuffer:sampleBuffer];
- }
- }
-}
-
-- (void)captureOutput:(AVCaptureOutput *)captureOutput
- didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
- fromConnection:(AVCaptureConnection *)connection
-{
- Q_UNUSED(connection);
- Q_ASSERT(m_service && m_service->session());
-
- if (m_state.loadAcquire() != WriterStateActive && m_state.loadAcquire() != WriterStatePaused)
- return;
-
- if (!CMSampleBufferDataIsReady(sampleBuffer)) {
- qWarning() << Q_FUNC_INFO << "sample buffer is not ready, skipping.";
- return;
- }
-
- CFRetain(sampleBuffer);
-
- bool isVideoBuffer = true;
- isVideoBuffer = (captureOutput != m_service->session()->audioOutput());
- if (isVideoBuffer) {
- // Find renderercontrol's delegate and invoke its method to
- // show updated viewfinder's frame.
- if (m_service->session()->videoOutput()) {
- NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *vfDelegate =
- (NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *)m_service->session()->videoOutput()->captureDelegate();
- if (vfDelegate) {
- AVCaptureOutput *output = nil;
- AVCaptureConnection *connection = nil;
- [vfDelegate captureOutput:output didOutputSampleBuffer:sampleBuffer fromConnection:connection];
- }
- }
- } else {
- if (m_service->session()->audioOutput()) {
- NSObject<AVCaptureAudioDataOutputSampleBufferDelegate> *audioPreviewDelegate =
- (NSObject<AVCaptureAudioDataOutputSampleBufferDelegate> *)m_service->session()->audioPreviewDelegate();
- if (audioPreviewDelegate) {
- AVCaptureOutput *output = nil;
- AVCaptureConnection *connection = nil;
- [audioPreviewDelegate captureOutput:output didOutputSampleBuffer:sampleBuffer fromConnection:connection];
- }
- }
- }
-
- if (m_state.loadAcquire() != WriterStateActive) {
- CFRelease(sampleBuffer);
- return;
- }
-
- if (m_adjustTime) {
- CMTime currentTimestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
- CMTime lastTimestamp = isVideoBuffer ? m_lastVideoTimestamp : m_lastAudioTimestamp;
-
- if (!CMTIME_IS_INVALID(lastTimestamp)) {
- if (!CMTIME_IS_INVALID(m_timeOffset))
- currentTimestamp = CMTimeSubtract(currentTimestamp, m_timeOffset);
-
- CMTime pauseDuration = CMTimeSubtract(currentTimestamp, lastTimestamp);
-
- if (m_timeOffset.value == 0)
- m_timeOffset = pauseDuration;
- else
- m_timeOffset = CMTimeAdd(m_timeOffset, pauseDuration);
- }
- m_lastVideoTimestamp = kCMTimeInvalid;
- m_adjustTime = false;
- }
-
- if (m_timeOffset.value > 0) {
- CFRelease(sampleBuffer);
- sampleBuffer = [self adjustTime:sampleBuffer by:m_timeOffset];
- }
-
- CMTime currentTimestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
- CMTime currentDuration = CMSampleBufferGetDuration(sampleBuffer);
- if (currentDuration.value > 0)
- currentTimestamp = CMTimeAdd(currentTimestamp, currentDuration);
-
- if (isVideoBuffer)
- {
- m_lastVideoTimestamp = currentTimestamp;
- dispatch_async(m_writerQueue, ^{
- [self writeVideoSampleBuffer:sampleBuffer];
- m_writeFirstAudioBuffer = true;
- CFRelease(sampleBuffer);
- });
- } else if (m_writeFirstAudioBuffer) {
- m_lastAudioTimestamp = currentTimestamp;
- dispatch_async(m_writerQueue, ^{
- [self writeAudioSampleBuffer:sampleBuffer];
- CFRelease(sampleBuffer);
- });
- }
-}
-
-- (bool)addWriterInputs
-{
- Q_ASSERT(m_service && m_service->session());
- Q_ASSERT(m_assetWriter.data());
-
- AVFCameraSession *session = m_service->session();
-
- if (m_videoQueue)
- {
- Q_ASSERT(session->videoOutput() && session->videoOutput()->videoDataOutput());
- m_cameraWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo
- outputSettings:m_videoSettings
- sourceFormatHint:session->videoCaptureDevice().activeFormat.formatDescription]);
-
- if (!m_cameraWriterInput) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create camera writer input";
- return false;
- }
- if ([m_assetWriter canAddInput:m_cameraWriterInput]) {
- [m_assetWriter addInput:m_cameraWriterInput];
- } else {
- qDebugCamera() << Q_FUNC_INFO << "failed to add camera writer input";
- m_cameraWriterInput.reset();
- return false;
- }
-
- m_cameraWriterInput.data().expectsMediaDataInRealTime = YES;
- }
-
- if (session->audioOutput()) {
- CMFormatDescriptionRef sourceFormat = session->audioCaptureDevice()
- ? session->audioCaptureDevice().activeFormat.formatDescription
- : 0;
- m_audioWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio
- outputSettings:m_audioSettings
- sourceFormatHint:sourceFormat]);
- if (!m_audioWriterInput) {
- qWarning() << Q_FUNC_INFO << "failed to create audio writer input";
- // But we still can record video.
- if (!m_cameraWriterInput)
- return false;
- } else if ([m_assetWriter canAddInput:m_audioWriterInput]) {
- [m_assetWriter addInput:m_audioWriterInput];
- m_audioWriterInput.data().expectsMediaDataInRealTime = YES;
- } else {
- qWarning() << Q_FUNC_INFO << "failed to add audio writer input";
- m_audioWriterInput.reset();
- if (!m_cameraWriterInput)
- return false;
- // We can (still) write video though ...
- }
- }
-
- return true;
-}
-
-- (void)setQueues
-{
- Q_ASSERT(m_service && m_service->session());
- if (m_videoQueue) {
- Q_ASSERT(m_service->session()->videoOutput()
- && m_service->session()->videoOutput()->videoDataOutput());
- [m_service->session()->videoOutput()->videoDataOutput() setSampleBufferDelegate:self queue:m_videoQueue];
- }
-
- if (m_service->session()->audioOutput()) {
- Q_ASSERT(m_audioQueue);
- [m_service->session()->audioOutput() setSampleBufferDelegate:self queue:m_audioQueue];
- }
-}
-
-- (void)updateDuration:(CMTime)newTimeStamp
-{
- Q_ASSERT(CMTimeCompare(m_startTime, kCMTimeInvalid));
- Q_ASSERT(CMTimeCompare(m_lastTimeStamp, kCMTimeInvalid));
- if (CMTimeCompare(newTimeStamp, m_lastTimeStamp) > 0) {
-
- const CMTime duration = CMTimeSubtract(newTimeStamp, m_startTime);
- if (!CMTimeCompare(duration, kCMTimeInvalid))
- return;
-
- m_durationInMs.storeRelease(CMTimeGetSeconds(duration) * 1000);
- m_lastTimeStamp = newTimeStamp;
-
- m_delegate->updateDuration([self durationInMs]);
- }
-}
-
-- (qint64)durationInMs
-{
- return m_durationInMs.loadAcquire();
-}
-
-@end
diff --git a/src/multimedia/platform/darwin/camera/avfmediaassetwriter_p.h b/src/multimedia/platform/darwin/camera/avfmediaassetwriter_p.h
deleted file mode 100644
index 6691b66a1..000000000
--- a/src/multimedia/platform/darwin/camera/avfmediaassetwriter_p.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFMEDIAASSETWRITER_H
-#define AVFMEDIAASSETWRITER_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 "avfcamerautility_p.h"
-#include "qmediaformat.h"
-
-#include <QtCore/qglobal.h>
-
-#include <AVFoundation/AVFoundation.h>
-
-QT_BEGIN_NAMESPACE
-
-class AVFMediaEncoder;
-class AVFCameraService;
-
-QT_END_NAMESPACE
-
-@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate,
- AVCaptureAudioDataOutputSampleBufferDelegate>
-- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(AVFMediaEncoder) *)delegate;
-
-- (bool)setupWithFileURL:(NSURL *)fileURL
- cameraService:(QT_PREPEND_NAMESPACE(AVFCameraService) *)service
- audioSettings:(NSDictionary *)audioSettings
- videoSettings:(NSDictionary *)videoSettings
- fileFormat:(QMediaFormat::FileFormat)fileFormat
- transform:(CGAffineTransform)transform;
-
-// This to be called from the recorder control's thread:
-- (void)start;
-- (void)stop;
-- (void)pause;
-- (void)resume;
-// This to be called from the recorder control's dtor:
-- (void)abort;
-- (qint64)durationInMs;
-
-@end
-
-#endif // AVFMEDIAASSETWRITER_H
diff --git a/src/multimedia/platform/darwin/camera/avfmediaencoder.mm b/src/multimedia/platform/darwin/camera/avfmediaencoder.mm
deleted file mode 100644
index 83e9c6d3d..000000000
--- a/src/multimedia/platform/darwin/camera/avfmediaencoder.mm
+++ /dev/null
@@ -1,649 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include "avfmediaencoder_p.h"
-#include "avfcamerarenderer_p.h"
-#include "avfcamerasession_p.h"
-#include "avfcamera_p.h"
-#include "avfcameraservice_p.h"
-#include "avfcameradebug_p.h"
-#include "avfcamerautility_p.h"
-#include "qaudiodevice.h"
-
-#include "qmediadevices.h"
-#include "qmediastoragelocation_p.h"
-#include "private/qmediarecorder_p.h"
-#include "private/qdarwinformatsinfo_p.h"
-#include "private/qplatformaudiooutput_p.h"
-
-#include <QtCore/qmath.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmimetype.h>
-
-QT_USE_NAMESPACE
-
-namespace {
-
-bool qt_is_writable_file_URL(NSURL *fileURL)
-{
- Q_ASSERT(fileURL);
-
- if (![fileURL isFileURL])
- return false;
-
- if (NSString *path = [[fileURL path] stringByExpandingTildeInPath]) {
- return [[NSFileManager defaultManager]
- isWritableFileAtPath:[path stringByDeletingLastPathComponent]];
- }
-
- return false;
-}
-
-bool qt_file_exists(NSURL *fileURL)
-{
- Q_ASSERT(fileURL);
-
- if (NSString *path = [[fileURL path] stringByExpandingTildeInPath])
- return [[NSFileManager defaultManager] fileExistsAtPath:path];
-
- return false;
-}
-
-}
-
-AVFMediaEncoder::AVFMediaEncoder(QMediaRecorder *parent)
- : QObject(parent)
- , QPlatformMediaEncoder(parent)
- , m_state(QMediaRecorder::StoppedState)
- , m_duration(0)
- , m_audioSettings(nil)
- , m_videoSettings(nil)
- //, m_restoreFPS(-1, -1)
-{
- m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithDelegate:this]);
- if (!m_writer) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer";
- return;
- }
-}
-
-AVFMediaEncoder::~AVFMediaEncoder()
-{
- [m_writer abort];
-
- if (m_audioSettings)
- [m_audioSettings release];
- if (m_videoSettings)
- [m_videoSettings release];
-}
-
-bool AVFMediaEncoder::isLocationWritable(const QUrl &location) const
-{
- return location.scheme() == QLatin1String("file") || location.scheme().isEmpty();
-}
-
-QMediaRecorder::RecorderState AVFMediaEncoder::state() const
-{
- return m_state;
-}
-
-qint64 AVFMediaEncoder::duration() const
-{
- return m_duration;
-}
-
-void AVFMediaEncoder::updateDuration(qint64 duration)
-{
- m_duration = duration;
- durationChanged(m_duration);
-}
-
-static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettings)
-{
- NSMutableDictionary *settings = [NSMutableDictionary dictionary];
-
- int codecId = QDarwinFormatInfo::audioFormatForCodec(encoderSettings.mediaFormat().audioCodec());
- [settings setObject:[NSNumber numberWithInt:codecId] forKey:AVFormatIDKey];
-
- // Setting AVEncoderQualityKey is not allowed when format ID is alac or lpcm
- if (codecId != kAudioFormatAppleLossless && codecId != kAudioFormatLinearPCM
- && encoderSettings.encodingMode() == QMediaRecorder::ConstantQualityEncoding) {
- int quality;
- switch (encoderSettings.quality()) {
- case QMediaRecorder::VeryLowQuality:
- quality = AVAudioQualityMin;
- break;
- case QMediaRecorder::LowQuality:
- quality = AVAudioQualityLow;
- break;
- case QMediaRecorder::HighQuality:
- quality = AVAudioQualityHigh;
- break;
- case QMediaRecorder::VeryHighQuality:
- quality = AVAudioQualityMax;
- break;
- case QMediaRecorder::NormalQuality:
- default:
- quality = AVAudioQualityMedium;
- break;
- }
- [settings setObject:[NSNumber numberWithInt:quality] forKey:AVEncoderAudioQualityKey];
- } else {
- bool isBitRateSupported = false;
- int bitRate = encoderSettings.audioBitRate();
- if (bitRate > 0) {
- QList<AudioValueRange> bitRates = qt_supported_bit_rates_for_format(codecId);
- for (int i = 0; i < bitRates.count(); i++) {
- if (bitRate >= bitRates[i].mMinimum &&
- bitRate <= bitRates[i].mMaximum) {
- isBitRateSupported = true;
- break;
- }
- }
- if (isBitRateSupported)
- [settings setObject:[NSNumber numberWithInt:encoderSettings.audioBitRate()]
- forKey:AVEncoderBitRateKey];
- }
- }
-
- int sampleRate = encoderSettings.audioSampleRate();
- bool isSampleRateSupported = false;
- if (sampleRate >= 8000 && sampleRate <= 192000) {
- QList<AudioValueRange> sampleRates = qt_supported_sample_rates_for_format(codecId);
- for (int i = 0; i < sampleRates.count(); i++) {
- if (sampleRate >= sampleRates[i].mMinimum && sampleRate <= sampleRates[i].mMaximum) {
- isSampleRateSupported = true;
- break;
- }
- }
- }
-
- int channelCount = encoderSettings.audioChannelCount();
- bool isChannelCountSupported = false;
- if (channelCount > 0) {
- std::optional<QList<UInt32>> channelCounts = qt_supported_channel_counts_for_format(codecId);
- // An std::nullopt result indicates that
- // any number of channels can be encoded.
- if (channelCounts == std::nullopt) {
- isChannelCountSupported = true;
- } else {
- for (int i = 0; i < channelCounts.value().count(); i++) {
- if ((UInt32)channelCount == channelCounts.value()[i]) {
- isChannelCountSupported = true;
- break;
- }
- }
- }
- }
-
-#ifdef Q_OS_IOS
- // Some keys are mandatory only on iOS
- if (!isSampleRateSupported) {
- sampleRate = 44100;
- isSampleRateSupported = true;
- }
- if (!isChannelCountSupported) {
- channelCount = 2;
- isChannelCountSupported = true;
- }
-
- if (codecId == kAudioFormatAppleLossless)
- [settings setObject:[NSNumber numberWithInt:24] forKey:AVEncoderBitDepthHintKey];
-
- if (codecId == kAudioFormatLinearPCM) {
- [settings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
- [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsBigEndianKey];
- [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsFloatKey];
- [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsNonInterleaved];
- }
-#endif
- if (isSampleRateSupported)
- [settings setObject:[NSNumber numberWithInt:sampleRate] forKey:AVSampleRateKey];
- if (isChannelCountSupported)
- [settings setObject:[NSNumber numberWithInt:channelCount] forKey:AVNumberOfChannelsKey];
-
- return settings;
-}
-
-NSDictionary *avfVideoSettings(QMediaEncoderSettings &encoderSettings, AVCaptureDevice *device, AVCaptureConnection *connection, QSize nativeSize)
-{
- if (!device)
- return nil;
-
-
- // ### re-add needFpsChange
-// AVFPSRange currentFps = qt_current_framerates(device, connection);
-
- NSMutableDictionary *videoSettings = [NSMutableDictionary dictionary];
-
- // -- Codec
-
- // AVVideoCodecKey is the only mandatory key
- auto codec = encoderSettings.mediaFormat().videoCodec();
- NSString *c = QDarwinFormatInfo::videoFormatForCodec(codec);
- [videoSettings setObject:c forKey:AVVideoCodecKey];
- [c release];
-
- // -- Resolution
-
- int w = encoderSettings.videoResolution().width();
- int h = encoderSettings.videoResolution().height();
-
- if (AVCaptureDeviceFormat *currentFormat = device.activeFormat) {
- CMFormatDescriptionRef formatDesc = currentFormat.formatDescription;
- CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDesc);
- FourCharCode formatCodec = CMVideoFormatDescriptionGetCodecType(formatDesc);
-
- // We have to change the device's activeFormat in 3 cases:
- // - the requested recording resolution is higher than the current device resolution
- // - the requested recording resolution has a different aspect ratio than the current device aspect ratio
- // - the requested frame rate is not available for the current device format
- AVCaptureDeviceFormat *newFormat = nil;
- if ((w <= 0 || h <= 0)
- && encoderSettings.videoFrameRate() > 0
- && !qt_format_supports_framerate(currentFormat, encoderSettings.videoFrameRate())) {
-
- newFormat = qt_find_best_framerate_match(device,
- formatCodec,
- encoderSettings.videoFrameRate());
-
- } else if (w > 0 && h > 0) {
- AVCaptureDeviceFormat *f = qt_find_best_resolution_match(device,
- encoderSettings.videoResolution(),
- formatCodec);
-
- if (f) {
- CMVideoDimensions d = CMVideoFormatDescriptionGetDimensions(f.formatDescription);
- qreal fAspectRatio = qreal(d.width) / d.height;
-
- if (w > dim.width || h > dim.height
- || qAbs((qreal(dim.width) / dim.height) - fAspectRatio) > 0.01) {
- newFormat = f;
- }
- }
- }
-
- if (qt_set_active_format(device, newFormat, false /*### !needFpsChange*/)) {
- formatDesc = newFormat.formatDescription;
- dim = CMVideoFormatDescriptionGetDimensions(formatDesc);
- }
-
- if (w > 0 && h > 0) {
- // Make sure the recording resolution has the same aspect ratio as the device's
- // current resolution
- qreal deviceAspectRatio = qreal(dim.width) / dim.height;
- qreal recAspectRatio = qreal(w) / h;
- if (qAbs(deviceAspectRatio - recAspectRatio) > 0.01) {
- if (recAspectRatio > deviceAspectRatio)
- w = qRound(h * deviceAspectRatio);
- else
- h = qRound(w / deviceAspectRatio);
- }
-
- // recording resolution can't be higher than the device's active resolution
- w = qMin(w, dim.width);
- h = qMin(h, dim.height);
- }
- }
-
- if (w > 0 && h > 0) {
- // Width and height must be divisible by 2
- w += w & 1;
- h += h & 1;
-
- bool isPortrait = nativeSize.width() < nativeSize.height();
- // Make sure the video has the right aspect ratio
- if (isPortrait && h < w)
- qSwap(w, h);
- else if (!isPortrait && w < h)
- qSwap(w, h);
-
- encoderSettings.setVideoResolution(QSize(w, h));
- } else {
- w = nativeSize.width();
- h = nativeSize.height();
- encoderSettings.setVideoResolution(nativeSize);
- }
- [videoSettings setObject:[NSNumber numberWithInt:w] forKey:AVVideoWidthKey];
- [videoSettings setObject:[NSNumber numberWithInt:h] forKey:AVVideoHeightKey];
-
- // -- FPS
-
- if (true /*needFpsChange*/) {
- const qreal fps = encoderSettings.videoFrameRate();
- qt_set_framerate_limits(device, connection, fps, fps);
- }
- encoderSettings.setVideoFrameRate(qt_current_framerates(device, connection).second);
-
- // -- Codec Settings
-
- NSMutableDictionary *codecProperties = [NSMutableDictionary dictionary];
- int bitrate = -1;
- float quality = -1.f;
-
- if (encoderSettings.encodingMode() == QMediaRecorder::ConstantQualityEncoding) {
- if (encoderSettings.quality() != QMediaRecorder::NormalQuality) {
- if (codec != QMediaFormat::VideoCodec::MotionJPEG) {
- qWarning("ConstantQualityEncoding is not supported for MotionJPEG");
- } else {
- switch (encoderSettings.quality()) {
- case QMediaRecorder::VeryLowQuality:
- quality = 0.f;
- break;
- case QMediaRecorder::LowQuality:
- quality = 0.25f;
- break;
- case QMediaRecorder::HighQuality:
- quality = 0.75f;
- break;
- case QMediaRecorder::VeryHighQuality:
- quality = 1.f;
- break;
- default:
- quality = -1.f; // NormalQuality, let the system decide
- break;
- }
- }
- }
- } else if (encoderSettings.encodingMode() == QMediaRecorder::AverageBitRateEncoding){
- if (codec != QMediaFormat::VideoCodec::H264 && codec != QMediaFormat::VideoCodec::H265)
- qWarning() << "AverageBitRateEncoding is not supported for codec" << QMediaFormat::videoCodecName(codec);
- else
- bitrate = encoderSettings.videoBitRate();
- } else {
- qWarning("Encoding mode is not supported");
- }
-
- if (bitrate != -1)
- [codecProperties setObject:[NSNumber numberWithInt:bitrate] forKey:AVVideoAverageBitRateKey];
- if (quality != -1.f)
- [codecProperties setObject:[NSNumber numberWithFloat:quality] forKey:AVVideoQualityKey];
-
- [videoSettings setObject:codecProperties forKey:AVVideoCompressionPropertiesKey];
-
- return videoSettings;
-}
-
-void AVFMediaEncoder::applySettings(QMediaEncoderSettings &settings)
-{
- AVFCameraSession *session = m_service->session();
-
- // audio settings
- m_audioSettings = avfAudioSettings(settings);
- if (m_audioSettings)
- [m_audioSettings retain];
-
- // video settings
- AVCaptureDevice *device = session->videoCaptureDevice();
- if (!device)
- return;
- const AVFConfigurationLock lock(device); // prevents activeFormat from being overridden
- AVCaptureConnection *conn = [session->videoOutput()->videoDataOutput() connectionWithMediaType:AVMediaTypeVideo];
- auto nativeSize = session->videoOutput()->nativeSize();
- m_videoSettings = avfVideoSettings(settings, device, conn, nativeSize);
- if (m_videoSettings)
- [m_videoSettings retain];
-}
-
-void AVFMediaEncoder::unapplySettings()
-{
- if (m_audioSettings) {
- [m_audioSettings release];
- m_audioSettings = nil;
- }
- if (m_videoSettings) {
- [m_videoSettings release];
- m_videoSettings = nil;
- }
-}
-
-void AVFMediaEncoder::setMetaData(const QMediaMetaData &metaData)
-{
- m_metaData = metaData;
-}
-
-QMediaMetaData AVFMediaEncoder::metaData() const
-{
- return m_metaData;
-}
-
-void AVFMediaEncoder::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- AVFCameraService *captureSession = static_cast<AVFCameraService *>(session);
- if (m_service == captureSession)
- return;
-
- if (m_service)
- stop();
-
- m_service = captureSession;
- if (!m_service)
- return;
-
- connect(m_service, &AVFCameraService::cameraChanged, this, &AVFMediaEncoder::onCameraChanged);
- onCameraChanged();
-}
-
-void AVFMediaEncoder::record(QMediaEncoderSettings &settings)
-{
- if (!m_service || !m_service->session()) {
- qWarning() << Q_FUNC_INFO << "Encoder is not set to a capture session";
- return;
- }
-
- if (!m_writer) {
- qDebugCamera() << Q_FUNC_INFO << "Invalid recorder";
- return;
- }
-
- if (QMediaRecorder::RecordingState == m_state)
- return;
-
- m_service->session()->setActive(true);
- const bool audioOnly = settings.videoCodec() == QMediaFormat::VideoCodec::Unspecified;
- AVCaptureSession *session = m_service->session()->captureSession();
- float rotation = 0;
-
- if (!audioOnly) {
- AVFCamera *cameraControl = m_service->avfCameraControl();
- if (!cameraControl || !cameraControl->isActive()) {
- qDebugCamera() << Q_FUNC_INFO << "can not start record while camera is not active";
- Q_EMIT error(QMediaRecorder::ResourceError,
- QMediaRecorderPrivate::msgFailedStartRecording());
- return;
- }
- }
-
- const QString path(outputLocation().scheme() == QLatin1String("file") ?
- outputLocation().path() : outputLocation().toString());
- const QUrl fileURL(QUrl::fromLocalFile(QMediaStorageLocation::generateFileName(path,
- audioOnly ? QStandardPaths::MusicLocation : QStandardPaths::MoviesLocation,
- settings.mimeType().preferredSuffix())));
-
- NSURL *nsFileURL = fileURL.toNSURL();
- if (!nsFileURL) {
- qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL;
- Q_EMIT error(QMediaRecorder::ResourceError, tr("Invalid output file URL"));
- return;
- }
- if (!qt_is_writable_file_URL(nsFileURL)) {
- qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
- << "(the location is not writable)";
- Q_EMIT error(QMediaRecorder::ResourceError, tr("Non-writeable file location"));
- return;
- }
- if (qt_file_exists(nsFileURL)) {
- // We test for/handle this error here since AWAssetWriter will raise an
- // Objective-C exception, which is not good at all.
- qWarning() << Q_FUNC_INFO << "invalid output URL:" << fileURL
- << "(file already exists)";
- Q_EMIT error(QMediaRecorder::ResourceError, tr("File already exists"));
- return;
- }
-
- applySettings(settings);
-
- QVideoOutputOrientationHandler::setIsRecording(true);
-
- // We stop session now so that no more frames for renderer's queue
- // generated, will restart in assetWriterStarted.
- [session stopRunning];
-
- if ([m_writer setupWithFileURL:nsFileURL
- cameraService:m_service
- audioSettings:m_audioSettings
- videoSettings:m_videoSettings
- fileFormat:settings.fileFormat()
- transform:CGAffineTransformMakeRotation(qDegreesToRadians(rotation))]) {
-
- m_state = QMediaRecorder::RecordingState;
-
- Q_EMIT actualLocationChanged(fileURL);
- Q_EMIT stateChanged(m_state);
-
- // Apple recommends to call startRunning and do all
- // setup on a special queue, and that's what we had
- // initially (dispatch_async to writerQueue). Unfortunately,
- // writer's queue is not the only queue/thread that can
- // access/modify the session, and as a result we have
- // all possible data/race-conditions with Obj-C exceptions
- // at best and something worse in general.
- // Now we try to only modify session on the same thread.
- [m_writer start];
- } else {
- [session startRunning];
- Q_EMIT error(QMediaRecorder::FormatError,
- QMediaRecorderPrivate::msgFailedStartRecording());
- }
-}
-
-void AVFMediaEncoder::pause()
-{
- if (!m_service || !m_service->session() || state() != QMediaRecorder::RecordingState)
- return;
-
- toggleRecord(false);
- m_state = QMediaRecorder::PausedState;
- stateChanged(m_state);
-}
-
-void AVFMediaEncoder::resume()
-{
- if (!m_service || !m_service->session() || state() != QMediaRecorder::PausedState)
- return;
-
- toggleRecord(true);
- m_state = QMediaRecorder::RecordingState;
- stateChanged(m_state);
-}
-
-void AVFMediaEncoder::stop()
-{
- if (m_state != QMediaRecorder::StoppedState) {
- // Do not check the camera status, we can stop if we started.
- stopWriter();
- }
- QVideoOutputOrientationHandler::setIsRecording(false);
-}
-
-
-void AVFMediaEncoder::toggleRecord(bool enable)
-{
- if (!m_service || !m_service->session())
- return;
-
- if (!enable)
- [m_writer pause];
- else
- [m_writer resume];
-}
-
-void AVFMediaEncoder::assetWriterStarted()
-{
-}
-
-void AVFMediaEncoder::assetWriterFinished()
-{
- Q_ASSERT(m_service && m_service->session());
- AVFCameraSession *session = m_service->session();
-
- const QMediaRecorder::RecorderState lastState = m_state;
-
- unapplySettings();
-
- if (session->videoOutput()) {
- session->videoOutput()->resetCaptureDelegate();
- }
- if (session->audioPreviewDelegate()) {
- [session->audioPreviewDelegate() resetAudioPreviewDelegate];
- }
- [session->captureSession() startRunning];
-
- m_state = QMediaRecorder::StoppedState;
- if (m_state != lastState)
- Q_EMIT stateChanged(m_state);
-}
-
-void AVFMediaEncoder::onCameraChanged()
-{
- if (m_service && m_service->avfCameraControl()) {
- AVFCamera *cameraControl = m_service->avfCameraControl();
- connect(cameraControl, SIGNAL(activeChanged(bool)),
- SLOT(cameraActiveChanged(bool)));
- }
-}
-
-void AVFMediaEncoder::cameraActiveChanged(bool active)
-{
- Q_ASSERT(m_service);
- AVFCamera *cameraControl = m_service->avfCameraControl();
- Q_ASSERT(cameraControl);
-
- if (!active) {
- return stopWriter();
- }
-}
-
-void AVFMediaEncoder::stopWriter()
-{
- [m_writer stop];
-}
-
-#include "moc_avfmediaencoder_p.cpp"
diff --git a/src/multimedia/platform/darwin/camera/avfmediaencoder_p.h b/src/multimedia/platform/darwin/camera/avfmediaencoder_p.h
deleted file mode 100644
index 9e80c4c13..000000000
--- a/src/multimedia/platform/darwin/camera/avfmediaencoder_p.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFMEDIAENCODER_H
-#define AVFMEDIAENCODER_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 "avfmediaassetwriter_p.h"
-#include "avfcamerautility_p.h"
-#include "qaudiodevice.h"
-
-#include <private/qplatformmediaencoder_p.h>
-#include <private/qplatformmediacapture_p.h>
-#include <QtMultimedia/qmediametadata.h>
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qurl.h>
-
-#include <AVFoundation/AVFoundation.h>
-
-QT_BEGIN_NAMESPACE
-
-class AVFCameraService;
-class QString;
-class QUrl;
-
-class AVFMediaEncoder : public QObject, public QPlatformMediaEncoder
-{
- Q_OBJECT
-public:
- AVFMediaEncoder(QMediaRecorder *parent);
- ~AVFMediaEncoder() override;
-
- bool isLocationWritable(const QUrl &location) const override;
-
- QMediaRecorder::RecorderState state() const override;
-
- qint64 duration() const override;
-
- void record(QMediaEncoderSettings &settings) override;
- void pause() override;
- void resume() override;
- void stop() override;
-
- void setMetaData(const QMediaMetaData &) override;
- QMediaMetaData metaData() const override;
-
- AVFCameraService *cameraService() const { return m_service; }
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
- void updateDuration(qint64 duration);
-
- void toggleRecord(bool enable);
-
-private:
- void applySettings(QMediaEncoderSettings &settings);
- void unapplySettings();
-
- Q_INVOKABLE void assetWriterStarted();
- Q_INVOKABLE void assetWriterFinished();
-
-private Q_SLOTS:
- void onCameraChanged();
- void cameraActiveChanged(bool);
-
-private:
- void stopWriter();
-
- AVFCameraService *m_service = nullptr;
- AVFScopedPointer<QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)> m_writer;
-
- QMediaRecorder::RecorderState m_state;
-
- QMediaMetaData m_metaData;
-
- qint64 m_duration;
-
- NSDictionary *m_audioSettings;
- NSDictionary *m_videoSettings;
-};
-
-QT_END_NAMESPACE
-
-#endif // AVFMEDIAENCODER_H
diff --git a/src/multimedia/platform/darwin/common/avfmetadata.mm b/src/multimedia/platform/darwin/common/avfmetadata.mm
deleted file mode 100644
index ea95bcea6..000000000
--- a/src/multimedia/platform/darwin/common/avfmetadata.mm
+++ /dev/null
@@ -1,398 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfmetadata_p.h"
-#include <private/qdarwinformatsinfo_p.h>
-
-#include <QtCore/qbuffer.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qlocale.h>
-#include <QtCore/qurl.h>
-#include <QImage>
-
-#if QT_HAS_INCLUDE(<AppKit/AppKit.h>)
-#include <AppKit/AppKit.h>
-#endif
-
-#include <CoreFoundation/CoreFoundation.h>
-
-QT_USE_NAMESPACE
-
-struct AVMetadataIDs {
- AVMetadataIdentifier common;
- AVMetadataIdentifier iTunes;
- AVMetadataIdentifier quickTime;
- AVMetadataIdentifier ID3;
- AVMetadataIdentifier quickTimeUserData;
- AVMetadataIdentifier isoUserData;
-};
-
-const AVMetadataIDs keyToAVMetaDataID[] = {
- // Title
- { AVMetadataCommonIdentifierTitle, AVMetadataIdentifieriTunesMetadataSongName,
- AVMetadataIdentifierQuickTimeMetadataTitle,
- AVMetadataIdentifierID3MetadataTitleDescription,
- nil, AVMetadata3GPUserDataKeyTitle },
- // Author
- { AVMetadataCommonIdentifierAuthor,AVMetadataIdentifieriTunesMetadataAuthor,
- AVMetadataIdentifierQuickTimeMetadataAuthor, nil,
- AVMetadataQuickTimeUserDataKeyAuthor, AVMetadata3GPUserDataKeyAuthor },
- // Comment
- { nil, AVMetadataIdentifieriTunesMetadataUserComment,
- AVMetadataIdentifierQuickTimeMetadataComment, AVMetadataIdentifierID3MetadataComments,
- AVMetadataQuickTimeUserDataKeyComment, nil },
- // Description
- { AVMetadataCommonIdentifierDescription,AVMetadataIdentifieriTunesMetadataDescription,
- AVMetadataIdentifierQuickTimeMetadataDescription, nil,
- AVMetadataQuickTimeUserDataKeyDescription, AVMetadata3GPUserDataKeyDescription },
- // Genre
- { nil, AVMetadataIdentifieriTunesMetadataUserGenre,
- AVMetadataIdentifierQuickTimeMetadataGenre, nil,
- AVMetadataQuickTimeUserDataKeyGenre, AVMetadata3GPUserDataKeyGenre },
- // Date
- { AVMetadataCommonIdentifierCreationDate, AVMetadataIdentifieriTunesMetadataReleaseDate,
- AVMetadataIdentifierQuickTimeMetadataCreationDate, AVMetadataIdentifierID3MetadataDate,
- AVMetadataQuickTimeUserDataKeyCreationDate, AVMetadataISOUserDataKeyDate },
- // Language
- { AVMetadataCommonIdentifierLanguage, nil, nil, AVMetadataIdentifierID3MetadataLanguage, nil, nil },
- // Publisher
- { AVMetadataCommonIdentifierPublisher, AVMetadataIdentifieriTunesMetadataPublisher,
- AVMetadataIdentifierQuickTimeMetadataPublisher, AVMetadataIdentifierID3MetadataPublisher, nil, nil },
- // Copyright
- { AVMetadataCommonIdentifierCopyrights, AVMetadataIdentifieriTunesMetadataCopyright,
- AVMetadataIdentifierQuickTimeMetadataCopyright, AVMetadataIdentifierID3MetadataCopyright,
- AVMetadataQuickTimeUserDataKeyCopyright, AVMetadataISOUserDataKeyCopyright },
- // Url
- { nil, nil, nil, AVMetadataIdentifierID3MetadataOfficialAudioSourceWebpage, nil, nil },
- // Duration
- { nil, nil, nil, AVMetadataIdentifierID3MetadataLength, nil, nil },
- // MediaType
- { AVMetadataCommonIdentifierType, nil, nil, AVMetadataIdentifierID3MetadataContentType, nil, nil },
- // FileFormat
- { nil, nil, nil, AVMetadataIdentifierID3MetadataFileType, nil, nil },
- // AudioBitRate
- { nil, nil, nil, nil, nil, nil },
- // AudioCodec
- { nil, nil, nil, nil, nil, nil },
- // VideoBitRate
- { nil, nil, nil, nil, nil, nil },
- // VideoCodec
- { nil, nil, nil, nil, nil, nil },
- // VideoFrameRate
- { nil, nil, AVMetadataIdentifierQuickTimeMetadataCameraFrameReadoutTime, nil, nil, nil },
- // AlbumTitle
- { AVMetadataCommonIdentifierAlbumName, AVMetadataIdentifieriTunesMetadataAlbum,
- AVMetadataIdentifierQuickTimeMetadataAlbum, AVMetadataIdentifierID3MetadataAlbumTitle,
- AVMetadataQuickTimeUserDataKeyAlbum, AVMetadata3GPUserDataKeyAlbumAndTrack },
- // AlbumArtist
- { nil, AVMetadataIdentifieriTunesMetadataAlbumArtist, nil, nil,
- AVMetadataQuickTimeUserDataKeyArtist, AVMetadata3GPUserDataKeyPerformer },
- // ContributingArtist
- { AVMetadataCommonIdentifierArtist, AVMetadataIdentifieriTunesMetadataArtist,
- AVMetadataIdentifierQuickTimeMetadataArtist, nil, nil, nil },
- // TrackNumber
- { nil, AVMetadataIdentifieriTunesMetadataTrackNumber,
- nil, AVMetadataIdentifierID3MetadataTrackNumber, nil, nil },
- // Composer
- { nil, AVMetadataIdentifieriTunesMetadataComposer,
- AVMetadataIdentifierQuickTimeMetadataComposer, AVMetadataIdentifierID3MetadataComposer, nil, nil },
- // LeadPerformer
- { nil, AVMetadataIdentifieriTunesMetadataPerformer,
- AVMetadataIdentifierQuickTimeMetadataPerformer, AVMetadataIdentifierID3MetadataLeadPerformer, nil, nil },
- // ThumbnailImage
- { nil, nil, nil, AVMetadataIdentifierID3MetadataAttachedPicture, nil, nil },
- // CoverArtImage
- { AVMetadataCommonIdentifierArtwork, AVMetadataIdentifieriTunesMetadataCoverArt,
- AVMetadataIdentifierQuickTimeMetadataArtwork, nil, nil, nil },
- // Orientation
- { nil, nil, AVMetadataIdentifierQuickTimeMetadataDirectionFacing, nil, nil, nil },
- // Resolution
- { nil, nil, nil, nil, nil, nil }
-};
-
-static AVMetadataIdentifier toIdentifier(QMediaMetaData::Key key, AVMetadataKeySpace keySpace)
-{
- static_assert(sizeof(keyToAVMetaDataID)/sizeof(AVMetadataIDs) == QMediaMetaData::Key::Resolution + 1);
-
- AVMetadataIdentifier identifier = nil;
- if ([keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
- identifier = keyToAVMetaDataID[key].iTunes;
- } else if ([keySpace isEqualToString:AVMetadataKeySpaceID3]) {
- identifier = keyToAVMetaDataID[key].ID3;
- } else if ([keySpace isEqualToString:AVMetadataKeySpaceQuickTimeMetadata]) {
- identifier = keyToAVMetaDataID[key].quickTime;
- } else {
- identifier = keyToAVMetaDataID[key].common;
- }
- return identifier;
-}
-
-static std::optional<QMediaMetaData::Key> toKey(AVMetadataItem *item)
-{
- static_assert(sizeof(keyToAVMetaDataID)/sizeof(AVMetadataIDs) == QMediaMetaData::Key::Resolution + 1);
-
- // The item identifier may be different than the ones we support,
- // so check by common key first, as it will get the metadata
- // irrespective of the format.
- AVMetadataKey commonKey = item.commonKey;
- if (commonKey.length != 0) {
- if ([commonKey isEqualToString:AVMetadataCommonKeyTitle]) {
- return QMediaMetaData::Title;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyDescription]) {
- return QMediaMetaData::Description;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyPublisher]) {
- return QMediaMetaData::Publisher;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyCreationDate]) {
- return QMediaMetaData::Date;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyType]) {
- return QMediaMetaData::MediaType;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyLanguage]) {
- return QMediaMetaData::Language;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyCopyrights]) {
- return QMediaMetaData::Copyright;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyAlbumName]) {
- return QMediaMetaData::AlbumTitle;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyAuthor]) {
- return QMediaMetaData::Author;
- } else if ([commonKey isEqualToString:AVMetadataCommonKeyArtist]) {
- return QMediaMetaData::ContributingArtist;
- }
- }
-
- // Check by identifier if no common key found
- // No need to check for the common keySpace since there's no common key
- enum keySpaces { iTunes, QuickTime, QuickTimeUserData, IsoUserData, ID3, Other } itemKeySpace;
- itemKeySpace = Other;
- AVMetadataKeySpace keySpace = [item keySpace];
- AVMetadataIdentifier identifier = [item identifier];
-
- if ([keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
- itemKeySpace = iTunes;
- } else if ([keySpace isEqualToString:AVMetadataKeySpaceQuickTimeMetadata]) {
- itemKeySpace = QuickTime;
- } else if ([keySpace isEqualToString:AVMetadataKeySpaceQuickTimeUserData]) {
- itemKeySpace = QuickTimeUserData;
- } else if ([keySpace isEqualToString:AVMetadataKeySpaceISOUserData]) {
- itemKeySpace = IsoUserData;
- } else if (([keySpace isEqualToString:AVMetadataKeySpaceID3])) {
- itemKeySpace = ID3;
- }
-
- for (int key = 0; key < QMediaMetaData::Resolution + 1; key++) {
- AVMetadataIdentifier idForKey = nil;
- switch (itemKeySpace) {
- case iTunes:
- idForKey = keyToAVMetaDataID[key].iTunes;
- break;
- case QuickTime:
- idForKey = keyToAVMetaDataID[key].quickTime;
- break;
- case ID3:
- idForKey = keyToAVMetaDataID[key].ID3;
- break;
- case QuickTimeUserData:
- idForKey = keyToAVMetaDataID[key].quickTimeUserData;
- break;
- case IsoUserData:
- idForKey = keyToAVMetaDataID[key].isoUserData;
- break;
- default:
- break;
- }
-
- if ([identifier isEqualToString:idForKey])
- return QMediaMetaData::Key(key);
- }
-
- return std::nullopt;
-}
-
-static QMediaMetaData fromAVMetadata(NSArray *metadataItems)
-{
- QMediaMetaData metadata;
-
- for (AVMetadataItem* item in metadataItems) {
- auto key = toKey(item);
- if (!key)
- continue;
-
- const QString value = QString::fromNSString([item stringValue]);
- if (!value.isNull())
- metadata.insert(*key, value);
- }
- return metadata;
-}
-
-QMediaMetaData AVFMetaData::fromAsset(AVAsset *asset)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- QMediaMetaData metadata = fromAVMetadata([asset metadata]);
-
- // add duration
- const CMTime time = [asset duration];
- const qint64 duration = static_cast<qint64>(float(time.value) / float(time.timescale) * 1000.0f);
- metadata.insert(QMediaMetaData::Duration, duration);
-
- return metadata;
-}
-
-QMediaMetaData AVFMetaData::fromAssetTrack(AVAssetTrack *asset)
-{
- QMediaMetaData metadata = fromAVMetadata([asset metadata]);
- if (metadata.value(QMediaMetaData::Language).isNull()) {
- auto *languageCode = asset.languageCode;
- if (languageCode) {
- // languageCode is encoded as ISO 639-2, which QLocale does not handle.
- // Convert it to 639-1 first.
- auto id = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorDefault,
- (__bridge CFStringRef)languageCode);
- QString lang = QString::fromCFString(id);
- CFRelease(id);
- metadata.insert(QMediaMetaData::Language, QLocale::codeToLanguage(lang));
- }
- }
- return metadata;
-}
-
-static AVMutableMetadataItem *setAVMetadataItemForKey(QMediaMetaData::Key key, const QVariant &value,
- AVMetadataKeySpace keySpace = AVMetadataKeySpaceCommon)
-{
- AVMetadataIdentifier identifier = toIdentifier(key, keySpace);
- if (!identifier.length)
- return nil;
-
- AVMutableMetadataItem *item = [AVMutableMetadataItem metadataItem];
- item.keySpace = keySpace;
- item.identifier = identifier;
-
- switch (key) {
- case QMediaMetaData::ThumbnailImage:
- case QMediaMetaData::CoverArtImage: {
-#if defined(Q_OS_MACOS)
- QImage img = value.value<QImage>();
- if (!img.isNull()) {
- QByteArray arr;
- QBuffer buffer(&arr);
- buffer.open(QIODevice::WriteOnly);
- img.save(&buffer);
- NSData *data = arr.toNSData();
- NSImage *nsImg = [[NSImage alloc] initWithData:data];
- item.value = nsImg;
- [nsImg release];
- }
-#endif
- break;
- }
- case QMediaMetaData::FileFormat: {
- QMediaFormat::FileFormat qtFormat = value.value<QMediaFormat::FileFormat>();
- AVFileType avFormat = QDarwinFormatInfo::avFileTypeForContainerFormat(qtFormat);
- item.value = avFormat;
- break;
- }
- case QMediaMetaData::Language: {
- QString lang = QLocale::languageToCode(value.value<QLocale::Language>());
- if (!lang.isEmpty())
- item.value = lang.toNSString();
- break;
- }
- default: {
- switch (value.typeId()) {
- case QMetaType::QString: {
- item.value = value.toString().toNSString();
- break;
- }
- case QMetaType::Int: {
- item.value = [NSNumber numberWithInt:value.toInt()];
- break;
- }
- case QMetaType::LongLong: {
- item.value = [NSNumber numberWithLongLong:value.toLongLong()];
- break;
- }
- case QMetaType::Double: {
- item.value = [NSNumber numberWithDouble:value.toDouble()];
- break;
- }
- case QMetaType::QDate:
- case QMetaType::QDateTime: {
- item.value = value.toDateTime().toNSDate();
- break;
- }
- case QMetaType::QUrl: {
- item.value = value.toUrl().toNSURL();
- break;
- }
- default:
- break;
- }
- }
- }
-
- return item;
-}
-
-NSMutableArray<AVMetadataItem *> *AVFMetaData::toAVMetadataForFormat(QMediaMetaData metadata, AVFileType format)
-{
- NSMutableArray<AVMetadataKeySpace> *keySpaces = [NSMutableArray<AVMetadataKeySpace> array];
- if (format == AVFileTypeAppleM4A) {
- [keySpaces addObject:AVMetadataKeySpaceiTunes];
- } else if (format == AVFileTypeMPEGLayer3) {
- [keySpaces addObject:AVMetadataKeySpaceID3];
- [keySpaces addObject:AVMetadataKeySpaceiTunes];
- } else if (format == AVFileTypeQuickTimeMovie) {
- [keySpaces addObject:AVMetadataKeySpaceQuickTimeMetadata];
- } else {
- [keySpaces addObject:AVMetadataKeySpaceCommon];
- }
- NSMutableArray<AVMetadataItem *> *avMetaDataArr = [NSMutableArray array];
- for (const auto &key : metadata.keys()) {
- for (NSUInteger i = 0; i < [keySpaces count]; i++) {
- const QVariant &value = metadata.value(key);
- // set format-specific metadata
- AVMetadataItem *item = setAVMetadataItemForKey(key, value, keySpaces[i]);
- if (item)
- [avMetaDataArr addObject:item];
- }
- }
- return avMetaDataArr;
-}
-
diff --git a/src/multimedia/platform/darwin/common/avfmetadata_p.h b/src/multimedia/platform/darwin/common/avfmetadata_p.h
deleted file mode 100644
index e983be531..000000000
--- a/src/multimedia/platform/darwin/common/avfmetadata_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFMEDIAPLAYERMETADATACONTROL_H
-#define AVFMEDIAPLAYERMETADATACONTROL_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/QMediaMetaData>
-#include <QtCore/qvariant.h>
-
-#import <AVFoundation/AVFoundation.h>
-
-QT_BEGIN_NAMESPACE
-
-class AVFMediaPlayer;
-
-class AVFMetaData
-{
-public:
- static QMediaMetaData fromAsset(AVAsset *asset);
- static QMediaMetaData fromAssetTrack(AVAssetTrack *asset);
- static NSMutableArray<AVMetadataItem *> *toAVMetadataForFormat(QMediaMetaData metaData, AVFileType format);
-};
-
-QT_END_NAMESPACE
-
-#endif // AVFMEDIAPLAYERMETADATACONTROL_H
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfdisplaylink.mm b/src/multimedia/platform/darwin/mediaplayer/avfdisplaylink.mm
deleted file mode 100644
index 64b625f0e..000000000
--- a/src/multimedia/platform/darwin/mediaplayer/avfdisplaylink.mm
+++ /dev/null
@@ -1,241 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfdisplaylink_p.h"
-#include <QtCore/qcoreapplication.h>
-
-#ifdef QT_DEBUG_AVF
-#include <QtCore/qdebug.h>
-#endif
-
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-#import <QuartzCore/CADisplayLink.h>
-#import <Foundation/NSRunLoop.h>
-#define _m_displayLink static_cast<DisplayLinkObserver*>(m_displayLink)
-#else
-#endif
-
-QT_USE_NAMESPACE
-
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-@interface DisplayLinkObserver : NSObject
-
-- (void)start;
-- (void)stop;
-- (void)displayLinkNotification:(CADisplayLink *)sender;
-
-@end
-
-@implementation DisplayLinkObserver
-{
- AVFDisplayLink *m_avfDisplayLink;
- CADisplayLink *m_displayLink;
-}
-
-- (id)initWithAVFDisplayLink:(AVFDisplayLink *)link
-{
- self = [super init];
-
- if (self) {
- m_avfDisplayLink = link;
- m_displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkNotification:)] retain];
- }
-
- return self;
-}
-
-- (void) dealloc
-{
- if (m_displayLink) {
- [m_displayLink release];
- m_displayLink = nullptr;
- }
-
- [super dealloc];
-}
-
-- (void)start
-{
- [m_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-}
-
-- (void)stop
-{
- [m_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-}
-
-- (void)displayLinkNotification:(CADisplayLink *)sender
-{
- Q_UNUSED(sender);
- m_avfDisplayLink->displayLinkEvent(nullptr);
-}
-
-@end
-#else
-static CVReturn CVDisplayLinkCallback(CVDisplayLinkRef displayLink,
- const CVTimeStamp *inNow,
- const CVTimeStamp *inOutputTime,
- CVOptionFlags flagsIn,
- CVOptionFlags *flagsOut,
- void *displayLinkContext)
-{
- Q_UNUSED(displayLink);
- Q_UNUSED(inNow);
- Q_UNUSED(flagsIn);
- Q_UNUSED(flagsOut);
-
- AVFDisplayLink *link = (AVFDisplayLink *)displayLinkContext;
-
- link->displayLinkEvent(inOutputTime);
- return kCVReturnSuccess;
-}
-#endif
-
-AVFDisplayLink::AVFDisplayLink(QObject *parent)
- : QObject(parent)
- , m_displayLink(nullptr)
- , m_pendingDisplayLinkEvent(false)
- , m_isActive(false)
-{
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- m_displayLink = [[DisplayLinkObserver alloc] initWithAVFDisplayLink:this];
-#else
- // create display link for the main display
- CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink);
- if (m_displayLink) {
- // set the current display of a display link.
- CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay);
-
- // set the renderer output callback function
- CVDisplayLinkSetOutputCallback(m_displayLink, &CVDisplayLinkCallback, this);
- }
-#endif
-}
-
-AVFDisplayLink::~AVFDisplayLink()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
-
- if (m_displayLink) {
- stop();
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- [_m_displayLink release];
-#else
- CVDisplayLinkRelease(m_displayLink);
-#endif
- m_displayLink = nullptr;
- }
-}
-
-bool AVFDisplayLink::isValid() const
-{
- return m_displayLink != nullptr;
-}
-
-bool AVFDisplayLink::isActive() const
-{
- return m_isActive;
-}
-
-void AVFDisplayLink::start()
-{
- if (m_displayLink && !m_isActive) {
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- [_m_displayLink start];
-#else
- CVDisplayLinkStart(m_displayLink);
-#endif
- m_isActive = true;
- }
-}
-
-void AVFDisplayLink::stop()
-{
- if (m_displayLink && m_isActive) {
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- [_m_displayLink stop];
-#else
- CVDisplayLinkStop(m_displayLink);
-#endif
- m_isActive = false;
- }
-}
-
-void AVFDisplayLink::displayLinkEvent(const CVTimeStamp *ts)
-{
- // This function is called from a
- // thread != gui thread. So we post the event.
- // But we need to make sure that we don't post faster
- // than the event loop can eat:
- m_displayLinkMutex.lock();
- bool pending = m_pendingDisplayLinkEvent;
- m_pendingDisplayLinkEvent = true;
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- Q_UNUSED(ts);
- memset(&m_frameTimeStamp, 0, sizeof(CVTimeStamp));
-#else
- m_frameTimeStamp = *ts;
-#endif
- m_displayLinkMutex.unlock();
-
- if (!pending)
- qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority);
-}
-
-bool AVFDisplayLink::event(QEvent *event)
-{
- switch (event->type()){
- case QEvent::User: {
- m_displayLinkMutex.lock();
- m_pendingDisplayLinkEvent = false;
- CVTimeStamp ts = m_frameTimeStamp;
- m_displayLinkMutex.unlock();
-
- Q_EMIT tick(ts);
-
- return false;
- }
- break;
- default:
- break;
- }
- return QObject::event(event);
-}
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfdisplaylink_p.h b/src/multimedia/platform/darwin/mediaplayer/avfdisplaylink_p.h
deleted file mode 100644
index 6b95e1e07..000000000
--- a/src/multimedia/platform/darwin/mediaplayer/avfdisplaylink_p.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFDISPLAYLINK_H
-#define AVFDISPLAYLINK_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/qobject.h>
-#include <QtCore/qmutex.h>
-
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-#include <CoreVideo/CVBase.h>
-#else
-#include <QuartzCore/CVDisplayLink.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class AVFDisplayLink : public QObject
-{
- Q_OBJECT
-public:
- explicit AVFDisplayLink(QObject *parent = nullptr);
- virtual ~AVFDisplayLink();
- bool isValid() const;
- bool isActive() const;
-
-public Q_SLOTS:
- void start();
- void stop();
-
-Q_SIGNALS:
- void tick(const CVTimeStamp &ts);
-
-public:
- void displayLinkEvent(const CVTimeStamp *);
-
-protected:
- virtual bool event(QEvent *) override;
-
-private:
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- void *m_displayLink;
-#else
- CVDisplayLinkRef m_displayLink;
-#endif
- QMutex m_displayLinkMutex;
- bool m_pendingDisplayLinkEvent;
- bool m_isActive;
- CVTimeStamp m_frameTimeStamp;
-};
-
-QT_END_NAMESPACE
-
-#endif // AVFDISPLAYLINK_H
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
deleted file mode 100644
index 2cd61a42e..000000000
--- a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer.mm
+++ /dev/null
@@ -1,1161 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfmediaplayer_p.h"
-#include "avfmediaplayer_p.h"
-#include "avfvideorenderercontrol_p.h"
-#include <private/avfvideosink_p.h>
-#include <private/avfmetadata_p.h>
-
-#include "qaudiooutput.h"
-#include "qplatformaudiooutput_p.h"
-
-#include <qpointer.h>
-#include <QFileInfo>
-
-#import <AVFoundation/AVFoundation.h>
-
-QT_USE_NAMESPACE
-
-//AVAsset Keys
-static NSString* const AVF_TRACKS_KEY = @"tracks";
-static NSString* const AVF_PLAYABLE_KEY = @"playable";
-
-//AVPlayerItem keys
-static NSString* const AVF_STATUS_KEY = @"status";
-static NSString* const AVF_BUFFER_LIKELY_KEEP_UP_KEY = @"playbackLikelyToKeepUp";
-
-//AVPlayer keys
-static NSString* const AVF_RATE_KEY = @"rate";
-static NSString* const AVF_CURRENT_ITEM_KEY = @"currentItem";
-static NSString* const AVF_CURRENT_ITEM_DURATION_KEY = @"currentItem.duration";
-
-static void *AVFMediaPlayerObserverRateObservationContext = &AVFMediaPlayerObserverRateObservationContext;
-static void *AVFMediaPlayerObserverStatusObservationContext = &AVFMediaPlayerObserverStatusObservationContext;
-static void *AVFMediaPlayerObserverPresentationSizeContext = &AVFMediaPlayerObserverPresentationSizeContext;
-static void *AVFMediaPlayerObserverBufferLikelyToKeepUpContext = &AVFMediaPlayerObserverBufferLikelyToKeepUpContext;
-static void *AVFMediaPlayerObserverTracksContext = &AVFMediaPlayerObserverTracksContext;
-static void *AVFMediaPlayerObserverCurrentItemObservationContext = &AVFMediaPlayerObserverCurrentItemObservationContext;
-static void *AVFMediaPlayerObserverCurrentItemDurationObservationContext = &AVFMediaPlayerObserverCurrentItemDurationObservationContext;
-
-@interface AVFMediaPlayerObserver : NSObject<AVAssetResourceLoaderDelegate>
-
-@property (readonly, getter=player) AVPlayer* m_player;
-@property (readonly, getter=playerItem) AVPlayerItem* m_playerItem;
-@property (readonly, getter=playerLayer) AVPlayerLayer* m_playerLayer;
-@property (readonly, getter=session) AVFMediaPlayer* m_session;
-@property (retain) AVPlayerItemTrack *videoTrack;
-
-- (AVFMediaPlayerObserver *) initWithMediaPlayerSession:(AVFMediaPlayer *)session;
-- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType;
-- (void) unloadMedia;
-- (void) prepareToPlayAsset:(AVURLAsset *)asset withKeys:(NSArray *)requestedKeys;
-- (void) assetFailedToPrepareForPlayback:(NSError *)error;
-- (void) playerItemDidReachEnd:(NSNotification *)notification;
-- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
- change:(NSDictionary *)change context:(void *)context;
-- (void) detatchSession;
-- (void) dealloc;
-- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest;
-@end
-
-@implementation AVFMediaPlayerObserver
-{
-@private
- AVFMediaPlayer *m_session;
- AVPlayer *m_player;
- AVPlayerItem *m_playerItem;
- AVPlayerLayer *m_playerLayer;
- NSURL *m_URL;
- BOOL m_bufferIsLikelyToKeepUp;
- NSData *m_data;
- NSString *m_mimeType;
-}
-
-@synthesize m_player, m_playerItem, m_playerLayer, m_session;
-
-- (AVFMediaPlayerObserver *) initWithMediaPlayerSession:(AVFMediaPlayer *)session
-{
- if (!(self = [super init]))
- return nil;
-
- m_session = session;
- m_bufferIsLikelyToKeepUp = FALSE;
-
- m_playerLayer = [AVPlayerLayer playerLayerWithPlayer:nil];
- [m_playerLayer retain];
- m_playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
- m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f);
- return self;
-}
-
-- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType
-{
- [m_mimeType release];
- m_mimeType = [mimeType retain];
-
- if (m_URL != url)
- {
- [m_URL release];
- m_URL = [url copy];
-
- //Create an asset for inspection of a resource referenced by a given URL.
- //Load the values for the asset keys "tracks", "playable".
-
- // use __block to avoid maintaining strong references on variables captured by the
- // following block callback
- __block AVURLAsset *asset = [[AVURLAsset URLAssetWithURL:m_URL options:nil] retain];
- [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
-
- __block NSArray *requestedKeys = [[NSArray arrayWithObjects:AVF_TRACKS_KEY, AVF_PLAYABLE_KEY, nil] retain];
-
- __block AVFMediaPlayerObserver *blockSelf = self;
- QPointer<AVFMediaPlayer> session(m_session);
-
- // Tells the asset to load the values of any of the specified keys that are not already loaded.
- [asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler:
- ^{
- dispatch_async( dispatch_get_main_queue(),
- ^{
- if (session)
- [blockSelf prepareToPlayAsset:asset withKeys:requestedKeys];
- [asset release];
- [requestedKeys release];
- });
- }];
- }
-}
-
-- (void) unloadMedia
-{
- if (m_playerItem) {
- [m_playerItem removeObserver:self forKeyPath:@"presentationSize"];
- [m_playerItem removeObserver:self forKeyPath:AVF_STATUS_KEY];
- [m_playerItem removeObserver:self forKeyPath:AVF_BUFFER_LIKELY_KEEP_UP_KEY];
- [m_playerItem removeObserver:self forKeyPath:AVF_TRACKS_KEY];
-
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:AVPlayerItemDidPlayToEndTimeNotification
- object:m_playerItem];
- m_playerItem = 0;
- }
- if (m_player) {
- [m_player setRate:0.0];
- [m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_DURATION_KEY];
- [m_player removeObserver:self forKeyPath:AVF_CURRENT_ITEM_KEY];
- [m_player removeObserver:self forKeyPath:AVF_RATE_KEY];
- [m_player release];
- m_player = 0;
- }
- if (m_playerLayer)
- m_playerLayer.player = nil;
-#if defined(Q_OS_IOS)
- [[AVAudioSession sharedInstance] setActive:NO error:nil];
-#endif
-}
-
-- (void) prepareToPlayAsset:(AVURLAsset *)asset
- withKeys:(NSArray *)requestedKeys
-{
- //Make sure that the value of each key has loaded successfully.
- for (NSString *thisKey in requestedKeys)
- {
- NSError *error = nil;
- AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error];
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << [thisKey UTF8String] << " status: " << keyStatus;
-#endif
- if (keyStatus == AVKeyValueStatusFailed)
- {
- [self assetFailedToPrepareForPlayback:error];
- return;
- }
- }
-
- //Use the AVAsset playable property to detect whether the asset can be played.
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << "isPlayable: " << [asset isPlayable];
-#endif
- if (!asset.playable)
- {
- //Generate an error describing the failure.
- NSString *localizedDescription = NSLocalizedString(@"Item cannot be played", @"Item cannot be played description");
- NSString *localizedFailureReason = NSLocalizedString(@"The assets tracks were loaded, but could not be made playable.", @"Item cannot be played failure reason");
- NSDictionary *errorDict = [NSDictionary dictionaryWithObjectsAndKeys:
- localizedDescription, NSLocalizedDescriptionKey,
- localizedFailureReason, NSLocalizedFailureReasonErrorKey,
- nil];
- NSError *assetCannotBePlayedError = [NSError errorWithDomain:@"StitchedStreamPlayer" code:0 userInfo:errorDict];
-
- [self assetFailedToPrepareForPlayback:assetCannotBePlayedError];
-
- return;
- }
-
- //At this point we're ready to set up for playback of the asset.
- //Stop observing our prior AVPlayerItem, if we have one.
- if (m_playerItem)
- {
- //Remove existing player item key value observers and notifications.
- [self unloadMedia];
- }
-
- //Create a new instance of AVPlayerItem from the now successfully loaded AVAsset.
- m_playerItem = [AVPlayerItem playerItemWithAsset:asset];
-
- //Observe the player item "status" key to determine when it is ready to play.
- [m_playerItem addObserver:self
- forKeyPath:AVF_STATUS_KEY
- options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
- context:AVFMediaPlayerObserverStatusObservationContext];
-
- [m_playerItem addObserver:self
- forKeyPath:@"presentationSize"
- options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
- context:AVFMediaPlayerObserverPresentationSizeContext];
-
- [m_playerItem addObserver:self
- forKeyPath:AVF_BUFFER_LIKELY_KEEP_UP_KEY
- options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
- context:AVFMediaPlayerObserverBufferLikelyToKeepUpContext];
-
- [m_playerItem addObserver:self
- forKeyPath:AVF_TRACKS_KEY
- options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
- context:AVFMediaPlayerObserverTracksContext];
-
- //When the player item has played to its end time we'll toggle
- //the movie controller Pause button to be the Play button
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(playerItemDidReachEnd:)
- name:AVPlayerItemDidPlayToEndTimeNotification
- object:m_playerItem];
-
- //Get a new AVPlayer initialized to play the specified player item.
- m_player = [AVPlayer playerWithPlayerItem:m_playerItem];
- [m_player retain];
-
- //Set the initial volume on new player object
- if (self.session) {
- auto *audioOutput = m_session->m_audioOutput;
- m_player.volume = (audioOutput ? audioOutput->volume : 1.);
- m_player.muted = (audioOutput ? audioOutput->muted : true);
- }
-
- //Assign the output layer to the new player
- m_playerLayer.player = m_player;
-
- //Observe the AVPlayer "currentItem" property to find out when any
- //AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did
- //occur.
- [m_player addObserver:self
- forKeyPath:AVF_CURRENT_ITEM_KEY
- options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
- context:AVFMediaPlayerObserverCurrentItemObservationContext];
-
- //Observe the AVPlayer "rate" property to update the scrubber control.
- [m_player addObserver:self
- forKeyPath:AVF_RATE_KEY
- options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
- context:AVFMediaPlayerObserverRateObservationContext];
-
- //Observe the duration for getting the buffer state
- [m_player addObserver:self
- forKeyPath:AVF_CURRENT_ITEM_DURATION_KEY
- options:0
- context:AVFMediaPlayerObserverCurrentItemDurationObservationContext];
-#if defined(Q_OS_IOS)
- [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
- [[AVAudioSession sharedInstance] setActive:YES error:nil];
-#endif
-}
-
--(void) assetFailedToPrepareForPlayback:(NSError *)error
-{
- Q_UNUSED(error);
- QMetaObject::invokeMethod(m_session, "processMediaLoadError", Qt::AutoConnection);
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
- qDebug() << [[error localizedDescription] UTF8String];
- qDebug() << [[error localizedFailureReason] UTF8String];
- qDebug() << [[error localizedRecoverySuggestion] UTF8String];
-#endif
-}
-
-- (void) playerItemDidReachEnd:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- if (self.session)
- QMetaObject::invokeMethod(m_session, "processEOS", Qt::AutoConnection);
-}
-
-- (void) observeValueForKeyPath:(NSString*) path
- ofObject:(id)object
- change:(NSDictionary*)change
- context:(void*)context
-{
- //AVPlayerItem "status" property value observer.
- if (context == AVFMediaPlayerObserverStatusObservationContext)
- {
- AVPlayerStatus status = (AVPlayerStatus)[[change objectForKey:NSKeyValueChangeNewKey] integerValue];
- switch (status)
- {
- //Indicates that the status of the player is not yet known because
- //it has not tried to load new media resources for playback
- case AVPlayerStatusUnknown:
- {
- //QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection);
- }
- break;
-
- case AVPlayerStatusReadyToPlay:
- {
- //Once the AVPlayerItem becomes ready to play, i.e.
- //[playerItem status] == AVPlayerItemStatusReadyToPlay,
- //its duration can be fetched from the item.
- if (self.session)
- QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection);
- }
- break;
-
- case AVPlayerStatusFailed:
- {
- AVPlayerItem *playerItem = static_cast<AVPlayerItem*>(object);
- [self assetFailedToPrepareForPlayback:playerItem.error];
-
- if (self.session)
- QMetaObject::invokeMethod(m_session, "processLoadStateFailure", Qt::AutoConnection);
- }
- break;
- }
- } else if (context == AVFMediaPlayerObserverPresentationSizeContext) {
- QSize size(m_playerItem.presentationSize.width, m_playerItem.presentationSize.height);
- QMetaObject::invokeMethod(m_session, "nativeSizeChanged", Qt::AutoConnection, Q_ARG(QSize, size));
- } else if (context == AVFMediaPlayerObserverBufferLikelyToKeepUpContext)
- {
- const bool isPlaybackLikelyToKeepUp = [m_playerItem isPlaybackLikelyToKeepUp];
- if (isPlaybackLikelyToKeepUp != m_bufferIsLikelyToKeepUp) {
- m_bufferIsLikelyToKeepUp = isPlaybackLikelyToKeepUp;
- QMetaObject::invokeMethod(m_session, "processBufferStateChange", Qt::AutoConnection,
- Q_ARG(int, isPlaybackLikelyToKeepUp ? 100 : 0));
- }
- }
- else if (context == AVFMediaPlayerObserverTracksContext)
- {
- QMetaObject::invokeMethod(m_session, "updateTracks", Qt::AutoConnection);
- }
- //AVPlayer "rate" property value observer.
- else if (context == AVFMediaPlayerObserverRateObservationContext)
- {
- //QMetaObject::invokeMethod(m_session, "setPlaybackRate", Qt::AutoConnection, Q_ARG(qreal, [m_player rate]));
- }
- //AVPlayer "currentItem" property observer.
- //Called when the AVPlayer replaceCurrentItemWithPlayerItem:
- //replacement will/did occur.
- else if (context == AVFMediaPlayerObserverCurrentItemObservationContext)
- {
- AVPlayerItem *newPlayerItem = [change objectForKey:NSKeyValueChangeNewKey];
- if (m_playerItem != newPlayerItem)
- m_playerItem = newPlayerItem;
- }
- else if (context == AVFMediaPlayerObserverCurrentItemDurationObservationContext)
- {
- const CMTime time = [m_playerItem duration];
- const qint64 duration = static_cast<qint64>(float(time.value) / float(time.timescale) * 1000.0f);
- if (self.session)
- QMetaObject::invokeMethod(m_session, "processDurationChange", Qt::AutoConnection, Q_ARG(qint64, duration));
- }
- else
- {
- [super observeValueForKeyPath:path ofObject:object change:change context:context];
- }
-}
-
-- (void) detatchSession
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- m_session = 0;
-}
-
-- (void) dealloc
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- [self unloadMedia];
-
- if (m_URL) {
- [m_URL release];
- }
-
- [m_mimeType release];
- [m_playerLayer release];
- [super dealloc];
-}
-
-- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
-{
- Q_UNUSED(resourceLoader);
-
- if (![loadingRequest.request.URL.scheme isEqualToString:@"iodevice"])
- return NO;
-
- QIODevice *device = m_session->mediaStream();
- if (!device)
- return NO;
-
- device->seek(loadingRequest.dataRequest.requestedOffset);
- if (loadingRequest.contentInformationRequest) {
- loadingRequest.contentInformationRequest.contentType = m_mimeType;
- loadingRequest.contentInformationRequest.contentLength = device->size();
- loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
- }
-
- if (loadingRequest.dataRequest) {
- NSInteger requestedLength = loadingRequest.dataRequest.requestedLength;
- int maxBytes = qMin(32 * 1064, int(requestedLength));
- char buffer[maxBytes];
- NSInteger submitted = 0;
- while (submitted < requestedLength) {
- qint64 len = device->read(buffer, maxBytes);
- if (len < 1)
- break;
-
- [loadingRequest.dataRequest respondWithData:[NSData dataWithBytes:buffer length:len]];
- submitted += len;
- }
-
- // Finish loading even if not all bytes submitted.
- [loadingRequest finishLoading];
- }
-
- return YES;
-}
-@end
-
-AVFMediaPlayer::AVFMediaPlayer(QMediaPlayer *player)
- : QObject(player)
- , QPlatformMediaPlayer(player)
- , m_state(QMediaPlayer::StoppedState)
- , m_mediaStatus(QMediaPlayer::NoMedia)
- , m_mediaStream(nullptr)
- , m_tryingAsync(false)
- , m_rate(1.0)
- , m_requestedPosition(-1)
- , m_duration(0)
- , m_bufferProgress(0)
- , m_videoAvailable(false)
- , m_audioAvailable(false)
- , m_seekable(false)
-{
- m_observer = [[AVFMediaPlayerObserver alloc] initWithMediaPlayerSession:this];
- connect(&m_playbackTimer, &QTimer::timeout, this, &AVFMediaPlayer::processPositionChange);
- setVideoOutput(new AVFVideoRendererControl(this));
-}
-
-AVFMediaPlayer::~AVFMediaPlayer()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- //Detatch the session from the sessionObserver (which could still be alive trying to communicate with this session).
- [m_observer detatchSession];
- [static_cast<AVFMediaPlayerObserver*>(m_observer) release];
-}
-
-void AVFMediaPlayer::setVideoSink(QVideoSink *sink)
-{
- m_videoSink = sink ? static_cast<AVFVideoSink *>(sink->platformVideoSink()): nullptr;
- m_videoOutput->setVideoSink(m_videoSink);
-}
-
-void AVFMediaPlayer::setVideoOutput(AVFVideoRendererControl *output)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << output;
-#endif
-
- if (m_videoOutput == output)
- return;
-
- //Set the current output layer to null to stop rendering
- if (m_videoOutput) {
- m_videoOutput->setLayer(nullptr);
- }
-
- m_videoOutput = output;
-
- if (m_videoOutput && m_state != QMediaPlayer::StoppedState)
- m_videoOutput->setLayer([static_cast<AVFMediaPlayerObserver*>(m_observer) playerLayer]);
-}
-
-AVAsset *AVFMediaPlayer::currentAssetHandle()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- AVAsset *currentAsset = [[static_cast<AVFMediaPlayerObserver*>(m_observer) playerItem] asset];
- return currentAsset;
-}
-
-QMediaPlayer::PlaybackState AVFMediaPlayer::state() const
-{
- return m_state;
-}
-
-QMediaPlayer::MediaStatus AVFMediaPlayer::mediaStatus() const
-{
- return m_mediaStatus;
-}
-
-QUrl AVFMediaPlayer::media() const
-{
- return m_resources;
-}
-
-QIODevice *AVFMediaPlayer::mediaStream() const
-{
- return m_mediaStream;
-}
-
-static void setURL(AVFMediaPlayerObserver *observer, const QByteArray &url, const QString &mimeType = QString())
-{
- NSString *urlString = [NSString stringWithUTF8String:url.constData()];
- NSURL *nsurl = [NSURL URLWithString:urlString];
- [observer setURL:nsurl mimeType:[NSString stringWithUTF8String:mimeType.toLatin1().constData()]];
-}
-
-static void setStreamURL(AVFMediaPlayerObserver *observer, const QByteArray &url)
-{
- setURL(observer, QByteArrayLiteral("iodevice://") + url, QFileInfo(QString::fromUtf8(url)).suffix());
-}
-
-void AVFMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << content.request().url();
-#endif
-
- [static_cast<AVFMediaPlayerObserver*>(m_observer) unloadMedia];
-
- m_resources = content;
- resetStream(stream);
-
- setAudioAvailable(false);
- setVideoAvailable(false);
- setSeekable(false);
- m_requestedPosition = -1;
- Q_EMIT positionChanged(position());
- if (m_duration != 0) {
- m_duration = 0;
- Q_EMIT durationChanged(0);
- }
- if (!m_metaData.isEmpty()) {
- m_metaData.clear();
- metaDataChanged();
- }
-
- const QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus;
- const QMediaPlayer::PlaybackState oldState = m_state;
-
- if (!m_mediaStream && content.isEmpty()) {
- m_mediaStatus = QMediaPlayer::NoMedia;
- if (m_mediaStatus != oldMediaStatus)
- Q_EMIT mediaStatusChanged(m_mediaStatus);
-
- m_state = QMediaPlayer::StoppedState;
- if (m_state != oldState)
- Q_EMIT stateChanged(m_state);
-
- return;
- }
-
- m_mediaStatus = QMediaPlayer::LoadingMedia;
- if (m_mediaStatus != oldMediaStatus)
- Q_EMIT mediaStatusChanged(m_mediaStatus);
-
- if (m_mediaStream) {
- // If there is a data, try to load it,
- // otherwise wait for readyRead.
- if (m_mediaStream->size())
- setStreamURL(m_observer, m_resources.toEncoded());
- } else {
- //Load AVURLAsset
- //initialize asset using content's URL
- setURL(m_observer, m_resources.toEncoded());
- }
-
- m_state = QMediaPlayer::StoppedState;
- if (m_state != oldState)
- Q_EMIT stateChanged(m_state);
-}
-
-qint64 AVFMediaPlayer::position() const
-{
- AVPlayerItem *playerItem = [static_cast<AVFMediaPlayerObserver*>(m_observer) playerItem];
-
- if (!playerItem)
- return m_requestedPosition != -1 ? m_requestedPosition : 0;
-
- CMTime time = [playerItem currentTime];
- return static_cast<quint64>(float(time.value) / float(time.timescale) * 1000.0f);
-}
-
-qint64 AVFMediaPlayer::duration() const
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- return m_duration;
-}
-
-float AVFMediaPlayer::bufferProgress() const
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- return m_bufferProgress/100.;
-}
-
-void AVFMediaPlayer::setAudioAvailable(bool available)
-{
- if (m_audioAvailable == available)
- return;
-
- m_audioAvailable = available;
- Q_EMIT audioAvailableChanged(available);
-}
-
-bool AVFMediaPlayer::isAudioAvailable() const
-{
- return m_audioAvailable;
-}
-
-void AVFMediaPlayer::setVideoAvailable(bool available)
-{
- if (m_videoAvailable == available)
- return;
-
- m_videoAvailable = available;
- Q_EMIT videoAvailableChanged(available);
-}
-
-bool AVFMediaPlayer::isVideoAvailable() const
-{
- return m_videoAvailable;
-}
-
-bool AVFMediaPlayer::isSeekable() const
-{
- return m_seekable;
-}
-
-void AVFMediaPlayer::setSeekable(bool seekable)
-{
- if (m_seekable == seekable)
- return;
-
- m_seekable = seekable;
- Q_EMIT seekableChanged(seekable);
-}
-
-QMediaTimeRange AVFMediaPlayer::availablePlaybackRanges() const
-{
- AVPlayerItem *playerItem = [static_cast<AVFMediaPlayerObserver*>(m_observer) playerItem];
-
- if (playerItem) {
- QMediaTimeRange timeRanges;
-
- NSArray *ranges = [playerItem loadedTimeRanges];
- for (NSValue *timeRange in ranges) {
- CMTimeRange currentTimeRange = [timeRange CMTimeRangeValue];
- qint64 startTime = qint64(float(currentTimeRange.start.value) / currentTimeRange.start.timescale * 1000.0);
- timeRanges.addInterval(startTime, startTime + qint64(float(currentTimeRange.duration.value) / currentTimeRange.duration.timescale * 1000.0));
- }
- if (!timeRanges.isEmpty())
- return timeRanges;
- }
- return QMediaTimeRange(0, duration());
-}
-
-qreal AVFMediaPlayer::playbackRate() const
-{
- return m_rate;
-}
-
-void AVFMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
-{
- if (m_audioOutput == output)
- return;
- if (m_audioOutput)
- m_audioOutput->q->disconnect(this);
- m_audioOutput = output;
- if (m_audioOutput) {
- connect(m_audioOutput->q, &QAudioOutput::deviceChanged, this, &AVFMediaPlayer::audioOutputChanged);
- connect(m_audioOutput->q, &QAudioOutput::volumeChanged, this, &AVFMediaPlayer::setVolume);
- connect(m_audioOutput->q, &QAudioOutput::mutedChanged, this, &AVFMediaPlayer::setMuted);
- //connect(m_audioOutput->q, &QAudioOutput::audioRoleChanged, this, &AVFMediaPlayer::setAudioRole);
- }
- audioOutputChanged();
- setMuted(m_audioOutput ? m_audioOutput->muted : true);
- setVolume(m_audioOutput ? m_audioOutput->volume : 1.);
-}
-
-QMediaMetaData AVFMediaPlayer::metaData() const
-{
- return m_metaData;
-}
-
-void AVFMediaPlayer::setPlaybackRate(qreal rate)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << rate;
-#endif
-
- if (qFuzzyCompare(m_rate, rate))
- return;
-
- m_rate = rate;
-
- AVPlayer *player = [static_cast<AVFMediaPlayerObserver*>(m_observer) player];
- if (player && m_state == QMediaPlayer::PlayingState)
- [player setRate:m_rate];
-
- Q_EMIT playbackRateChanged(m_rate);
-}
-
-void AVFMediaPlayer::setPosition(qint64 pos)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << pos;
-#endif
-
- if (pos == position())
- return;
-
- AVPlayerItem *playerItem = [static_cast<AVFMediaPlayerObserver*>(m_observer) playerItem];
- if (!playerItem) {
- m_requestedPosition = pos;
- Q_EMIT positionChanged(m_requestedPosition);
- return;
- }
-
- if (!isSeekable()) {
- if (m_requestedPosition != -1) {
- m_requestedPosition = -1;
- Q_EMIT positionChanged(position());
- }
- return;
- }
-
- pos = qMax(qint64(0), pos);
- if (duration() > 0)
- pos = qMin(pos, duration());
-
- CMTime newTime = [playerItem currentTime];
- newTime.value = (pos / 1000.0f) * newTime.timescale;
- [playerItem seekToTime:newTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:nil];
-
- Q_EMIT positionChanged(pos);
-
- // Reset media status if the current status is EndOfMedia
- if (m_mediaStatus == QMediaPlayer::EndOfMedia) {
- QMediaPlayer::MediaStatus newMediaStatus = (m_state == QMediaPlayer::PausedState) ? QMediaPlayer::BufferedMedia
- : QMediaPlayer::LoadedMedia;
- Q_EMIT mediaStatusChanged((m_mediaStatus = newMediaStatus));
- }
-}
-
-void AVFMediaPlayer::play()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << "currently: " << m_state;
-#endif
-
- if (m_mediaStatus == QMediaPlayer::NoMedia || m_mediaStatus == QMediaPlayer::InvalidMedia)
- return;
-
- if (m_state == QMediaPlayer::PlayingState)
- return;
-
- if (m_videoOutput && m_videoSink)
- m_videoOutput->setLayer([static_cast<AVFMediaPlayerObserver*>(m_observer) playerLayer]);
-
- // Reset media status if the current status is EndOfMedia
- if (m_mediaStatus == QMediaPlayer::EndOfMedia)
- setPosition(0);
-
- if (m_mediaStatus == QMediaPlayer::LoadedMedia || m_mediaStatus == QMediaPlayer::BufferedMedia) {
- // Setting the rate starts playback
- [[static_cast<AVFMediaPlayerObserver*>(m_observer) player] setRate:m_rate];
- }
-
- m_state = QMediaPlayer::PlayingState;
- processLoadStateChange();
-
- Q_EMIT stateChanged(m_state);
- m_playbackTimer.start(100);
-}
-
-void AVFMediaPlayer::pause()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << "currently: " << m_state;
-#endif
-
- if (m_mediaStatus == QMediaPlayer::NoMedia)
- return;
-
- if (m_state == QMediaPlayer::PausedState)
- return;
-
- m_state = QMediaPlayer::PausedState;
-
- if (m_videoOutput && m_videoSink)
- m_videoOutput->setLayer([static_cast<AVFMediaPlayerObserver*>(m_observer) playerLayer]);
-
- [[static_cast<AVFMediaPlayerObserver*>(m_observer) player] pause];
-
- // Reset media status if the current status is EndOfMedia
- if (m_mediaStatus == QMediaPlayer::EndOfMedia)
- setPosition(0);
-
- Q_EMIT positionChanged(position());
- Q_EMIT stateChanged(m_state);
- m_playbackTimer.stop();
-}
-
-void AVFMediaPlayer::stop()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << "currently: " << m_state;
-#endif
-
- if (m_state == QMediaPlayer::StoppedState)
- return;
-
- // AVPlayer doesn't have stop(), only pause() and play().
- [[static_cast<AVFMediaPlayerObserver*>(m_observer) player] pause];
- setPosition(0);
-
- if (m_videoOutput)
- m_videoOutput->setLayer(nullptr);
-
- if (m_mediaStatus == QMediaPlayer::BufferedMedia)
- Q_EMIT mediaStatusChanged((m_mediaStatus = QMediaPlayer::LoadedMedia));
-
- Q_EMIT stateChanged((m_state = QMediaPlayer::StoppedState));
- m_playbackTimer.stop();
-}
-
-void AVFMediaPlayer::setVolume(float volume)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << volume;
-#endif
-
- AVPlayer *player = [static_cast<AVFMediaPlayerObserver*>(m_observer) player];
- if (player)
- player.volume = volume;
-}
-
-void AVFMediaPlayer::setMuted(bool muted)
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << muted;
-#endif
-
- AVPlayer *player = [static_cast<AVFMediaPlayerObserver*>(m_observer) player];
- if (player)
- player.muted = muted;
-}
-
-void AVFMediaPlayer::audioOutputChanged()
-{
-#ifdef Q_OS_MACOS
- AVPlayer *player = [static_cast<AVFMediaPlayerObserver*>(m_observer) player];
- if (!m_audioOutput || m_audioOutput->device.id().isEmpty()) {
- player.audioOutputDeviceUniqueID = nil;
- if (!m_audioOutput)
- player.muted = true;
- } else {
- NSString *str = QString::fromUtf8(m_audioOutput->device.id()).toNSString();
- player.audioOutputDeviceUniqueID = str;
- }
-#endif
-}
-
-void AVFMediaPlayer::processEOS()
-{
- //AVPlayerItem has reached end of track/stream
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- Q_EMIT positionChanged(position());
- m_mediaStatus = QMediaPlayer::EndOfMedia;
- m_state = QMediaPlayer::StoppedState;
-
- if (m_videoOutput)
- m_videoOutput->setLayer(nullptr);
-
- Q_EMIT mediaStatusChanged(m_mediaStatus);
- Q_EMIT stateChanged(m_state);
-}
-
-void AVFMediaPlayer::processLoadStateChange(QMediaPlayer::PlaybackState newState)
-{
- AVPlayerStatus currentStatus = [[static_cast<AVFMediaPlayerObserver*>(m_observer) player] status];
-
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO << currentStatus << ", " << m_mediaStatus << ", " << newState;
-#endif
-
- if (m_mediaStatus == QMediaPlayer::NoMedia)
- return;
-
- if (currentStatus == AVPlayerStatusReadyToPlay) {
-
- QMediaPlayer::MediaStatus newStatus = m_mediaStatus;
-
- AVPlayerItem *playerItem = [m_observer playerItem];
-
- // get the meta data
- m_metaData = AVFMetaData::fromAsset(playerItem.asset);
- Q_EMIT metaDataChanged();
- updateTracks();
-
- if (playerItem) {
- setSeekable([[playerItem seekableTimeRanges] count] > 0);
-
- // Get the native size of the video, and reset the bounds of the player layer
- AVPlayerLayer *playerLayer = [m_observer playerLayer];
- if (m_observer.videoTrack && playerLayer) {
- if (!playerLayer.bounds.size.width || !playerLayer.bounds.size.height) {
- playerLayer.bounds = CGRectMake(0.0f, 0.0f,
- m_observer.videoTrack.assetTrack.naturalSize.width,
- m_observer.videoTrack.assetTrack.naturalSize.height);
- }
- }
-
- if (m_requestedPosition != -1) {
- setPosition(m_requestedPosition);
- m_requestedPosition = -1;
- }
- }
-
- newStatus = (newState != QMediaPlayer::StoppedState) ? QMediaPlayer::BufferedMedia
- : QMediaPlayer::LoadedMedia;
-
- if (newStatus != m_mediaStatus)
- Q_EMIT mediaStatusChanged((m_mediaStatus = newStatus));
-
- }
-
- if (newState == QMediaPlayer::PlayingState && [static_cast<AVFMediaPlayerObserver*>(m_observer) player]) {
- // Setting the rate is enough to start playback, no need to call play()
- [[static_cast<AVFMediaPlayerObserver*>(m_observer) player] setRate:m_rate];
- m_playbackTimer.start();
- }
-}
-
-
-void AVFMediaPlayer::processLoadStateChange()
-{
- processLoadStateChange(m_state);
-}
-
-
-void AVFMediaPlayer::processLoadStateFailure()
-{
- Q_EMIT stateChanged((m_state = QMediaPlayer::StoppedState));
-}
-
-void AVFMediaPlayer::processBufferStateChange(int bufferProgress)
-{
- if (bufferProgress == m_bufferProgress)
- return;
-
- auto status = m_mediaStatus;
- // Buffered -> unbuffered.
- if (!bufferProgress) {
- status = QMediaPlayer::StalledMedia;
- } else if (status == QMediaPlayer::StalledMedia) {
- status = QMediaPlayer::BufferedMedia;
- // Resume playback.
- if (m_state == QMediaPlayer::PlayingState) {
- [[static_cast<AVFMediaPlayerObserver*>(m_observer) player] setRate:m_rate];
- m_playbackTimer.start();
- }
- }
-
- if (m_mediaStatus != status)
- Q_EMIT mediaStatusChanged(m_mediaStatus = status);
-
- m_bufferProgress = bufferProgress;
- Q_EMIT bufferProgressChanged(bufferProgress/100.);
-}
-
-void AVFMediaPlayer::processDurationChange(qint64 duration)
-{
- if (duration == m_duration)
- return;
-
- m_duration = duration;
- Q_EMIT durationChanged(duration);
-}
-
-void AVFMediaPlayer::processPositionChange()
-{
- if (m_state == QMediaPlayer::StoppedState)
- return;
-
- Q_EMIT positionChanged(position());
-}
-
-void AVFMediaPlayer::processMediaLoadError()
-{
- if (m_requestedPosition != -1) {
- m_requestedPosition = -1;
- Q_EMIT positionChanged(position());
- }
-
- Q_EMIT mediaStatusChanged((m_mediaStatus = QMediaPlayer::InvalidMedia));
-
- Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media"));
-}
-
-void AVFMediaPlayer::streamReady()
-{
- setStreamURL(m_observer, m_resources.toEncoded());
-}
-
-void AVFMediaPlayer::streamDestroyed()
-{
- resetStream(nullptr);
-}
-
-void AVFMediaPlayer::updateTracks()
-{
- for (int i = 0; i < QPlatformMediaPlayer::NTrackTypes; ++i) {
- tracks[i].clear();
- nativeTracks[i].clear();
- }
- AVPlayerItem *playerItem = [m_observer playerItem];
- if (playerItem) {
- // Check each track for audio and video content
- NSArray *tracks = playerItem.tracks;
- for (AVPlayerItemTrack *track in tracks) {
- AVAssetTrack *assetTrack = track.assetTrack;
- if (assetTrack) {
- int qtTrack = -1;
- if ([assetTrack.mediaType isEqualToString:AVMediaTypeAudio]) {
- qtTrack = QPlatformMediaPlayer::AudioStream;
- setAudioAvailable(true);
- } else if ([assetTrack.mediaType isEqualToString:AVMediaTypeVideo]) {
- qtTrack = QPlatformMediaPlayer::VideoStream;
- setVideoAvailable(true);
- if (!m_observer.videoTrack)
- m_observer.videoTrack = track;
- }
- else if ([assetTrack.mediaType isEqualToString:AVMediaTypeSubtitle]) {
- qtTrack = QPlatformMediaPlayer::SubtitleStream;
- }
- if (qtTrack != -1) {
- QMediaMetaData metaData = AVFMetaData::fromAssetTrack(assetTrack);
- this->tracks[qtTrack].append(metaData);
- nativeTracks[qtTrack].append(track);
- }
- }
- }
- }
- Q_EMIT tracksChanged();
-}
-
-void AVFMediaPlayer::setActiveTrack(QPlatformMediaPlayer::TrackType type, int index)
-{
- const auto &t = nativeTracks[type];
- for (int i = 0; i < t.count(); ++i)
- t.at(i).enabled = (i == index);
-}
-
-int AVFMediaPlayer::activeTrack(QPlatformMediaPlayer::TrackType type)
-{
- const auto &t = nativeTracks[type];
- for (int i = 0; i < t.count(); ++i)
- if (t.at(i).enabled)
- return i;
- return -1;
-}
-
-int AVFMediaPlayer::trackCount(QPlatformMediaPlayer::TrackType type)
-{
- return nativeTracks[type].count();
-}
-
-QMediaMetaData AVFMediaPlayer::trackMetaData(QPlatformMediaPlayer::TrackType type, int trackNumber)
-{
- const auto &t = tracks[type];
- if (trackNumber < 0 || trackNumber >= t.count())
- return QMediaMetaData();
- return t.at(trackNumber);
-}
-
-void AVFMediaPlayer::resetStream(QIODevice *stream)
-{
- if (m_mediaStream) {
- disconnect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayer::streamReady);
- disconnect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayer::streamDestroyed);
- }
-
- m_mediaStream = stream;
-
- if (m_mediaStream) {
- connect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayer::streamReady);
- connect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayer::streamDestroyed);
- }
-}
-
-void AVFMediaPlayer::nativeSizeChanged(QSize size)
-{
- if (!m_videoSink)
- return;
- m_videoSink->setNativeSize(size);
-}
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h b/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h
deleted file mode 100644
index 4bd082c1c..000000000
--- a/src/multimedia/platform/darwin/mediaplayer/avfmediaplayer_p.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFMEDIAPLAYER_H
-#define AVFMEDIAPLAYER_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/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QSet>
-#include <QtCore/QResource>
-#include <QtCore/QUrl>
-#include <QtCore/QTimer>
-
-#include <private/qplatformmediaplayer_p.h>
-#include <QtMultimedia/QMediaPlayer>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(AVAsset);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVPlayerItemTrack);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVFMediaPlayerObserver);
-
-QT_BEGIN_NAMESPACE
-
-class AVFMediaPlayer;
-class AVFVideoRendererControl;
-class AVFVideoSink;
-
-class AVFMediaPlayer : public QObject, public QPlatformMediaPlayer
-{
- Q_OBJECT
-public:
- AVFMediaPlayer(QMediaPlayer *parent);
- virtual ~AVFMediaPlayer();
-
- void setVideoSink(QVideoSink *sink) override;
- void setVideoOutput(AVFVideoRendererControl *output);
- AVAsset *currentAssetHandle();
-
- QMediaPlayer::PlaybackState state() const override;
- QMediaPlayer::MediaStatus mediaStatus() const override;
-
- QUrl media() const override;
- QIODevice *mediaStream() const override;
- void setMedia(const QUrl &content, QIODevice *stream) override;
-
- qint64 position() const override;
- qint64 duration() const override;
-
- float bufferProgress() const override;
-
- bool isAudioAvailable() const override;
- bool isVideoAvailable() const override;
-
- bool isSeekable() const override;
- QMediaTimeRange availablePlaybackRanges() const override;
-
- qreal playbackRate() const override;
-
- void setAudioOutput(QPlatformAudioOutput *output) override;
- QPlatformAudioOutput *m_audioOutput = nullptr;
-
- QMediaMetaData metaData() const override;
-
-public Q_SLOTS:
- void setPlaybackRate(qreal rate) override;
- void nativeSizeChanged(QSize size);
-
- void setPosition(qint64 pos) override;
-
- void play() override;
- void pause() override;
- void stop() override;
-
- void setVolume(float volume);
- void setMuted(bool muted);
- void audioOutputChanged();
-
- void processEOS();
- void processLoadStateChange(QMediaPlayer::PlaybackState newState);
- void processPositionChange();
- void processMediaLoadError();
-
- void processLoadStateChange();
- void processLoadStateFailure();
-
- void processBufferStateChange(int bufferProgress);
-
- void processDurationChange(qint64 duration);
-
- void streamReady();
- void streamDestroyed();
- void updateTracks();
- void setActiveTrack(QPlatformMediaPlayer::TrackType type, int index) override;
- int activeTrack(QPlatformMediaPlayer::TrackType type) override;
- int trackCount(TrackType) override;
- QMediaMetaData trackMetaData(TrackType type, int trackNumber) override;
-
-public:
- QList<QMediaMetaData> tracks[QPlatformMediaPlayer::NTrackTypes];
- QList<AVPlayerItemTrack *> nativeTracks[QPlatformMediaPlayer::NTrackTypes];
-
-private:
- void setAudioAvailable(bool available);
- void setVideoAvailable(bool available);
- void setSeekable(bool seekable);
- void resetStream(QIODevice *stream = nullptr);
-
- AVFVideoRendererControl *m_videoOutput = nullptr;
- AVFVideoSink *m_videoSink = nullptr;
-
- QMediaPlayer::PlaybackState m_state;
- QMediaPlayer::MediaStatus m_mediaStatus;
- QIODevice *m_mediaStream;
- QUrl m_resources;
- QMediaMetaData m_metaData;
-
- bool m_tryingAsync;
- qreal m_rate;
- qint64 m_requestedPosition;
-
- qint64 m_duration;
- int m_bufferProgress;
- bool m_videoAvailable;
- bool m_audioAvailable;
- bool m_seekable;
-
- AVFMediaPlayerObserver *m_observer;
-
- QTimer m_playbackTimer;
-};
-
-QT_END_NAMESPACE
-
-#endif // AVFMEDIAPLAYER_H
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm b/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm
deleted file mode 100644
index 1b3985688..000000000
--- a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol.mm
+++ /dev/null
@@ -1,272 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "avfvideorenderercontrol_p.h"
-#include "avfdisplaylink_p.h"
-#include <private/avfvideobuffer_p.h>
-
-#include <private/qabstractvideobuffer_p.h>
-#include <QtMultimedia/qvideoframeformat.h>
-
-#include <private/avfvideosink_p.h>
-#include <QtGui/private/qrhi_p.h>
-
-#include <QtCore/qdebug.h>
-
-#import <AVFoundation/AVFoundation.h>
-#include <CoreVideo/CVPixelBuffer.h>
-#include <CoreVideo/CVImageBuffer.h>
-
-QT_USE_NAMESPACE
-
-@interface SubtitleDelegate : NSObject <AVPlayerItemLegibleOutputPushDelegate>
-{
- AVFVideoRendererControl *m_renderer;
-}
-
-- (void)legibleOutput:(AVPlayerItemLegibleOutput *)output
- didOutputAttributedStrings:(NSArray<NSAttributedString *> *)strings
- nativeSampleBuffers:(NSArray *)nativeSamples
- forItemTime:(CMTime)itemTime;
-
-@end
-
-@implementation SubtitleDelegate
-
--(id)initWithRenderer: (AVFVideoRendererControl *)renderer
-{
- if (!(self = [super init]))
- return nil;
-
- m_renderer = renderer;
-
- return self;
-}
-
-- (void)legibleOutput:(AVPlayerItemLegibleOutput *)output
- didOutputAttributedStrings:(NSArray<NSAttributedString *> *)strings
- nativeSampleBuffers:(NSArray *)nativeSamples
- forItemTime:(CMTime)itemTime
-{
- QString text;
- for (NSAttributedString *s : strings) {
- if (!text.isEmpty())
- text += QChar::LineSeparator;
- text += QString::fromNSString(s.string);
- }
- m_renderer->setSubtitleText(text);
-}
-
-@end
-
-
-AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent)
- : QObject(parent)
-{
- m_displayLink = new AVFDisplayLink(this);
- connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp)));
-}
-
-AVFVideoRendererControl::~AVFVideoRendererControl()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
- m_displayLink->stop();
- if (m_videoOutput)
- [m_videoOutput release];
- if (m_subtitleOutput)
- [m_subtitleOutput release];
- if (m_subtitleDelegate)
- [m_subtitleDelegate release];
-}
-
-void AVFVideoRendererControl::reconfigure()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << "reconfigure";
-#endif
- if (!m_layer) {
- m_displayLink->stop();
- return;
- }
-
- QMutexLocker locker(&m_mutex);
-
- m_displayLink->start();
-
- nativeSizeChanged();
-}
-
-void AVFVideoRendererControl::setLayer(CALayer *layer)
-{
- if (m_layer == layer)
- return;
-
- AVPlayerLayer *plLayer = playerLayer();
- if (plLayer) {
- if (m_videoOutput)
- [[[plLayer player] currentItem] removeOutput:m_videoOutput];
-
- if (m_subtitleOutput)
- [[[plLayer player] currentItem] removeOutput:m_subtitleOutput];
- }
-
- if (!layer && m_sink)
- m_sink->setVideoFrame(QVideoFrame());
-
- AVFVideoSinkInterface::setLayer(layer);
-}
-
-void AVFVideoRendererControl::updateVideoFrame(const CVTimeStamp &ts)
-{
- Q_UNUSED(ts);
-
- if (!m_sink)
- return;
-
- if (!m_layer)
- return;
-
- auto *layer = playerLayer();
- if (!layer.readyForDisplay)
- return;
- nativeSizeChanged();
-
- QVideoFrame frame;
- size_t width, height;
- CVPixelBufferRef pixelBuffer = copyPixelBufferFromLayer(width, height);
- if (!pixelBuffer)
- return;
- AVFVideoBuffer *buffer = new AVFVideoBuffer(this, pixelBuffer);
- auto fmt = buffer->fromCVVideoPixelFormat(CVPixelBufferGetPixelFormatType(pixelBuffer));
-// qDebug() << "Got pixelbuffer with format" << fmt << Qt::hex << CVPixelBufferGetPixelFormatType(pixelBuffer);
- CVPixelBufferRelease(pixelBuffer);
-
- QVideoFrameFormat format(QSize(width, height), fmt);
-
- frame = QVideoFrame(buffer, format);
- m_sink->setVideoFrame(frame);
-}
-
-static NSDictionary* const AVF_OUTPUT_SETTINGS = @{
- (NSString *)kCVPixelBufferPixelFormatTypeKey: @[
- @(kCVPixelFormatType_32BGRA),
- @(kCVPixelFormatType_32RGBA),
- @(kCVPixelFormatType_422YpCbCr8),
- @(kCVPixelFormatType_422YpCbCr8_yuvs),
- @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange),
- @(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange),
- @(kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange),
- @(kCVPixelFormatType_420YpCbCr10BiPlanarFullRange),
- @(kCVPixelFormatType_OneComponent8),
- @(q_kCVPixelFormatType_OneComponent16),
- @(kCVPixelFormatType_420YpCbCr8Planar),
- @(kCVPixelFormatType_420YpCbCr8PlanarFullRange)
- ],
- (NSString *)kCVPixelBufferMetalCompatibilityKey: @true
-};
-
-// The OpengGL texture cache can apparently only handle single plane formats, so lets simply restrict to BGRA
-static NSDictionary* const AVF_OUTPUT_SETTINGS_OPENGL = @{
- (NSString *)kCVPixelBufferPixelFormatTypeKey: @[
- @(kCVPixelFormatType_32BGRA),
- ],
- (NSString *)kCVPixelBufferOpenGLCompatibilityKey: @true
-};
-
-CVPixelBufferRef AVFVideoRendererControl::copyPixelBufferFromLayer(size_t& width, size_t& height)
-{
- AVPlayerLayer *layer = playerLayer();
- //Is layer valid
- if (!layer) {
-#ifdef QT_DEBUG_AVF
- qWarning("copyPixelBufferFromLayer: invalid layer");
-#endif
- return nullptr;
- }
-
- AVPlayerItem * item = [[layer player] currentItem];
-
- if (!m_videoOutput) {
- auto *settings = (m_rhi && m_rhi->backend() == QRhi::OpenGLES2) ? AVF_OUTPUT_SETTINGS_OPENGL : AVF_OUTPUT_SETTINGS;
- m_videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:settings];
- [m_videoOutput setDelegate:nil queue:nil];
- }
- if (!m_subtitleOutput) {
- m_subtitleOutput = [[AVPlayerItemLegibleOutput alloc] init];
- m_subtitleDelegate = [[SubtitleDelegate alloc] initWithRenderer:this];
- [m_subtitleOutput setDelegate:m_subtitleDelegate queue:dispatch_get_main_queue()];
- }
- if (![item.outputs containsObject:m_videoOutput])
- [item addOutput:m_videoOutput];
- if (![item.outputs containsObject:m_subtitleOutput])
- [item addOutput:m_subtitleOutput];
-
- CFTimeInterval currentCAFrameTime = CACurrentMediaTime();
- CMTime currentCMFrameTime = [m_videoOutput itemTimeForHostTime:currentCAFrameTime];
- // happens when buffering / loading
- if (CMTimeCompare(currentCMFrameTime, kCMTimeZero) < 0) {
- return nullptr;
- }
-
- if (![m_videoOutput hasNewPixelBufferForItemTime:currentCMFrameTime])
- return nullptr;
-
- CVPixelBufferRef pixelBuffer = [m_videoOutput copyPixelBufferForItemTime:currentCMFrameTime
- itemTimeForDisplay:nil];
- if (!pixelBuffer) {
-#ifdef QT_DEBUG_AVF
- qWarning("copyPixelBufferForItemTime returned nil");
- CMTimeShow(currentCMFrameTime);
-#endif
- return nullptr;
- }
-
- width = CVPixelBufferGetWidth(pixelBuffer);
- height = CVPixelBufferGetHeight(pixelBuffer);
-// auto f = CVPixelBufferGetPixelFormatType(pixelBuffer);
-// char fmt[5];
-// memcpy(fmt, &f, 4);
-// fmt[4] = 0;
-// qDebug() << "copyPixelBuffer" << f << fmt << width << height;
- return pixelBuffer;
-}
-
-#include "moc_avfvideorenderercontrol_p.cpp"
diff --git a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h b/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h
deleted file mode 100644
index ce0ec0738..000000000
--- a/src/multimedia/platform/darwin/mediaplayer/avfvideorenderercontrol_p.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef AVFVIDEORENDERERCONTROL_H
-#define AVFVIDEORENDERERCONTROL_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/QObject>
-#include <QtCore/QMutex>
-#include <QtCore/QSize>
-
-#include <private/avfvideosink_p.h>
-
-#include <CoreVideo/CVBase.h>
-#include <CoreVideo/CVPixelBuffer.h>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(CALayer);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVPlayerItemVideoOutput);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVPlayerItemLegibleOutput);
-Q_FORWARD_DECLARE_OBJC_CLASS(SubtitleDelegate);
-
-QT_BEGIN_NAMESPACE
-
-class AVFDisplayLink;
-
-class AVFVideoRendererControl : public QObject, public AVFVideoSinkInterface
-{
- Q_OBJECT
-public:
- explicit AVFVideoRendererControl(QObject *parent = nullptr);
- virtual ~AVFVideoRendererControl();
-
- // AVFVideoSinkInterface
- void reconfigure() override;
- void setLayer(CALayer *layer) override;
-
- void setSubtitleText(const QString &subtitle)
- {
- m_sink->setSubtitleText(subtitle);
- }
-private Q_SLOTS:
- void updateVideoFrame(const CVTimeStamp &ts);
-
-private:
- AVPlayerLayer *playerLayer() const { return static_cast<AVPlayerLayer *>(m_layer); }
- CVPixelBufferRef copyPixelBufferFromLayer(size_t& width, size_t& height);
-
- QMutex m_mutex;
- AVFDisplayLink *m_displayLink = nullptr;
- AVPlayerItemVideoOutput *m_videoOutput = nullptr;
- AVPlayerItemLegibleOutput *m_subtitleOutput = nullptr;
- SubtitleDelegate *m_subtitleDelegate = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // AVFVIDEORENDERERCONTROL_H
diff --git a/src/multimedia/platform/darwin/qdarwinformatsinfo.mm b/src/multimedia/platform/darwin/qdarwinformatsinfo.mm
deleted file mode 100644
index 9d27a843d..000000000
--- a/src/multimedia/platform/darwin/qdarwinformatsinfo.mm
+++ /dev/null
@@ -1,246 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdarwinformatsinfo_p.h"
-#include <AVFoundation/AVFoundation.h>
-#include <qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-static struct {
- const char *name;
- QMediaFormat::FileFormat value;
-} mediaContainerMap[] = {
- { "video/x-ms-asf", QMediaFormat::WMV },
- { "video/avi", QMediaFormat::AVI },
- { "video/x-matroska", QMediaFormat::Matroska },
- { "video/mp4", QMediaFormat::MPEG4 },
- { "video/quicktime", QMediaFormat::QuickTime },
- { "video/ogg", QMediaFormat::Ogg },
- { "audio/mp3", QMediaFormat::MP3 },
- { nullptr, QMediaFormat::UnspecifiedFormat }
-};
-
-static struct {
- const char *name;
- QMediaFormat::VideoCodec value;
-} videoCodecMap[] = {
- // See CMVideoCodecType for the four character code names of codecs
- { "; codecs=\"mp1v\"", QMediaFormat::VideoCodec::MPEG1 },
- { "; codecs=\"mp2v\"", QMediaFormat::VideoCodec::MPEG2 },
- { "; codecs=\"mp4v\"", QMediaFormat::VideoCodec::MPEG4 },
- { "; codecs=\"avc1\"", QMediaFormat::VideoCodec::H264 },
- { "; codecs=\"hvc1\"", QMediaFormat::VideoCodec::H265 },
- { "; codecs=\"vp09\"", QMediaFormat::VideoCodec::VP9 },
- { "; codecs=\"av01\"", QMediaFormat::VideoCodec::AV1 }, // ### ????
- { "; codecs=\"jpeg\"", QMediaFormat::VideoCodec::MotionJPEG },
- { nullptr, QMediaFormat::VideoCodec::Unspecified }
-};
-
-static struct {
- const char *name;
- QMediaFormat::AudioCodec value;
-} audioCodecMap[] = {
- // AudioFile.h
- // ### The next two entries do not work, probably because they contain non a space and period and AVFoundation doesn't like that
- // We know they are supported on all Apple platforms, so we'll add them manually below
-// { "; codecs=\".mp3\"", QMediaFormat::AudioCodec::MP3 },
-// { "; codecs=\"aac \"", QMediaFormat::AudioCodec::AAC },
- { "; codecs=\"ac-3\"", QMediaFormat::AudioCodec::AC3 },
- { "; codecs=\"ec-3\"", QMediaFormat::AudioCodec::EAC3 },
- { "; codecs=\"flac\"", QMediaFormat::AudioCodec::FLAC },
- { "; codecs=\"alac\"", QMediaFormat::AudioCodec::ALAC },
- { "; codecs=\"opus\"", QMediaFormat::AudioCodec::Opus },
- { nullptr, QMediaFormat::AudioCodec::Unspecified },
-};
-
-QDarwinFormatInfo::QDarwinFormatInfo()
-{
- auto avtypes = [AVURLAsset audiovisualMIMETypes];
- for (AVFileType filetype in avtypes) {
- auto *m = mediaContainerMap;
- while (m->name) {
- if (strcmp(filetype.UTF8String, m->name)) {
- ++m;
- continue;
- }
-
- QList<QMediaFormat::VideoCodec> video;
- QList<QMediaFormat::AudioCodec> audio;
-
- auto *v = videoCodecMap;
- while (v->name) {
- QByteArray extendedMimetype = m->name;
- extendedMimetype += v->name;
- if ([AVURLAsset isPlayableExtendedMIMEType:[NSString stringWithUTF8String:extendedMimetype.constData()]])
- video << v->value;
- ++v;
- }
-
- auto *a = audioCodecMap;
- while (a->name) {
- QByteArray extendedMimetype = m->name;
- extendedMimetype += a->name;
- if ([AVURLAsset isPlayableExtendedMIMEType:[NSString stringWithUTF8String:extendedMimetype.constData()]])
- audio << a->value;
- ++a;
- }
- // Added manually, see comment in the list above
- if (m->value <= QMediaFormat::AAC)
- audio << QMediaFormat::AudioCodec::AAC;
- if (m->value < QMediaFormat::AAC || m->value == QMediaFormat::MP3)
- audio << QMediaFormat::AudioCodec::MP3;
-
- decoders << CodecMap{ m->value, audio, video };
- ++m;
- }
- }
-
- // seems AVFoundation only supports those for encoding
- encoders = {
- { QMediaFormat::MPEG4,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::ALAC },
- { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
- { QMediaFormat::QuickTime,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::ALAC },
- { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
- { QMediaFormat::Mpeg4Audio,
- { QMediaFormat::AudioCodec::AAC },
- {} },
- { QMediaFormat::Wave,
- { QMediaFormat::AudioCodec::Wave },
- {} },
- };
-
- // ###
- imageFormats << QImageCapture::JPEG;
-}
-
-QDarwinFormatInfo::~QDarwinFormatInfo()
-{
-}
-
-int QDarwinFormatInfo::audioFormatForCodec(QMediaFormat::AudioCodec codec)
-{
- int codecId = kAudioFormatMPEG4AAC;
- switch (codec) {
- case QMediaFormat::AudioCodec::Unspecified:
- case QMediaFormat::AudioCodec::DolbyTrueHD:
- case QMediaFormat::AudioCodec::Vorbis:
- case QMediaFormat::AudioCodec::WMA:
- // Unsupported, shouldn't happen. Fall back to AAC
- case QMediaFormat::AudioCodec::AAC:
- codecId = kAudioFormatMPEG4AAC;
- break;
- case QMediaFormat::AudioCodec::MP3:
- codecId = kAudioFormatMPEGLayer3;
- break;
- case QMediaFormat::AudioCodec::AC3:
- codecId = kAudioFormatAC3;
- break;
- case QMediaFormat::AudioCodec::EAC3:
- codecId = kAudioFormatEnhancedAC3;
- break;
- case QMediaFormat::AudioCodec::FLAC:
- codecId = kAudioFormatFLAC;
- break;
- case QMediaFormat::AudioCodec::ALAC:
- codecId = kAudioFormatAppleLossless;
- break;
- case QMediaFormat::AudioCodec::Opus:
- codecId = kAudioFormatOpus;
- break;
- case QMediaFormat::AudioCodec::Wave:
- codecId = kAudioFormatLinearPCM;
- }
- return codecId;
-}
-
-NSString *QDarwinFormatInfo::videoFormatForCodec(QMediaFormat::VideoCodec codec)
-{
- const char *c = "hvc1"; // fallback is H265
- switch (codec) {
- case QMediaFormat::VideoCodec::Unspecified:
- case QMediaFormat::VideoCodec::VP8:
- case QMediaFormat::VideoCodec::H265:
- case QMediaFormat::VideoCodec::AV1:
- case QMediaFormat::VideoCodec::Theora:
- case QMediaFormat::VideoCodec::WMV:
- break;
-
- case QMediaFormat::VideoCodec::MPEG1:
- c = "mp1v";
- break;
- case QMediaFormat::VideoCodec::MPEG2:
- c = "mp2v";
- break;
- case QMediaFormat::VideoCodec::MPEG4:
- c = "mp4v";
- break;
- case QMediaFormat::VideoCodec::H264:
- c = "avc1";
- break;
- case QMediaFormat::VideoCodec::VP9:
- c = "vp09";
- break;
- case QMediaFormat::VideoCodec::MotionJPEG:
- c = "jpeg";
- }
- return [NSString stringWithUTF8String:c];
-}
-
-NSString *QDarwinFormatInfo::avFileTypeForContainerFormat(QMediaFormat::FileFormat container)
-{
- switch (container) {
- case QMediaFormat::MPEG4:
- return AVFileTypeMPEG4;
- case QMediaFormat::QuickTime:
- return AVFileTypeQuickTimeMovie;
- case QMediaFormat::MP3:
- return AVFileTypeMPEGLayer3;
- case QMediaFormat::Mpeg4Audio:
- return AVFileTypeAppleM4A;
- case QMediaFormat::Wave:
- return AVFileTypeWAVE;
- default:
- return AVFileTypeQuickTimeMovie;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/qdarwinformatsinfo_p.h b/src/multimedia/platform/darwin/qdarwinformatsinfo_p.h
deleted file mode 100644
index 79e33b6f4..000000000
--- a/src/multimedia/platform/darwin/qdarwinformatsinfo_p.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDARWINFORMATINFO_H
-#define QDARWINFORMATINFO_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaformatinfo_p.h>
-#include <qlist.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDarwinMediaDevices;
-
-class QDarwinFormatInfo : public QPlatformMediaFormatInfo
-{
-public:
- QDarwinFormatInfo();
- ~QDarwinFormatInfo();
-
- static int audioFormatForCodec(QMediaFormat::AudioCodec codec);
- static NSString *videoFormatForCodec(QMediaFormat::VideoCodec codec);
- static NSString *avFileTypeForContainerFormat(QMediaFormat::FileFormat fileType);
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/qdarwinintegration.mm b/src/multimedia/platform/darwin/qdarwinintegration.mm
deleted file mode 100644
index 372ce9e81..000000000
--- a/src/multimedia/platform/darwin/qdarwinintegration.mm
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdarwinintegration_p.h"
-#include "qdarwinmediadevices_p.h"
-#include <private/avfmediaplayer_p.h>
-#include <private/avfcameraservice_p.h>
-#include <private/avfcamera_p.h>
-#include <private/avfimagecapture_p.h>
-#include <private/avfmediaencoder_p.h>
-#include <private/qdarwinformatsinfo_p.h>
-#include <private/avfvideosink_p.h>
-#include <private/avfaudiodecoder_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QDarwinIntegration::QDarwinIntegration()
-{
-
-}
-
-QDarwinIntegration::~QDarwinIntegration()
-{
- delete m_devices;
- delete m_formatInfo;
-}
-
-QPlatformMediaDevices *QDarwinIntegration::devices()
-{
- if (!m_devices)
- m_devices = new QDarwinMediaDevices();
- return m_devices;
-}
-
-QPlatformMediaFormatInfo *QDarwinIntegration::formatInfo()
-{
- if (!m_formatInfo)
- m_formatInfo = new QDarwinFormatInfo();
- return m_formatInfo;
-}
-
-QPlatformAudioDecoder *QDarwinIntegration::createAudioDecoder(QAudioDecoder *decoder)
-{
- return new AVFAudioDecoder(decoder);
-}
-
-QPlatformMediaCaptureSession *QDarwinIntegration::createCaptureSession()
-{
- return new AVFCameraService;
-}
-
-QPlatformMediaPlayer *QDarwinIntegration::createPlayer(QMediaPlayer *player)
-{
- return new AVFMediaPlayer(player);
-}
-
-QPlatformCamera *QDarwinIntegration::createCamera(QCamera *camera)
-{
- return new AVFCamera(camera);
-}
-
-QPlatformMediaEncoder *QDarwinIntegration::createEncoder(QMediaRecorder *encoder)
-{
- return new AVFMediaEncoder(encoder);
-}
-
-QPlatformImageCapture *QDarwinIntegration::createImageCapture(QImageCapture *imageCapture)
-{
- return new AVFImageCapture(imageCapture);
-}
-
-QPlatformVideoSink *QDarwinIntegration::createVideoSink(QVideoSink *sink)
-{
- return new AVFVideoSink(sink);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/qdarwinintegration_p.h b/src/multimedia/platform/darwin/qdarwinintegration_p.h
deleted file mode 100644
index 946300761..000000000
--- a/src/multimedia/platform/darwin/qdarwinintegration_p.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDARWININTEGRATION_H
-#define QDARWININTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDarwinMediaDevices;
-
-class QDarwinIntegration : public QPlatformMediaIntegration
-{
-public:
- QDarwinIntegration();
- ~QDarwinIntegration();
-
- QPlatformMediaDevices *devices() override;
- QPlatformMediaFormatInfo *formatInfo() override;
-
- QPlatformAudioDecoder *createAudioDecoder(QAudioDecoder *) override;
- QPlatformMediaCaptureSession *createCaptureSession() override;
- QPlatformMediaPlayer *createPlayer(QMediaPlayer *player) override;
- QPlatformCamera *createCamera(QCamera *camera) override;
- QPlatformMediaEncoder *createEncoder(QMediaRecorder *) override;
- QPlatformImageCapture *createImageCapture(QImageCapture *) override;
-
- QPlatformVideoSink *createVideoSink(QVideoSink *) override;
-
- QDarwinMediaDevices *m_devices = nullptr;
- QPlatformMediaFormatInfo *m_formatInfo = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/darwin/qdarwinmediadevices.mm b/src/multimedia/platform/darwin/qdarwinmediadevices.mm
deleted file mode 100644
index b7bb6e7f9..000000000
--- a/src/multimedia/platform/darwin/qdarwinmediadevices.mm
+++ /dev/null
@@ -1,348 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdarwinmediadevices_p.h"
-#include "qmediadevices.h"
-#include "qcameradevice_p.h"
-#include "qaudiodevice_p.h"
-#include "private/qdarwinaudiodevice_p.h"
-#include "private/qdarwinaudiosource_p.h"
-#include "private/qdarwinaudiosink_p.h"
-#include "private/avfcamera_p.h"
-#include "private/avfcamerautility_p.h"
-#include "private/avfvideobuffer_p.h"
-
-#include <CoreVideo/CoreVideo.h>
-#import <AVFoundation/AVFoundation.h>
-
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-#include "private/qcoreaudiosessionmanager_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#if defined(Q_OS_MACOS)
-AudioDeviceID defaultAudioDevice(QAudioDevice::Mode mode)
-{
- AudioDeviceID audioDevice;
- UInt32 size = sizeof(audioDevice);
- const AudioObjectPropertySelector selector = (mode == QAudioDevice::Output) ? kAudioHardwarePropertyDefaultOutputDevice
- : kAudioHardwarePropertyDefaultInputDevice;
- AudioObjectPropertyAddress defaultDevicePropertyAddress = { selector,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- if (AudioObjectGetPropertyData(kAudioObjectSystemObject,
- &defaultDevicePropertyAddress,
- 0, NULL, &size, &audioDevice) != noErr) {
- qWarning("QAudioDevice: Unable to find default %s device", (mode == QAudioDevice::Output) ? "output" : "input");
- return 0;
- }
-
- return audioDevice;
-}
-
-static QByteArray uniqueId(AudioDeviceID device, QAudioDevice::Mode mode)
-{
- CFStringRef name;
- UInt32 size = sizeof(CFStringRef);
-
- AudioObjectPropertyScope audioPropertyScope = mode == QAudioDevice::Input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
-
- AudioObjectPropertyAddress audioDeviceNamePropertyAddress = { kAudioDevicePropertyDeviceUID,
- audioPropertyScope,
- kAudioObjectPropertyElementMaster };
-
- if (AudioObjectGetPropertyData(device, &audioDeviceNamePropertyAddress, 0, NULL, &size, &name) != noErr) {
- qWarning() << "QAudioDevice: Unable to get device UID";
- return QByteArray();
- }
-
- QString s = QString::fromCFString(name);
- CFRelease(name);
- return s.toUtf8();
-}
-
-QList<QAudioDevice> availableAudioDevices(QAudioDevice::Mode mode)
-{
-
- QList<QAudioDevice> devices;
-
- AudioDeviceID defaultDevice = defaultAudioDevice(mode);
- if (defaultDevice != 0)
- devices << (new QCoreAudioDeviceInfo(defaultDevice, uniqueId(defaultDevice, mode), mode))->create();
-
- UInt32 propSize = 0;
- AudioObjectPropertyAddress audioDevicesPropertyAddress = { kAudioHardwarePropertyDevices,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
- &audioDevicesPropertyAddress,
- 0, NULL, &propSize) == noErr) {
-
- const int dc = propSize / sizeof(AudioDeviceID);
-
- if (dc > 0) {
- AudioDeviceID* audioDevices = new AudioDeviceID[dc];
-
- if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &audioDevicesPropertyAddress, 0, NULL, &propSize, audioDevices) == noErr) {
- for (int i = 0; i < dc; ++i) {
- if (audioDevices[i] == defaultDevice)
- continue;
-
- AudioStreamBasicDescription sf;
- UInt32 size = sizeof(AudioStreamBasicDescription);
- AudioObjectPropertyAddress audioDeviceStreamFormatPropertyAddress = { kAudioDevicePropertyStreamFormat,
- (mode == QAudioDevice::Input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput),
- kAudioObjectPropertyElementMaster };
-
- if (AudioObjectGetPropertyData(audioDevices[i], &audioDeviceStreamFormatPropertyAddress, 0, NULL, &size, &sf) == noErr)
- devices << (new QCoreAudioDeviceInfo(audioDevices[i], uniqueId(audioDevices[i], mode), mode))->create();
- }
- }
-
- delete[] audioDevices;
- }
- }
-
- return devices;
-}
-
-static OSStatus
-audioDeviceChangeListener(AudioObjectID, UInt32, const AudioObjectPropertyAddress*, void* ptr)
-{
- QDarwinMediaDevices *m = static_cast<QDarwinMediaDevices *>(ptr);
- m->updateAudioDevices();
- return 0;
-}
-#endif
-
-
-QDarwinMediaDevices::QDarwinMediaDevices()
- : QPlatformMediaDevices()
-{
- NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
- m_deviceConnectedObserver = [notificationCenter addObserverForName:AVCaptureDeviceWasConnectedNotification
- object:nil
- queue:[NSOperationQueue mainQueue]
- usingBlock:^(NSNotification *) {
- this->updateCameraDevices();
- this->updateAudioDevices();
- }];
-
- m_deviceDisconnectedObserver = [notificationCenter addObserverForName:AVCaptureDeviceWasDisconnectedNotification
- object:nil
- queue:[NSOperationQueue mainQueue]
- usingBlock:^(NSNotification *) {
- this->updateCameraDevices();
- this->updateAudioDevices();
- }];
-
-#ifdef Q_OS_MACOS
- OSStatus err = noErr;
- AudioObjectPropertyAddress *audioDevicesAddress = new AudioObjectPropertyAddress{ kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- m_audioDevicesProperty = audioDevicesAddress;
- err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, audioDevicesAddress, audioDeviceChangeListener, this);
- if (err)
- qDebug("error on AudioObjectAddPropertyListener");
-#else
- // ### This should use the audio session manager
-#endif
- updateCameraDevices();
- updateAudioDevices();
-}
-
-
-QDarwinMediaDevices::~QDarwinMediaDevices()
-{
- NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
- [notificationCenter removeObserver:(id)m_deviceConnectedObserver];
- [notificationCenter removeObserver:(id)m_deviceDisconnectedObserver];
-
-#ifdef Q_OS_MACOS
- AudioObjectRemovePropertyListener(kAudioObjectSystemObject, (AudioObjectPropertyAddress *)m_audioDevicesProperty, audioDeviceChangeListener, this);
-#endif
-}
-
-QList<QAudioDevice> QDarwinMediaDevices::audioInputs() const
-{
-#ifdef Q_OS_IOS
- // TODO: Support Bluetooth and USB devices
- QList<QAudioDevice> devices;
- AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession = [AVCaptureDeviceDiscoverySession
- discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInMicrophone]
- mediaType:AVMediaTypeAudio
- position:AVCaptureDevicePositionUnspecified];
-
- NSArray *captureDevices = [captureDeviceDiscoverySession devices];
- for (AVCaptureDevice *device in captureDevices)
- devices << (new QCoreAudioDeviceInfo(QString::fromNSString(device.uniqueID).toUtf8(), QAudioDevice::Input))->create();
- return devices;
-#else
- return availableAudioDevices(QAudioDevice::Input);
-#endif
-}
-
-QList<QAudioDevice> QDarwinMediaDevices::audioOutputs() const
-{
-#ifdef Q_OS_IOS
- QList<QAudioDevice> devices;
- devices.append((new QCoreAudioDeviceInfo("default", QAudioDevice::Output))->create());
- return devices;
-#else
- return availableAudioDevices(QAudioDevice::Output);
-#endif
-}
-
-QList<QCameraDevice> QDarwinMediaDevices::videoInputs() const
-{
- return m_cameraDevices;
-}
-
-void QDarwinMediaDevices::updateCameraDevices()
-{
-#ifdef Q_OS_IOS
- // Cameras can't change dynamically on iOS. Update only once.
- if (!m_cameraDevices.isEmpty())
- return;
-#endif
-
- QList<QCameraDevice> cameras;
-
- AVCaptureDevice *defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
- NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
-
- for (AVCaptureDevice *device in videoDevices) {
-
- QCameraDevicePrivate *info = new QCameraDevicePrivate;
- if (defaultDevice && [defaultDevice.uniqueID isEqualToString:device.uniqueID])
- info->isDefault = true;
- info->id = QByteArray([[device uniqueID] UTF8String]);
- info->description = QString::fromNSString([device localizedName]);
-
- QSet<QSize> photoResolutions;
- QList<QCameraFormat> videoFormats;
-
- for (AVCaptureDeviceFormat *format in device.formats) {
- if (![format.mediaType isEqualToString:AVMediaTypeVideo])
- continue;
-
- auto dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
- QSize resolution(dimensions.width, dimensions.height);
- photoResolutions.insert(resolution);
-
- float maxFrameRate = 0;
- float minFrameRate = 1.e6;
-
- auto encoding = CMVideoFormatDescriptionGetCodecType(format.formatDescription);
- auto pixelFormat = AVFVideoBuffer::fromCVPixelFormat(encoding);
- // Ignore pixel formats we can't handle
- if (pixelFormat == QVideoFrameFormat::Format_Invalid)
- continue;
-
- for (AVFrameRateRange *frameRateRange in format.videoSupportedFrameRateRanges) {
- if (frameRateRange.minFrameRate < minFrameRate)
- minFrameRate = frameRateRange.minFrameRate;
- if (frameRateRange.maxFrameRate > maxFrameRate)
- maxFrameRate = frameRateRange.maxFrameRate;
- }
-
-#ifdef Q_OS_IOS
- // From Apple's docs (iOS):
- // By default, AVCaptureStillImageOutput emits images with the same dimensions as
- // its source AVCaptureDevice instance’s activeFormat.formatDescription. However,
- // if you set this property to YES, the receiver emits still images at the capture
- // device’s highResolutionStillImageDimensions value.
- const QSize hrRes(qt_device_format_high_resolution(format));
- if (!hrRes.isNull() && hrRes.isValid())
- photoResolutions.insert(hrRes);
-#endif
-
- auto *f = new QCameraFormatPrivate{
- QSharedData(),
- pixelFormat,
- resolution,
- minFrameRate,
- maxFrameRate
- };
- videoFormats << f->create();
- }
- info->videoFormats = videoFormats;
- info->photoResolutions = photoResolutions.values();
-
- cameras.append(info->create());
- }
-
- if (cameras != m_cameraDevices) {
- m_cameraDevices = cameras;
- videoInputsChanged();
- }
-}
-
-
-void QDarwinMediaDevices::updateAudioDevices()
-{
-#ifdef Q_OS_MACOS
- QList<QAudioDevice> inputs = availableAudioDevices(QAudioDevice::Input);
- if (m_audioInputs != inputs) {
- m_audioInputs = inputs;
- audioInputsChanged();
- }
-
- QList<QAudioDevice> outputs = availableAudioDevices(QAudioDevice::Output);
- if (m_audioOutputs!= outputs) {
- m_audioOutputs = outputs;
- audioOutputsChanged();
- }
-#endif
-}
-
-QPlatformAudioSource *QDarwinMediaDevices::createAudioSource(const QAudioDevice &info)
-{
- return new QDarwinAudioSource(info);
-}
-
-QPlatformAudioSink *QDarwinMediaDevices::createAudioSink(const QAudioDevice &info)
-{
- return new QDarwinAudioSink(info);
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/qdarwinmediadevices_p.h b/src/multimedia/platform/darwin/qdarwinmediadevices_p.h
deleted file mode 100644
index 0c3515f2b..000000000
--- a/src/multimedia/platform/darwin/qdarwinmediadevices_p.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDARWINMEDIADEVICES_H
-#define QDARWINMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <qelapsedtimer.h>
-#include <qcameradevice.h>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
-Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureDeviceDiscoverySession);
-
-QT_BEGIN_NAMESPACE
-
-class QCameraDevice;
-
-class QDarwinMediaDevices : public QPlatformMediaDevices
-{
-public:
- QDarwinMediaDevices();
- ~QDarwinMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &info) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &info) override;
-
- void updateCameraDevices();
- void updateAudioDevices();
-
-private:
- QList<QCameraDevice> m_cameraDevices;
- QList<QAudioDevice> m_audioInputs;
- QList<QAudioDevice> m_audioOutputs;
-
- NSObject *m_deviceConnectedObserver;
- NSObject *m_deviceDisconnectedObserver;
-#ifdef Q_OS_MACOS
- void *m_audioDevicesProperty;
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp b/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp
deleted file mode 100644
index dc44a1c38..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp
+++ /dev/null
@@ -1,558 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//#define DEBUG_DECODER
-
-#include "qgstreameraudiodecoder_p.h"
-#include "private/qgstreamermessage_p.h"
-
-#include <private/qgstutils_p.h>
-
-#include <gst/gstvalue.h>
-#include <gst/base/gstbasesrc.h>
-
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qurl.h>
-
-#define MAX_BUFFERS_IN_QUEUE 4
-
-QT_BEGIN_NAMESPACE
-
-typedef enum {
- GST_PLAY_FLAG_VIDEO = 0x00000001,
- GST_PLAY_FLAG_AUDIO = 0x00000002,
- GST_PLAY_FLAG_TEXT = 0x00000004,
- GST_PLAY_FLAG_VIS = 0x00000008,
- GST_PLAY_FLAG_SOFT_VOLUME = 0x00000010,
- GST_PLAY_FLAG_NATIVE_AUDIO = 0x00000020,
- GST_PLAY_FLAG_NATIVE_VIDEO = 0x00000040,
- GST_PLAY_FLAG_DOWNLOAD = 0x00000080,
- GST_PLAY_FLAG_BUFFERING = 0x000000100
-} GstPlayFlags;
-
-
-
-QGstreamerAudioDecoder::QGstreamerAudioDecoder(QAudioDecoder *parent)
- : QPlatformAudioDecoder(parent),
- m_playbin(GST_PIPELINE_CAST(QGstElement("playbin", "playbin").element()))
-{
- if (m_playbin.isNull()) {
- // ### set error
- return;
- }
-
- // Sort out messages
- m_playbin.installMessageFilter(this);
-
- // Set the rest of the pipeline up
- setAudioFlags(true);
-
- m_audioConvert = QGstElement("audioconvert", "audioconvert");
-
- m_outputBin = QGstBin("audio-output-bin");
- m_outputBin.add(m_audioConvert);
-
- // add ghostpad
- m_outputBin.addGhostPad(m_audioConvert, "sink");
-
- g_object_set(m_playbin.object(), "audio-sink", m_outputBin.element(), NULL);
- g_signal_connect(m_playbin.object(), "deep-notify::source", (GCallback) &QGstreamerAudioDecoder::configureAppSrcElement, (gpointer)this);
-
- // Set volume to 100%
- gdouble volume = 1.0;
- m_playbin.set("volume", volume);
-}
-
-QGstreamerAudioDecoder::~QGstreamerAudioDecoder()
-{
- if (m_playbin.isNull())
- return;
-
- stop();
-
-#if QT_CONFIG(gstreamer_app)
- delete m_appSrc;
-#endif
-}
-
-#if QT_CONFIG(gstreamer_app)
-void QGstreamerAudioDecoder::configureAppSrcElement(GObject* object, GObject *orig, GParamSpec *pspec, QGstreamerAudioDecoder *self)
-{
- Q_UNUSED(object);
- Q_UNUSED(pspec);
-
- // In case we switch from appsrc to not
- if (!self->appsrc())
- return;
-
- GstElement *appsrc;
- g_object_get(orig, "source", &appsrc, NULL);
-
- auto *qAppSrc = self->appsrc();
- qAppSrc->setExternalAppSrc(appsrc);
- qAppSrc->setup(self->mDevice);
-
- g_object_unref(G_OBJECT(appsrc));
-}
-#endif
-
-bool QGstreamerAudioDecoder::processBusMessage(const QGstreamerMessage &message)
-{
- GstMessage* gm = message.rawMessage();
- if (gm) {
- if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_DURATION) {
- updateDuration();
- } else if (GST_MESSAGE_SRC(gm) == m_playbin.object()) {
- switch (GST_MESSAGE_TYPE(gm)) {
- case GST_MESSAGE_STATE_CHANGED:
- {
- GstState oldState;
- GstState newState;
- GstState pending;
-
- gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
-
-#ifdef DEBUG_DECODER
- QStringList states;
- states << "GST_STATE_VOID_PENDING" << "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING";
-
- qDebug() << QString("state changed: old: %1 new: %2 pending: %3") \
- .arg(states[oldState]) \
- .arg(states[newState]) \
- .arg(states[pending]) << "internal" << m_state;
-#endif
-
- bool isDecoding = false;
- switch (newState) {
- case GST_STATE_VOID_PENDING:
- case GST_STATE_NULL:
- case GST_STATE_READY:
- break;
- case GST_STATE_PLAYING:
- isDecoding = true;
- break;
- case GST_STATE_PAUSED:
- isDecoding = true;
-
- //gstreamer doesn't give a reliable indication the duration
- //information is ready, GST_MESSAGE_DURATION is not sent by most elements
- //the duration is queried up to 5 times with increasing delay
- m_durationQueries = 5;
- updateDuration();
- break;
- }
-
- setIsDecoding(isDecoding);
- }
- break;
-
- case GST_MESSAGE_EOS:
- finished();
- break;
-
- case GST_MESSAGE_ERROR: {
- GError *err;
- gchar *debug;
- gst_message_parse_error(gm, &err, &debug);
- if (err->domain == GST_STREAM_ERROR && err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND)
- processInvalidMedia(QAudioDecoder::FormatError, tr("Cannot play stream of type: <unknown>"));
- else
- processInvalidMedia(QAudioDecoder::ResourceError, QString::fromUtf8(err->message));
- qWarning() << "Error:" << QString::fromUtf8(err->message);
- g_error_free(err);
- g_free(debug);
- }
- break;
- case GST_MESSAGE_WARNING:
- {
- GError *err;
- gchar *debug;
- gst_message_parse_warning (gm, &err, &debug);
- qWarning() << "Warning:" << QString::fromUtf8(err->message);
- g_error_free (err);
- g_free (debug);
- }
- break;
-#ifdef DEBUG_DECODER
- case GST_MESSAGE_INFO:
- {
- GError *err;
- gchar *debug;
- gst_message_parse_info (gm, &err, &debug);
- qDebug() << "Info:" << QString::fromUtf8(err->message);
- g_error_free (err);
- g_free (debug);
- }
- break;
-#endif
- default:
- break;
- }
- } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) {
- GError *err;
- gchar *debug;
- gst_message_parse_error(gm, &err, &debug);
- QAudioDecoder::Error qerror = QAudioDecoder::ResourceError;
- if (err->domain == GST_STREAM_ERROR) {
- switch (err->code) {
- case GST_STREAM_ERROR_DECRYPT:
- case GST_STREAM_ERROR_DECRYPT_NOKEY:
- qerror = QAudioDecoder::AccessDeniedError;
- break;
- case GST_STREAM_ERROR_FORMAT:
- case GST_STREAM_ERROR_DEMUX:
- case GST_STREAM_ERROR_DECODE:
- case GST_STREAM_ERROR_WRONG_TYPE:
- case GST_STREAM_ERROR_TYPE_NOT_FOUND:
- case GST_STREAM_ERROR_CODEC_NOT_FOUND:
- qerror = QAudioDecoder::FormatError;
- break;
- default:
- break;
- }
- } else if (err->domain == GST_CORE_ERROR) {
- switch (err->code) {
- case GST_CORE_ERROR_MISSING_PLUGIN:
- qerror = QAudioDecoder::FormatError;
- break;
- default:
- break;
- }
- }
-
- processInvalidMedia(qerror, QString::fromUtf8(err->message));
- g_error_free(err);
- g_free(debug);
- }
- }
-
- return false;
-}
-
-QUrl QGstreamerAudioDecoder::source() const
-{
- return mSource;
-}
-
-void QGstreamerAudioDecoder::setSource(const QUrl &fileName)
-{
- stop();
- mDevice = nullptr;
- delete m_appSrc;
- m_appSrc = nullptr;
-
- bool isSignalRequired = (mSource != fileName);
- mSource = fileName;
- if (isSignalRequired)
- emit sourceChanged();
-}
-
-QIODevice *QGstreamerAudioDecoder::sourceDevice() const
-{
- return mDevice;
-}
-
-void QGstreamerAudioDecoder::setSourceDevice(QIODevice *device)
-{
- stop();
- mSource.clear();
- bool isSignalRequired = (mDevice != device);
- mDevice = device;
- if (isSignalRequired)
- emit sourceChanged();
-}
-
-void QGstreamerAudioDecoder::start()
-{
- if (m_playbin.isNull()) {
- processInvalidMedia(QAudioDecoder::ResourceError, QLatin1String("Playbin element is not valid"));
- return;
- }
-
- addAppSink();
-
- if (!mSource.isEmpty()) {
- m_playbin.set("uri", mSource.toEncoded().constData());
- } else if (mDevice) {
- // make sure we can read from device
- if (!mDevice->isOpen() || !mDevice->isReadable()) {
- processInvalidMedia(QAudioDecoder::AccessDeniedError, QLatin1String("Unable to read from specified device"));
- return;
- }
-
- if (!m_appSrc)
- m_appSrc = new QGstAppSrc(this);
-
- m_playbin.set("uri", "appsrc://");
- } else {
- return;
- }
-
- // Set audio format
- if (m_appSink) {
- if (mFormat.isValid()) {
- setAudioFlags(false);
- QGstMutableCaps caps = QGstUtils::capsForAudioFormat(mFormat);
- gst_app_sink_set_caps(m_appSink, caps.get());
- } else {
- // We want whatever the native audio format is
- setAudioFlags(true);
- gst_app_sink_set_caps(m_appSink, nullptr);
- }
- }
-
- if (m_playbin.setState(GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
- qWarning() << "GStreamer; Unable to start decoding process";
- m_playbin.dumpGraph("failed");
- return;
- }
-}
-
-void QGstreamerAudioDecoder::stop()
-{
- if (m_playbin.isNull())
- return;
-
- m_playbin.setState(GST_STATE_NULL);
- removeAppSink();
-
- // GStreamer thread is stopped. Can safely access m_buffersAvailable
- if (m_buffersAvailable != 0) {
- m_buffersAvailable = 0;
- emit bufferAvailableChanged(false);
- }
-
- if (m_position != -1) {
- m_position = -1;
- emit positionChanged(m_position);
- }
-
- if (m_duration != -1) {
- m_duration = -1;
- emit durationChanged(m_duration);
- }
-
- setIsDecoding(false);
-}
-
-QAudioFormat QGstreamerAudioDecoder::audioFormat() const
-{
- return mFormat;
-}
-
-void QGstreamerAudioDecoder::setAudioFormat(const QAudioFormat &format)
-{
- if (mFormat != format) {
- mFormat = format;
- emit formatChanged(mFormat);
- }
-}
-
-QAudioBuffer QGstreamerAudioDecoder::read()
-{
- QAudioBuffer audioBuffer;
-
- int buffersAvailable;
- {
- QMutexLocker locker(&m_buffersMutex);
- buffersAvailable = m_buffersAvailable;
-
- // need to decrement before pulling a buffer
- // to make sure assert in QGstreamerAudioDecoderControl::new_buffer works
- m_buffersAvailable--;
- }
-
-
- if (buffersAvailable) {
- if (buffersAvailable == 1)
- emit bufferAvailableChanged(false);
-
- const char* bufferData = nullptr;
- int bufferSize = 0;
-
- GstSample *sample = gst_app_sink_pull_sample(m_appSink);
- GstBuffer *buffer = gst_sample_get_buffer(sample);
- GstMapInfo mapInfo;
- gst_buffer_map(buffer, &mapInfo, GST_MAP_READ);
- bufferData = (const char*)mapInfo.data;
- bufferSize = mapInfo.size;
- QAudioFormat format = QGstUtils::audioFormatForSample(sample);
-
- 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((const char*)bufferData, bufferSize), format, position);
- position /= 1000; // convert to milliseconds
- if (position != m_position) {
- m_position = position;
- emit positionChanged(m_position);
- }
- }
- gst_buffer_unmap(buffer, &mapInfo);
- gst_sample_unref(sample);
- }
-
- return audioBuffer;
-}
-
-bool QGstreamerAudioDecoder::bufferAvailable() const
-{
- QMutexLocker locker(&m_buffersMutex);
- return m_buffersAvailable > 0;
-}
-
-qint64 QGstreamerAudioDecoder::position() const
-{
- return m_position;
-}
-
-qint64 QGstreamerAudioDecoder::duration() const
-{
- return m_duration;
-}
-
-void QGstreamerAudioDecoder::processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString)
-{
- stop();
- emit error(int(errorCode), errorString);
-}
-
-GstFlowReturn QGstreamerAudioDecoder::new_sample(GstAppSink *, gpointer user_data)
-{
- // "Note that the preroll buffer will also be returned as the first buffer when calling gst_app_sink_pull_buffer()."
- QGstreamerAudioDecoder *decoder = reinterpret_cast<QGstreamerAudioDecoder*>(user_data);
-
- int buffersAvailable;
- {
- QMutexLocker locker(&decoder->m_buffersMutex);
- buffersAvailable = decoder->m_buffersAvailable;
- decoder->m_buffersAvailable++;
- Q_ASSERT(decoder->m_buffersAvailable <= MAX_BUFFERS_IN_QUEUE);
- }
-
- if (!buffersAvailable)
- decoder->bufferAvailableChanged(true);
- decoder->bufferReady();
- return GST_FLOW_OK;
-}
-
-void QGstreamerAudioDecoder::setAudioFlags(bool wantNativeAudio)
-{
- if (m_playbin.isNull())
- return;
-
- int flags = m_playbin.getInt("flags");
- // make sure not to use GST_PLAY_FLAG_NATIVE_AUDIO unless desired
- // it prevents audio format conversion
- flags &= ~(GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_TEXT | GST_PLAY_FLAG_VIS | GST_PLAY_FLAG_NATIVE_AUDIO);
- flags |= GST_PLAY_FLAG_AUDIO;
- if (wantNativeAudio)
- flags |= GST_PLAY_FLAG_NATIVE_AUDIO;
- m_playbin.set("flags", flags);
-}
-
-void QGstreamerAudioDecoder::addAppSink()
-{
- if (m_appSink)
- return;
-
- m_appSink = (GstAppSink*)gst_element_factory_make("appsink", nullptr);
-
- GstAppSinkCallbacks callbacks;
- memset(&callbacks, 0, sizeof(callbacks));
- callbacks.new_sample = &new_sample;
- gst_app_sink_set_callbacks(m_appSink, &callbacks, this, nullptr);
- gst_app_sink_set_max_buffers(m_appSink, MAX_BUFFERS_IN_QUEUE);
- gst_base_sink_set_sync(GST_BASE_SINK(m_appSink), FALSE);
-
- gst_bin_add(m_outputBin.bin(), GST_ELEMENT(m_appSink));
- gst_element_link(m_audioConvert.element(), GST_ELEMENT(m_appSink));
-}
-
-void QGstreamerAudioDecoder::removeAppSink()
-{
- if (!m_appSink)
- return;
-
- gst_element_unlink(m_audioConvert.element(), GST_ELEMENT(m_appSink));
- gst_bin_remove(m_outputBin.bin(), GST_ELEMENT(m_appSink));
-
- m_appSink = nullptr;
-}
-
-void QGstreamerAudioDecoder::updateDuration()
-{
- int duration = -1;
-
- if (!m_playbin.isNull())
- duration = m_playbin.duration() / 1000000;
-
- if (m_duration != duration) {
- m_duration = duration;
- emit durationChanged(m_duration);
- }
-
- if (m_duration > 0)
- m_durationQueries = 0;
-
- if (m_durationQueries > 0) {
- //increase delay between duration requests
- int delay = 25 << (5 - m_durationQueries);
- QTimer::singleShot(delay, this, SLOT(updateDuration()));
- m_durationQueries--;
- }
-}
-
-qint64 QGstreamerAudioDecoder::getPositionFromBuffer(GstBuffer* buffer)
-{
- qint64 position = GST_BUFFER_TIMESTAMP(buffer);
- if (position >= 0)
- position = position / G_GINT64_CONSTANT(1000); // microseconds
- else
- position = -1;
- return position;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder_p.h b/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder_p.h
deleted file mode 100644
index 693b00c3d..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder_p.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERAUDIODECODERCONTROL_H
-#define QGSTREAMERAUDIODECODERCONTROL_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/qtmultimediaglobal_p.h>
-#include <QObject>
-#include <QtCore/qmutex.h>
-#include <QtCore/qurl.h>
-
-#include "private/qplatformaudiodecoder_p.h"
-#include <private/qgstpipeline_p.h>
-#include "qaudiodecoder.h"
-
-#if QT_CONFIG(gstreamer_app)
-#include <private/qgstappsrc_p.h>
-#endif
-
-#include <private/qgst_p.h>
-#include <gst/app/gstappsink.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerMessage;
-
-class QGstreamerAudioDecoder
- : public QPlatformAudioDecoder,
- public QGstreamerBusMessageFilter
-{
- Q_OBJECT
-
-public:
- QGstreamerAudioDecoder(QAudioDecoder *parent);
- virtual ~QGstreamerAudioDecoder();
-
- QUrl source() const override;
- void setSource(const QUrl &fileName) override;
-
- QIODevice *sourceDevice() const override;
- void setSourceDevice(QIODevice *device) override;
-
- void start() override;
- void stop() override;
-
- QAudioFormat audioFormat() const override;
- void setAudioFormat(const QAudioFormat &format) override;
-
- QAudioBuffer read() override;
- bool bufferAvailable() const override;
-
- qint64 position() const override;
- qint64 duration() const override;
-
- // GStreamerBusMessageFilter interface
- bool processBusMessage(const QGstreamerMessage &message) override;
-
-#if QT_CONFIG(gstreamer_app)
- QGstAppSrc *appsrc() const { return m_appSrc; }
- static void configureAppSrcElement(GObject*, GObject*, GParamSpec*, QGstreamerAudioDecoder *_this);
-#endif
-
- static GstFlowReturn new_sample(GstAppSink *sink, gpointer user_data);
-
-private slots:
- void updateDuration();
-
-private:
- void setAudioFlags(bool wantNativeAudio);
- void addAppSink();
- void removeAppSink();
-
- void processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString);
- static qint64 getPositionFromBuffer(GstBuffer* buffer);
-
- QGstPipeline m_playbin;
- QGstBin m_outputBin;
- QGstElement m_audioConvert;
- GstAppSink *m_appSink = nullptr;
- QGstAppSrc *m_appSrc = nullptr;
-
- QUrl mSource;
- QIODevice *mDevice = nullptr;
- QAudioFormat mFormat;
-
- mutable QMutex m_buffersMutex;
- int m_buffersAvailable = 0;
-
- qint64 m_position = -1;
- qint64 m_duration = -1;
-
- int m_durationQueries = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERPLAYERSESSION_H
diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice.cpp b/src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice.cpp
deleted file mode 100644
index 301283013..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreameraudiodevice_p.h"
-
-#include <private/qgstutils_p.h>
-#include <private/qplatformmediaintegration_p.h>
-#include <private/qgstreamermediadevices_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QGStreamerAudioDeviceInfo::QGStreamerAudioDeviceInfo(GstDevice *d, const QByteArray &device, QAudioDevice::Mode mode)
- : QAudioDevicePrivate(device, mode),
- gstDevice(d)
-{
- Q_ASSERT(gstDevice);
- gst_object_ref(gstDevice);
-
- auto *n = gst_device_get_display_name(gstDevice);
- description = QString::fromUtf8(n);
- g_free(n);
-
- QGstCaps caps = gst_device_get_caps(gstDevice);
- int size = caps.size();
- for (int i = 0; i < size; ++i) {
- auto c = caps.at(i);
- if (c.name() == "audio/x-raw") {
- auto rate = c["rate"].toIntRange();
- if (rate) {
- minimumSampleRate = rate->min;
- maximumSampleRate = rate->max;
- }
- auto channels = c["channels"].toIntRange();
- if (channels) {
- minimumChannelCount = channels->min;
- maximumChannelCount = channels->max;
- }
- supportedSampleFormats = c["format"].getSampleFormats();
- }
- }
-
- preferredFormat.setChannelCount(qBound(minimumChannelCount, 2, maximumChannelCount));
- preferredFormat.setSampleRate(qBound(minimumSampleRate, 48000, maximumSampleRate));
- QAudioFormat::SampleFormat f = QAudioFormat::Int16;
- if (!supportedSampleFormats.contains(f))
- f = supportedSampleFormats.value(0, QAudioFormat::Unknown);
- preferredFormat.setSampleFormat(f);
-}
-
-QGStreamerAudioDeviceInfo::~QGStreamerAudioDeviceInfo()
-{
- if (gstDevice)
- gst_object_unref(gstDevice);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice_p.h b/src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice_p.h
deleted file mode 100644
index 9da109e38..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodevice_p.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERAUDIODEVICEINFO_H
-#define QGSTREAMERAUDIODEVICEINFO_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/qbytearray.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qlist.h>
-
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiodevice_p.h>
-
-#include <gst/gst.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGStreamerAudioDeviceInfo : public QAudioDevicePrivate
-{
-public:
- QGStreamerAudioDeviceInfo(GstDevice *gstDevice, const QByteArray &device, QAudioDevice::Mode mode);
- ~QGStreamerAudioDeviceInfo();
-
- GstDevice *gstDevice = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
-
diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiosink.cpp b/src/multimedia/platform/gstreamer/audio/qgstreameraudiosink.cpp
deleted file mode 100644
index 3bf5b597b..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiosink.cpp
+++ /dev/null
@@ -1,395 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <private/qaudiohelpers_p.h>
-
-#include "qgstreameraudiosink_p.h"
-#include "qgstreameraudiodevice_p.h"
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <private/qgstpipeline_p.h>
-#include <private/qgstappsrc_p.h>
-
-#include <private/qgstutils_p.h>
-#include <private/qgstreamermessage_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QGStreamerAudioSink::QGStreamerAudioSink(const QAudioDevice &device)
- : m_device(device.id()),
- gstPipeline("pipeline")
-{
- gstPipeline.installMessageFilter(this);
-
- m_appSrc = new QGstAppSrc;
- connect(m_appSrc, &QGstAppSrc::bytesProcessed, this, &QGStreamerAudioSink::bytesProcessedByAppSrc);
- connect(m_appSrc, &QGstAppSrc::noMoreData, this, &QGStreamerAudioSink::needData);
- gstAppSrc = m_appSrc->element();
-
- // gstDecodeBin = gst_element_factory_make ("decodebin", "dec");
- QGstElement queue("queue", "queue");
- QGstElement conv("audioconvert", "conv");
- gstVolume = QGstElement("volume", "volume");
- 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 = gst_device_create_element(audioInfo->gstDevice, nullptr);
-
- gstPipeline.add(gstAppSrc, queue, /*gstDecodeBin, */ conv, gstVolume, gstOutput);
- gstAppSrc.link(queue, conv, gstVolume, gstOutput);
-}
-
-QGStreamerAudioSink::~QGStreamerAudioSink()
-{
- close();
- 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);
-
- gchar *name = gst_pad_get_name(pad);
- qDebug("A new pad %s was created for %s\n", name, gst_element_get_name(element));
- g_free(name);
-
- 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.rawMessage();
- switch (GST_MESSAGE_TYPE (msg)) {
- case GST_MESSAGE_EOS:
- setState(QAudio::IdleState);
- break;
- case GST_MESSAGE_ERROR: {
- setError(QAudio::IOError);
- gchar *debug;
- GError *error;
-
- gst_message_parse_error (msg, &error, &debug);
- g_free (debug);
-
- qDebug("Error: %s\n", error->message);
- g_error_free (error);
-
- 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_pullMode ? QAudio::ActiveState : QAudio::IdleState);
- 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) {
- 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;
-}
-
-void QGStreamerAudioSink::needData()
-{
- if (state() != QAudio::StoppedState && state() != QAudio::IdleState) {
- setState(QAudio::IdleState);
- setError(QAudio::UnderrunError);
- }
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qgstreameraudiosink_p.cpp"
diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiosink_p.h b/src/multimedia/platform/gstreamer/audio/qgstreameraudiosink_p.h
deleted file mode 100644
index 872f0f241..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiosink_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QAUDIOOUTPUTPULSE_H
-#define QAUDIOOUTPUTPULSE_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/qgst_p.h>
-#include <private/qgstpipeline_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstAppSrc;
-
-class QGStreamerAudioSink
- : public QPlatformAudioSink,
- public QGstreamerBusMessageFilter
-{
- friend class GStreamerOutputPrivate;
- Q_OBJECT
-
-public:
- QGStreamerAudioSink(const QAudioDevice &device);
- ~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:
- 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;
- bool m_pullMode = true;
- bool m_opened = false;
- QIODevice *m_audioSource = nullptr;
- QTimer m_periodTimer;
- 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;
- QGstAppSrc *m_appSrc = nullptr;
-};
-
-class GStreamerOutputPrivate : public QIODevice
-{
- friend class QGStreamerAudioSink;
- Q_OBJECT
-
-public:
- GStreamerOutputPrivate(QGStreamerAudioSink *audio);
- virtual ~GStreamerOutputPrivate() {}
-
-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/multimedia/platform/gstreamer/audio/qgstreameraudiosource.cpp b/src/multimedia/platform/gstreamer/audio/qgstreameraudiosource.cpp
deleted file mode 100644
index ffa402627..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiosource.cpp
+++ /dev/null
@@ -1,407 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <private/qaudiohelpers_p.h>
-
-#include "qgstreameraudiosource_p.h"
-#include "qgstreameraudiodevice_p.h"
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gst/gst.h>
-Q_DECLARE_OPAQUE_POINTER(GstSample *);
-Q_DECLARE_METATYPE(GstSample *);
-
-QT_BEGIN_NAMESPACE
-
-
-QGStreamerAudioSource::QGStreamerAudioSource(const QAudioDevice &device)
- : 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(gst_device_create_element(deviceInfo->gstDevice, nullptr));
- 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("pipeline");
-
- 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("audioconvert", "conv");
- gstVolume = QGstElement("volume", "volume");
- if (m_volume != 1.)
- gstVolume.set("volume", m_volume);
-
- gstPipeline.add(gstInput, gstVolume, conv, gstAppSink);
- gstInput.link(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);
- gchar *debug;
- GError *error;
-
- gst_message_parse_error (msg, &error, &debug);
- g_free (debug);
-
- qDebug("Error: %s\n", error->message);
- g_error_free (error);
-
- 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
-
-QGstElement QGStreamerAudioSource::createAppSink()
-{
- QGstElement sink("appsink", "appsink");
- GstAppSink *appSink = reinterpret_cast<GstAppSink *>(sink.element());
-
- GstAppSinkCallbacks callbacks;
- memset(&callbacks, 0, sizeof(callbacks));
- callbacks.eos = &eos;
- callbacks.new_sample = &new_sample;
- gst_app_sink_set_callbacks(appSink, &callbacks, this, nullptr);
-// gst_app_sink_set_max_buffers(appSink, MAX_BUFFERS_IN_QUEUE);
- gst_base_sink_set_sync(GST_BASE_SINK(appSink), FALSE);
-
- return sink;
-}
-
-void QGStreamerAudioSource::newDataAvailable(GstSample *sample)
-{
- if (m_audioSink) {
- GstBuffer *buffer = gst_sample_get_buffer(sample);
- 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);
- }
-
- gst_sample_unref(sample);
-}
-
-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);
-
- GstSample *sample = gst_app_sink_pull_sample(sink);
- QMetaObject::invokeMethod(control, "newDataAvailable", Qt::AutoConnection, Q_ARG(GstSample *, 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 = qobject_cast<QGStreamerAudioSource*>(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
-
-#include "moc_qgstreameraudiosource_p.cpp"
diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiosource_p.h b/src/multimedia/platform/gstreamer/audio/qgstreameraudiosource_p.h
deleted file mode 100644
index 67e11c1c5..000000000
--- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiosource_p.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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 QAUDIOINPUTPULSE_H
-#define QAUDIOINPUTPULSE_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 <private/qgstutils_p.h>
-#include <private/qgstpipeline_p.h>
-#include <gst/app/gstappsink.h>
-
-QT_BEGIN_NAMESPACE
-
-class GStreamerInputPrivate;
-
-class QGStreamerAudioSource
- : public QPlatformAudioSource
-{
- Q_OBJECT
- friend class GStreamerInputPrivate;
-public:
- QGStreamerAudioSource(const QAudioDevice &device);
- ~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 Q_SLOTS:
- void newDataAvailable(GstSample *sample);
-
-private:
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
- QGstElement 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);
-
- 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;
- QGstElement gstAppSink;
-};
-
-class GStreamerInputPrivate : public QIODevice
-{
- Q_OBJECT
-public:
- GStreamerInputPrivate(QGStreamerAudioSource *audio);
- ~GStreamerInputPrivate() {};
-
- 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/multimedia/platform/gstreamer/common/qgst_p.h b/src/multimedia/platform/gstreamer/common/qgst_p.h
deleted file mode 100644
index 0130ca00f..000000000
--- a/src/multimedia/platform/gstreamer/common/qgst_p.h
+++ /dev/null
@@ -1,620 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGST_P_H
-#define QGST_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 <private/qtmultimediaglobal_p.h>
-
-#include <QSemaphore>
-#include <QtCore/qlist.h>
-
-#include <QtMultimedia/qaudioformat.h>
-#include <QtMultimedia/qvideoframe.h>
-
-#include <gst/gst.h>
-#include <gst/video/video-info.h>
-
-#include <functional>
-
-#if QT_CONFIG(gstreamer_photography)
-#define GST_USE_UNSTABLE_API
-#include <gst/interfaces/photography.h>
-#undef GST_USE_UNSTABLE_API
-#endif
-#ifndef QT_NO_DEBUG
-#include <qdebug.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QSize;
-class QGstStructure;
-class QGstCaps;
-class QGstPipelinePrivate;
-class QCameraFormat;
-
-template <typename T> struct QGRange
-{
- T min;
- T max;
-};
-
-class QGString
-{
- char *str;
-public:
- QGString(char *string) : str(string) {}
- ~QGString() { g_free(str); }
- operator QByteArray() { return QByteArray(str); }
- operator const char *() { return str; }
-};
-
-class QGValue
-{
-public:
- QGValue(const GValue *v) : value(v) {}
- const GValue *value;
-
- bool isNull() const { return !value; }
-
- std::optional<bool> toBool() const
- {
- if (!G_VALUE_HOLDS_BOOLEAN(value))
- return std::nullopt;
- return g_value_get_boolean(value);
- }
- std::optional<int> toInt() const
- {
- if (!G_VALUE_HOLDS_INT(value))
- return std::nullopt;
- return g_value_get_int(value);
- }
- std::optional<int> toInt64() const
- {
- if (!G_VALUE_HOLDS_INT64(value))
- return std::nullopt;
- return g_value_get_int64(value);
- }
- template<typename T>
- T *getPointer() const
- {
- return value ? static_cast<T *>(g_value_get_pointer(value)) : nullptr;
- }
-
- const char *toString() const
- {
- return value ? g_value_get_string(value) : nullptr;
- }
- std::optional<float> getFraction() const
- {
- if (!GST_VALUE_HOLDS_FRACTION(value))
- return std::nullopt;
- return (float)gst_value_get_fraction_numerator(value)/(float)gst_value_get_fraction_denominator(value);
- }
-
- std::optional<QGRange<float>> getFractionRange() const
- {
- if (!GST_VALUE_HOLDS_FRACTION_RANGE(value))
- return std::nullopt;
- QGValue min = gst_value_get_fraction_range_min(value);
- QGValue max = gst_value_get_fraction_range_max(value);
- return QGRange<float>{ *min.getFraction(), *max.getFraction() };
- }
-
- std::optional<QGRange<int>> toIntRange() const
- {
- if (!GST_VALUE_HOLDS_INT_RANGE(value))
- return std::nullopt;
- return QGRange<int>{ gst_value_get_int_range_min(value), gst_value_get_int_range_max(value) };
- }
-
- inline QGstStructure toStructure() const;
- inline QGstCaps toCaps() const;
-
- inline bool isList() const { return value && GST_VALUE_HOLDS_LIST(value); }
- inline int listSize() const { return gst_value_list_get_size(value); }
- inline QGValue at(int index) const { return gst_value_list_get_value(value, index); }
-
- Q_MULTIMEDIA_EXPORT QList<QAudioFormat::SampleFormat> getSampleFormats() const;
-};
-
-class QGstStructure {
-public:
- const GstStructure *structure = nullptr;
- QGstStructure() = default;
- QGstStructure(const GstStructure *s) : structure(s) {}
- void free() { if (structure) gst_structure_free(const_cast<GstStructure *>(structure)); structure = nullptr; }
-
- bool isNull() const { return !structure; }
-
- QByteArrayView name() const { return gst_structure_get_name(structure); }
-
- QGValue operator[](const char *name) const { return gst_structure_get_value(structure, name); }
-
- GstMessage *getMessage() const
- {
- GstMessage *msg;
- gst_structure_get(structure, "message", GST_TYPE_MESSAGE, &msg, nullptr);
- return msg;
- }
-
- Q_MULTIMEDIA_EXPORT QSize resolution() const;
- Q_MULTIMEDIA_EXPORT QVideoFrameFormat::PixelFormat pixelFormat() const;
- Q_MULTIMEDIA_EXPORT QGRange<float> frameRateRange() const;
-
- QByteArray toString() const
- {
- char *s = gst_structure_to_string(structure);
- QByteArray str(s);
- g_free(s);
- return str;
- }
- QGstStructure copy() const { return gst_structure_copy(structure); }
-};
-
-class QGstCaps {
- const GstCaps *caps = nullptr;
-public:
- enum MemoryFormat {
- CpuMemory,
- GLTexture,
- DMABuf
- };
-
- QGstCaps() = default;
- QGstCaps(const GstCaps *c) : caps(c) {}
-
- bool isNull() const { return !caps; }
-
- int size() const { return gst_caps_get_size(caps); }
- QGstStructure at(int index) { return gst_caps_get_structure(caps, index); }
- const GstCaps *get() const { return caps; }
- QByteArray toString() const
- {
- gchar *c = gst_caps_to_string(caps);
- QByteArray b(c);
- g_free(c);
- return b;
- }
- MemoryFormat memoryFormat() const {
- auto *features = gst_caps_get_features(caps, 0);
- if (gst_caps_features_contains(features, "memory:GLMemory"))
- return GLTexture;
- else if (gst_caps_features_contains(features, "memory:DMABuf"))
- return DMABuf;
- return CpuMemory;
- }
- QVideoFrameFormat formatForCaps(GstVideoInfo *info) const;
-};
-
-class QGstMutableCaps : public QGstCaps {
- GstCaps *caps = nullptr;
-public:
- enum RefMode { HasRef, NeedsRef };
- QGstMutableCaps() = default;
- QGstMutableCaps(GstCaps *c, RefMode mode = HasRef)
- : QGstCaps(c), caps(c)
- {
- Q_ASSERT(QGstCaps::get() == caps);
- if (mode == NeedsRef)
- gst_caps_ref(caps);
- }
- QGstMutableCaps(const QGstMutableCaps &other)
- : QGstCaps(other), caps(other.caps)
- {
- Q_ASSERT(QGstCaps::get() == caps);
- if (caps)
- gst_caps_ref(caps);
- }
- QGstMutableCaps &operator=(const QGstMutableCaps &other)
- {
- QGstCaps::operator=(other);
- if (other.caps)
- gst_caps_ref(other.caps);
- if (caps)
- gst_caps_unref(caps);
- caps = other.caps;
- Q_ASSERT(QGstCaps::get() == caps);
- return *this;
- }
- ~QGstMutableCaps() {
- Q_ASSERT(QGstCaps::get() == caps);
- if (caps)
- gst_caps_unref(caps);
- }
-
- void create() {
- caps = gst_caps_new_empty();
- QGstCaps::operator=(QGstCaps(caps));
- }
-
- void addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats, const char *modifier = nullptr);
- static QGstMutableCaps fromCameraFormat(const QCameraFormat &format);
-
- GstCaps *get() const { return caps; }
-};
-
-class QGstObject
-{
-protected:
- GstObject *m_object = nullptr;
-public:
- enum RefMode { HasRef, NeedsRef };
-
- QGstObject() = default;
- QGstObject(GstObject *o, RefMode mode = HasRef)
- : m_object(o)
- {
- if (o && mode == NeedsRef)
- // Use ref_sink to remove any floating references
- gst_object_ref_sink(m_object);
- }
- QGstObject(const QGstObject &other)
- : m_object(other.m_object)
- {
- if (m_object)
- gst_object_ref(m_object);
- }
- QGstObject &operator=(const QGstObject &other)
- {
- if (other.m_object)
- gst_object_ref(other.m_object);
- if (m_object)
- gst_object_unref(m_object);
- m_object = other.m_object;
- return *this;
- }
- ~QGstObject() {
- if (m_object)
- gst_object_unref(m_object);
- }
-
- friend bool operator==(const QGstObject &a, const QGstObject &b)
- { return a.m_object == b.m_object; }
- friend bool operator!=(const QGstObject &a, const QGstObject &b)
- { return a.m_object != b.m_object; }
-
- bool isNull() const { return !m_object; }
-
- void set(const char *property, const char *str) { g_object_set(m_object, property, str, nullptr); }
- void set(const char *property, bool b) { g_object_set(m_object, property, gboolean(b), nullptr); }
- void set(const char *property, uint i) { g_object_set(m_object, property, guint(i), nullptr); }
- void set(const char *property, int i) { g_object_set(m_object, property, gint(i), nullptr); }
- void set(const char *property, qint64 i) { g_object_set(m_object, property, gint64(i), nullptr); }
- void set(const char *property, quint64 i) { g_object_set(m_object, property, guint64(i), nullptr); }
- void set(const char *property, double d) { g_object_set(m_object, property, gdouble(d), nullptr); }
- void set(const char *property, const QGstObject &o) { g_object_set(m_object, property, o.object(), nullptr); }
- void set(const char *property, const QGstMutableCaps &c) { g_object_set(m_object, property, c.get(), nullptr); }
-
- QGString getString(const char *property) const
- { char *s = nullptr; g_object_get(m_object, property, &s, nullptr); return s; }
- QGstStructure getStructure(const char *property) const
- { GstStructure *s = nullptr; g_object_get(m_object, property, &s, nullptr); return QGstStructure(s); }
- bool getBool(const char *property) const { gboolean b = false; g_object_get(m_object, property, &b, nullptr); return b; }
- uint getUInt(const char *property) const { guint i = 0; g_object_get(m_object, property, &i, nullptr); return i; }
- int getInt(const char *property) const { gint i = 0; g_object_get(m_object, property, &i, nullptr); return i; }
- quint64 getUInt64(const char *property) const { guint64 i = 0; g_object_get(m_object, property, &i, nullptr); return i; }
- qint64 getInt64(const char *property) const { gint64 i = 0; g_object_get(m_object, property, &i, nullptr); return i; }
- float getFloat(const char *property) const { gfloat d = 0; g_object_get(m_object, property, &d, nullptr); return d; }
- double getDouble(const char *property) const { gdouble d = 0; g_object_get(m_object, property, &d, nullptr); return d; }
- QGstObject getObject(const char *property) const { GstObject *o = nullptr; g_object_get(m_object, property, &o, nullptr); return o; }
-
- void connect(const char *name, GCallback callback, gpointer userData) { g_signal_connect(m_object, name, callback, userData); }
-
- GstObject *object() const { return m_object; }
- const char *name() const { return m_object ? GST_OBJECT_NAME(m_object) : "(null)"; }
-};
-
-class QGstElement;
-
-class QGstPad : public QGstObject
-{
-public:
- QGstPad() = default;
- QGstPad(const QGstObject &o)
- : QGstPad(GST_PAD(o.object()), NeedsRef)
- {}
- QGstPad(GstPad *pad, RefMode mode = NeedsRef)
- : QGstObject(&pad->object, mode)
- {}
-
- QGstMutableCaps currentCaps() const
- { return QGstMutableCaps(gst_pad_get_current_caps(pad())); }
- QGstCaps queryCaps() const
- { return QGstCaps(gst_pad_query_caps(pad(), nullptr)); }
-
- bool isLinked() const { return gst_pad_is_linked(pad()); }
- bool link(const QGstPad &sink) const { return gst_pad_link(pad(), sink.pad()) == GST_PAD_LINK_OK; }
- bool unlink(const QGstPad &sink) const { return gst_pad_unlink(pad(), sink.pad()); }
- bool unlinkPeer() const { return unlink(peer()); }
- QGstPad peer() const { return QGstPad(gst_pad_get_peer(pad()), HasRef); }
- inline QGstElement parent() const;
-
- GstPad *pad() const { return GST_PAD_CAST(object()); }
-
- GstEvent *stickyEvent(GstEventType type) { return gst_pad_get_sticky_event(pad(), type, 0); }
- bool sendEvent(GstEvent *event) { return gst_pad_send_event (pad(), event); }
-
- template<auto Member, typename T>
- void addProbe(T *instance, GstPadProbeType type) {
- struct Impl {
- static GstPadProbeReturn callback(GstPad *pad, GstPadProbeInfo *info, gpointer userData) {
- return (static_cast<T *>(userData)->*Member)(QGstPad(pad, NeedsRef), info);
- };
- };
-
- gst_pad_add_probe (pad(), type, Impl::callback, instance, nullptr);
- }
-
- void doInIdleProbe(std::function<void()> work) {
- struct CallbackData {
- QSemaphore waitDone;
- std::function<void()> work;
- } cd;
- cd.work = work;
-
- auto callback= [](GstPad *, GstPadProbeInfo *, gpointer p) {
- auto cd = reinterpret_cast<CallbackData*>(p);
- cd->work();
- cd->waitDone.release();
- return GST_PAD_PROBE_REMOVE;
- };
-
- gst_pad_add_probe(pad(), GST_PAD_PROBE_TYPE_IDLE, callback, &cd, nullptr);
- cd.waitDone.acquire();
- }
-
- template<auto Member, typename T>
- void addEosProbe(T *instance) {
- struct Impl {
- static GstPadProbeReturn callback(GstPad */*pad*/, GstPadProbeInfo *info, gpointer userData) {
- if (GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS)
- return GST_PAD_PROBE_PASS;
- (static_cast<T *>(userData)->*Member)();
- return GST_PAD_PROBE_REMOVE;
- };
- };
-
- gst_pad_add_probe (pad(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, Impl::callback, instance, nullptr);
- }
-};
-
-class QGstClock : public QGstObject
-{
-public:
- QGstClock() = default;
- QGstClock(const QGstObject &o)
- : QGstClock(GST_CLOCK(o.object()))
- {}
- QGstClock(GstClock *clock, RefMode mode = NeedsRef)
- : QGstObject(&clock->object, mode)
- {}
-
- GstClock *clock() const { return GST_CLOCK_CAST(object()); }
-
- GstClockTime time() const { return gst_clock_get_time(clock()); }
-};
-
-class QGstElement : public QGstObject
-{
-public:
- QGstElement() = default;
- QGstElement(const QGstObject &o)
- : QGstElement(GST_ELEMENT(o.object()), NeedsRef)
- {}
- QGstElement(GstElement *element, RefMode mode = NeedsRef)
- : QGstObject(&element->object, mode)
- {}
-
- QGstElement(const char *factory, const char *name = nullptr)
- : QGstElement(gst_element_factory_make(factory, name), NeedsRef)
- {
- }
-
- bool linkFiltered(const QGstElement &next, const QGstMutableCaps &caps)
- { return gst_element_link_filtered(element(), next.element(), caps.get()); }
- bool link(const QGstElement &next)
- { return gst_element_link(element(), next.element()); }
- bool link(const QGstElement &n1, const QGstElement &n2)
- { return gst_element_link_many(element(), n1.element(), n2.element(), nullptr); }
- bool link(const QGstElement &n1, const QGstElement &n2, const QGstElement &n3)
- { return gst_element_link_many(element(), n1.element(), n2.element(), n3.element(), nullptr); }
- bool link(const QGstElement &n1, const QGstElement &n2, const QGstElement &n3, const QGstElement &n4)
- { return gst_element_link_many(element(), n1.element(), n2.element(), n3.element(), n4.element(), nullptr); }
- bool link(const QGstElement &n1, const QGstElement &n2, const QGstElement &n3, const QGstElement &n4, const QGstElement &n5)
- { return gst_element_link_many(element(), n1.element(), n2.element(), n3.element(), n4.element(), n5.element(), nullptr); }
-
- void unlink(const QGstElement &next)
- { gst_element_unlink(element(), next.element()); }
-
- QGstPad staticPad(const char *name) const { return QGstPad(gst_element_get_static_pad(element(), name), HasRef); }
- QGstPad src() const { return staticPad("src"); }
- QGstPad sink() const { return staticPad("sink"); }
- QGstPad getRequestPad(const char *name) const { return QGstPad(gst_element_get_request_pad(element(), name), HasRef); }
- void releaseRequestPad(const QGstPad &pad) const { return gst_element_release_request_pad(element(), pad.pad()); }
-
- GstState state() const
- {
- GstState state;
- gst_element_get_state(element(), &state, nullptr, 0);
- return state;
- }
- GstStateChangeReturn setState(GstState state) { return gst_element_set_state(element(), state); }
- bool setStateSync(GstState state)
- {
- auto change = gst_element_set_state(element(), state);
- if (change == GST_STATE_CHANGE_ASYNC) {
- change = gst_element_get_state(element(), nullptr, &state, 1000*1e6 /*nano seconds*/);
- }
-#ifndef QT_NO_DEBUG
- if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL)
- qWarning() << "Could not change state of" << name() << "to" << state << change;
-#endif
- return change == GST_STATE_CHANGE_SUCCESS;
- }
- bool syncStateWithParent() { return gst_element_sync_state_with_parent(element()) == TRUE; }
- bool finishStateChange()
- {
- auto change = gst_element_get_state(element(), nullptr, nullptr, 1000*1e6 /*nano seconds*/);
-#ifndef QT_NO_DEBUG
- if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL)
- qWarning() << "Could finish change state of" << name();
-#endif
- return change == GST_STATE_CHANGE_SUCCESS;
- }
-
- void lockState(bool locked) { gst_element_set_locked_state(element(), locked); }
- bool isStateLocked() const { return gst_element_is_locked_state(element()); }
-
- void sendEvent(GstEvent *event) const { gst_element_send_event(element(), event); }
- void sendEos() const { sendEvent(gst_event_new_eos()); }
-
- template<auto Member, typename T>
- void onPadAdded(T *instance) {
- struct Impl {
- static void callback(GstElement *e, GstPad *pad, gpointer userData) {
- (static_cast<T *>(userData)->*Member)(QGstElement(e), QGstPad(pad, NeedsRef));
- };
- };
-
- connect("pad-added", G_CALLBACK(Impl::callback), instance);
- }
- template<auto Member, typename T>
- void onPadRemoved(T *instance) {
- struct Impl {
- static void callback(GstElement *e, GstPad *pad, gpointer userData) {
- (static_cast<T *>(userData)->*Member)(QGstElement(e), QGstPad(pad, NeedsRef));
- };
- };
-
- connect("pad-removed", G_CALLBACK(Impl::callback), instance);
- }
- template<auto Member, typename T>
- void onNoMorePads(T *instance) {
- struct Impl {
- static void callback(GstElement *e, gpointer userData) {
- (static_cast<T *>(userData)->*Member)(QGstElement(e));
- };
- };
-
- connect("no-more-pads", G_CALLBACK(Impl::callback), instance);
- }
-
- GstClockTime baseTime() const { return gst_element_get_base_time(element()); }
- void setBaseTime(GstClockTime time) const { gst_element_set_base_time(element(), time); }
-
- GstElement *element() const { return GST_ELEMENT_CAST(m_object); }
-};
-
-inline QGstElement QGstPad::parent() const
-{
- return QGstElement(gst_pad_get_parent_element(pad()), HasRef);
-}
-
-class QGstBin : public QGstElement
-{
-public:
- QGstBin() = default;
- QGstBin(const QGstObject &o)
- : QGstBin(GST_BIN(o.object()), NeedsRef)
- {}
- QGstBin(const char *name)
- : QGstElement(gst_bin_new(name), NeedsRef)
- {
- }
- QGstBin(GstBin *bin, RefMode mode = NeedsRef)
- : QGstElement(&bin->element, mode)
- {}
-
- void add(const QGstElement &element)
- { gst_bin_add(bin(), element.element()); }
- void add(const QGstElement &e1, const QGstElement &e2)
- { gst_bin_add_many(bin(), e1.element(), e2.element(), nullptr); }
- void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3)
- { gst_bin_add_many(bin(), e1.element(), e2.element(), e3.element(), nullptr); }
- void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3, const QGstElement &e4)
- { gst_bin_add_many(bin(), e1.element(), e2.element(), e3.element(), e4.element(), nullptr); }
- void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3, const QGstElement &e4, const QGstElement &e5)
- { gst_bin_add_many(bin(), e1.element(), e2.element(), e3.element(), e4.element(), e5.element(), nullptr); }
- void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3, const QGstElement &e4, const QGstElement &e5, const QGstElement &e6)
- { gst_bin_add_many(bin(), e1.element(), e2.element(), e3.element(), e4.element(), e5.element(), e6.element(), nullptr); }
- void remove(const QGstElement &element)
- { gst_bin_remove(bin(), element.element()); }
-
- GstBin *bin() const { return GST_BIN_CAST(m_object); }
-
- void addGhostPad(const QGstElement &child, const char *name)
- {
- addGhostPad(name, child.staticPad(name));
- }
- void addGhostPad(const char *name, const QGstPad &pad)
- {
- gst_element_add_pad(element(), gst_ghost_pad_new(name, pad.pad()));
- }
-};
-
-inline QGstStructure QGValue::toStructure() const
-{
- if (!value || !GST_VALUE_HOLDS_STRUCTURE(value))
- return QGstStructure();
- return QGstStructure(gst_value_get_structure(value));
-}
-
-inline QGstCaps QGValue::toCaps() const
-{
- if (!value || !GST_VALUE_HOLDS_CAPS(value))
- return QGstCaps();
- return QGstCaps(gst_value_get_caps(value));
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp b/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp
deleted file mode 100644
index 992e3d5a9..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp
+++ /dev/null
@@ -1,308 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QDebug>
-
-#include "qgstappsrc_p.h"
-#include "qgstutils_p.h"
-#include "qnetworkreply.h"
-#include "qloggingcategory.h"
-
-Q_LOGGING_CATEGORY(qLcAppSrc, "qt.multimedia.appsrc")
-
-QGstAppSrc::QGstAppSrc(QObject *parent)
- : QObject(parent)
-{
- m_appSrc = QGstElement("appsrc", "appsrc");
- if (m_appSrc.isNull())
- qWarning() << "Could not create GstAppSrc.";
-}
-
-QGstAppSrc::~QGstAppSrc()
-{
- m_appSrc.setStateSync(GST_STATE_NULL);
- streamDestroyed();
- qCDebug(qLcAppSrc) << "~QGstAppSrc";
-}
-
-bool QGstAppSrc::setup(QIODevice *stream, qint64 offset)
-{
- if (m_appSrc.isNull())
- return false;
-
- if (!setStream(stream, offset))
- return false;
-
- auto *appSrc = GST_APP_SRC(m_appSrc.element());
- GstAppSrcCallbacks m_callbacks;
- memset(&m_callbacks, 0, sizeof(GstAppSrcCallbacks));
- m_callbacks.need_data = &QGstAppSrc::on_need_data;
- m_callbacks.enough_data = &QGstAppSrc::on_enough_data;
- m_callbacks.seek_data = &QGstAppSrc::on_seek_data;
- gst_app_src_set_callbacks(appSrc, (GstAppSrcCallbacks*)&m_callbacks, this, nullptr);
-
- m_maxBytes = gst_app_src_get_max_bytes(appSrc);
- m_suspended = false;
-
- if (m_sequential)
- m_streamType = GST_APP_STREAM_TYPE_STREAM;
- else
- m_streamType = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
- gst_app_src_set_stream_type(appSrc, m_streamType);
- gst_app_src_set_size(appSrc, m_sequential ? -1 : m_stream->size() - m_offset);
-
- m_networkReply = qobject_cast<QNetworkReply *>(m_stream);
- m_noMoreData = true;
-
- return true;
-}
-
-void QGstAppSrc::setAudioFormat(const QAudioFormat &f)
-{
- m_format = f;
- if (!m_format.isValid())
- return;
-
- auto caps = QGstUtils::capsForAudioFormat(m_format);
- Q_ASSERT(!caps.isNull());
- m_appSrc.set("caps", caps);
- m_appSrc.set("format", GST_FORMAT_TIME);
-}
-
-void QGstAppSrc::setExternalAppSrc(const QGstElement &appsrc)
-{
- m_appSrc = appsrc;
-}
-
-bool QGstAppSrc::setStream(QIODevice *stream, qint64 offset)
-{
- if (m_stream) {
- disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady()));
- disconnect(m_stream, SIGNAL(destroyed()), this, SLOT(streamDestroyed()));
- m_stream = nullptr;
- }
-
- m_dataRequestSize = 0;
- m_sequential = true;
- m_maxBytes = 0;
- streamedSamples = 0;
-
- if (stream) {
- if (!stream->isOpen() && !stream->open(QIODevice::ReadOnly))
- return false;
- m_stream = stream;
- connect(m_stream, SIGNAL(destroyed()), SLOT(streamDestroyed()));
- connect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady()));
- m_sequential = m_stream->isSequential();
- m_offset = offset;
- }
- return true;
-}
-
-QGstElement QGstAppSrc::element()
-{
- return m_appSrc;
-}
-
-void QGstAppSrc::write(const char *data, qsizetype size)
-{
- qCDebug(qLcAppSrc) << "write" << size << m_noMoreData << m_dataRequestSize;
- if (!size)
- return;
- Q_ASSERT(!m_stream);
- m_buffer.append(data, size);
- m_noMoreData = false;
- pushData();
-}
-
-void QGstAppSrc::onDataReady()
-{
- qCDebug(qLcAppSrc) << "onDataReady" << m_stream->bytesAvailable() << m_stream->size();
- pushData();
-}
-
-void QGstAppSrc::streamDestroyed()
-{
- qCDebug(qLcAppSrc) << "stream destroyed";
- m_stream = nullptr;
- m_dataRequestSize = 0;
- streamedSamples = 0;
- sendEOS();
-}
-
-void QGstAppSrc::pushData()
-{
- if (m_appSrc.isNull() || !m_dataRequestSize || m_suspended) {
- qCDebug(qLcAppSrc) << "push data: return immediately" << m_appSrc.isNull() << m_dataRequestSize << m_suspended;
- return;
- }
-
- qCDebug(qLcAppSrc) << "pushData" << (m_stream ? m_stream : nullptr) << m_buffer.size();
- if ((m_stream && m_stream->atEnd())) {
- eosOrIdle();
- qCDebug(qLcAppSrc) << "end pushData" << (m_stream ? m_stream : nullptr) << m_buffer.size();
- return;
- }
-
- qint64 size;
- if (m_stream)
- size = m_stream->bytesAvailable();
- else
- size = m_buffer.size();
-
- if (!m_dataRequestSize)
- m_dataRequestSize = m_maxBytes;
- size = qMin(size, (qint64)m_dataRequestSize);
- qCDebug(qLcAppSrc) << " reading" << size << "bytes" << size << m_dataRequestSize;
-
- GstBuffer* buffer = gst_buffer_new_and_alloc(size);
-
- if (m_sequential || !m_stream)
- buffer->offset = bytesReadSoFar;
- else
- buffer->offset = m_stream->pos();
-
- if (m_format.isValid()) {
- // timestamp raw audio data
- uint nSamples = size/m_format.bytesPerFrame();
-
- GST_BUFFER_TIMESTAMP(buffer) = gst_util_uint64_scale(streamedSamples, GST_SECOND, m_format.sampleRate());
- GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(nSamples, GST_SECOND, m_format.sampleRate());
- streamedSamples += nSamples;
- }
-
- GstMapInfo mapInfo;
- gst_buffer_map(buffer, &mapInfo, GST_MAP_WRITE);
- void* bufferData = mapInfo.data;
-
- qint64 bytesRead;
- if (m_stream)
- bytesRead = m_stream->read((char*)bufferData, size);
- else
- bytesRead = m_buffer.read((char*)bufferData, size);
- buffer->offset_end = buffer->offset + bytesRead - 1;
- bytesReadSoFar += bytesRead;
-
- gst_buffer_unmap(buffer, &mapInfo);
- qCDebug(qLcAppSrc) << "pushing bytes into gstreamer" << buffer->offset << bytesRead;
- if (bytesRead == 0) {
- gst_buffer_unref(buffer);
- eosOrIdle();
- qCDebug(qLcAppSrc) << "end pushData" << (m_stream ? m_stream : nullptr) << m_buffer.size();
- return;
- }
- m_noMoreData = false;
- emit bytesProcessed(bytesRead);
-
- GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(m_appSrc.element()), buffer);
- if (ret == GST_FLOW_ERROR) {
- qWarning() << "QGstAppSrc: push buffer error";
- } else if (ret == GST_FLOW_FLUSHING) {
- qWarning() << "QGstAppSrc: push buffer wrong state";
- }
- qCDebug(qLcAppSrc) << "end pushData" << (m_stream ? m_stream : nullptr) << m_buffer.size();
-
-}
-
-bool QGstAppSrc::doSeek(qint64 value)
-{
- if (isStreamValid())
- return m_stream->seek(value + m_offset);
- return false;
-}
-
-
-gboolean QGstAppSrc::on_seek_data(GstAppSrc *, guint64 arg0, gpointer userdata)
-{
- // we do get some spurious seeks to INT_MAX, ignore those
- if (arg0 == std::numeric_limits<quint64>::max())
- return true;
-
- QGstAppSrc *self = reinterpret_cast<QGstAppSrc*>(userdata);
- Q_ASSERT(self);
- if (self->m_sequential)
- return false;
-
- QMetaObject::invokeMethod(self, "doSeek", Qt::AutoConnection, Q_ARG(qint64, arg0));
- return true;
-}
-
-void QGstAppSrc::on_enough_data(GstAppSrc *, gpointer userdata)
-{
- qCDebug(qLcAppSrc) << "on_enough_data";
- QGstAppSrc *self = static_cast<QGstAppSrc*>(userdata);
- Q_ASSERT(self);
- self->m_dataRequestSize = 0;
-}
-
-void QGstAppSrc::on_need_data(GstAppSrc *, guint arg0, gpointer userdata)
-{
- qCDebug(qLcAppSrc) << "on_need_data requesting bytes" << arg0;
- QGstAppSrc *self = static_cast<QGstAppSrc*>(userdata);
- Q_ASSERT(self);
- self->m_dataRequestSize = arg0;
- QMetaObject::invokeMethod(self, "pushData", Qt::AutoConnection);
- qCDebug(qLcAppSrc) << "done on_need_data";
-}
-
-void QGstAppSrc::sendEOS()
-{
- qCDebug(qLcAppSrc) << "sending EOS";
- if (m_appSrc.isNull())
- return;
-
- gst_app_src_end_of_stream(GST_APP_SRC(m_appSrc.element()));
-}
-
-void QGstAppSrc::eosOrIdle()
-{
- qCDebug(qLcAppSrc) << "eosOrIdle";
- if (m_appSrc.isNull())
- return;
-
- if (!m_sequential) {
- sendEOS();
- return;
- }
- if (m_noMoreData)
- return;
- qCDebug(qLcAppSrc) << " idle!";
- m_noMoreData = true;
- emit noMoreData();
-}
diff --git a/src/multimedia/platform/gstreamer/common/qgstappsrc_p.h b/src/multimedia/platform/gstreamer/common/qgstappsrc_p.h
deleted file mode 100644
index 3a978454c..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstappsrc_p.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTAPPSRC_H
-#define QGSTAPPSRC_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtmultimediaglobal_p.h>
-#include <qaudioformat.h>
-
-#include <QtCore/qobject.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/private/qringbuffer_p.h>
-#include <QtCore/qatomic.h>
-
-#include <private/qgst_p.h>
-#include <gst/app/gstappsrc.h>
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkReply;
-
-class Q_MULTIMEDIA_EXPORT QGstAppSrc : public QObject
-{
- Q_OBJECT
-public:
- QGstAppSrc(QObject *parent = 0);
- ~QGstAppSrc();
-
- bool setup(QIODevice *stream = nullptr, qint64 offset = 0);
- void setAudioFormat(const QAudioFormat &f);
-
- void setExternalAppSrc(const QGstElement &appsrc);
- QGstElement element();
-
- void write(const char *data, qsizetype size);
-
- bool canAcceptMoreData() { return m_noMoreData || m_dataRequestSize != 0; }
-
- void suspend() { m_suspended = true; }
- void resume() { m_suspended = false; m_noMoreData = true; }
-
-Q_SIGNALS:
- void bytesProcessed(int bytes);
- void noMoreData();
-
-private Q_SLOTS:
- void pushData();
- bool doSeek(qint64);
- void onDataReady();
-
- void streamDestroyed();
-private:
- bool setStream(QIODevice *, qint64 offset);
- bool isStreamValid() const
- {
- return m_stream != nullptr && m_stream->isOpen();
- }
-
- static gboolean on_seek_data(GstAppSrc *element, guint64 arg0, gpointer userdata);
- static void on_enough_data(GstAppSrc *element, gpointer userdata);
- static void on_need_data(GstAppSrc *element, uint arg0, gpointer userdata);
-
- void sendEOS();
- void eosOrIdle();
-
- QIODevice *m_stream = nullptr;
- QNetworkReply *m_networkReply = nullptr;
- QRingBuffer m_buffer;
- QAudioFormat m_format;
-
- QGstElement m_appSrc;
- bool m_sequential = true;
- bool m_suspended = false;
- bool m_noMoreData = false;
- GstAppStreamType m_streamType = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
- qint64 m_offset = 0;
- qint64 m_maxBytes = 0;
- qint64 bytesReadSoFar = 0;
- QAtomicInteger<unsigned int> m_dataRequestSize = 0;
- int streamedSamples = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstpipeline.cpp b/src/multimedia/platform/gstreamer/common/qgstpipeline.cpp
deleted file mode 100644
index 0f98e7d21..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstpipeline.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qmap.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qabstracteventdispatcher.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qproperty.h>
-
-#include "qgstpipeline_p.h"
-#include "qgstreamermessage_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QGstPipelinePrivate : public QObject
-{
- Q_OBJECT
-public:
-
- int m_ref = 0;
- guint m_tag = 0;
- GstBus *m_bus = nullptr;
- QTimer *m_intervalTimer = nullptr;
- QMutex filterMutex;
- QList<QGstreamerSyncMessageFilter*> syncFilters;
- QList<QGstreamerBusMessageFilter*> busFilters;
- QProperty<bool> inStoppedState;
- mutable qint64 m_position = 0;
- double m_rate = 1.;
- bool m_flushOnConfigChanges = false;
- bool m_pendingFlush = false;
-
- int m_configCounter = 0;
- GstState m_savedState = GST_STATE_NULL;
-
- QGstPipelinePrivate(GstBus* bus, QObject* parent = 0);
- ~QGstPipelinePrivate();
-
- void ref() { ++ m_ref; }
- void deref() { if (!--m_ref) delete this; }
-
- void installMessageFilter(QGstreamerSyncMessageFilter *filter);
- void removeMessageFilter(QGstreamerSyncMessageFilter *filter);
- void installMessageFilter(QGstreamerBusMessageFilter *filter);
- void removeMessageFilter(QGstreamerBusMessageFilter *filter);
-
- static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstPipelinePrivate *d)
- {
- Q_UNUSED(bus);
- QMutexLocker lock(&d->filterMutex);
-
- for (QGstreamerSyncMessageFilter *filter : qAsConst(d->syncFilters)) {
- if (filter->processSyncMessage(QGstreamerMessage(message))) {
- gst_message_unref(message);
- return GST_BUS_DROP;
- }
- }
-
- return GST_BUS_PASS;
- }
-
-private Q_SLOTS:
- void interval()
- {
- GstMessage* message;
- while ((message = gst_bus_poll(m_bus, GST_MESSAGE_ANY, 0)) != nullptr) {
- processMessage(message);
- gst_message_unref(message);
- }
- }
- void doProcessMessage(const QGstreamerMessage& msg)
- {
- for (QGstreamerBusMessageFilter *filter : qAsConst(busFilters)) {
- if (filter->processBusMessage(msg))
- break;
- }
- }
-
-private:
- void processMessage(GstMessage* message)
- {
- QGstreamerMessage msg(message);
- doProcessMessage(msg);
- }
-
- void queueMessage(GstMessage* message)
- {
- QGstreamerMessage msg(message);
- QMetaObject::invokeMethod(this, "doProcessMessage", Qt::QueuedConnection,
- Q_ARG(QGstreamerMessage, msg));
- }
-
- static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data)
- {
- Q_UNUSED(bus);
- static_cast<QGstPipelinePrivate *>(data)->queueMessage(message);
- return TRUE;
- }
-};
-
-QGstPipelinePrivate::QGstPipelinePrivate(GstBus* bus, QObject* parent)
- : QObject(parent),
- m_bus(bus),
- inStoppedState(true)
-{
- gst_object_ref(GST_OBJECT(bus));
-
- // glib event loop can be disabled either by env variable or QT_NO_GLIB define, so check the dispacher
- QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher();
- const bool hasGlib = dispatcher && dispatcher->inherits("QEventDispatcherGlib");
- if (!hasGlib) {
- m_intervalTimer = new QTimer(this);
- m_intervalTimer->setInterval(250);
- connect(m_intervalTimer, SIGNAL(timeout()), SLOT(interval()));
- m_intervalTimer->start();
- } else {
- m_tag = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, busCallback, this, nullptr);
- }
-
- gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, this, nullptr);
-}
-
-QGstPipelinePrivate::~QGstPipelinePrivate()
-{
- delete m_intervalTimer;
-
- if (m_tag)
- gst_bus_remove_watch(m_bus);
-
- gst_bus_set_sync_handler(m_bus, nullptr, nullptr, nullptr);
- gst_object_unref(GST_OBJECT(m_bus));
-}
-
-void QGstPipelinePrivate::installMessageFilter(QGstreamerSyncMessageFilter *filter)
-{
- if (filter) {
- QMutexLocker lock(&filterMutex);
- if (!syncFilters.contains(filter))
- syncFilters.append(filter);
- }
-}
-
-void QGstPipelinePrivate::removeMessageFilter(QGstreamerSyncMessageFilter *filter)
-{
- if (filter) {
- QMutexLocker lock(&filterMutex);
- syncFilters.removeAll(filter);
- }
-}
-
-void QGstPipelinePrivate::installMessageFilter(QGstreamerBusMessageFilter *filter)
-{
- if (filter && !busFilters.contains(filter))
- busFilters.append(filter);
-}
-
-void QGstPipelinePrivate::removeMessageFilter(QGstreamerBusMessageFilter *filter)
-{
- if (filter)
- busFilters.removeAll(filter);
-}
-
-QGstPipeline::QGstPipeline(const QGstPipeline &o)
- : QGstBin(o.bin(), NeedsRef),
- d(o.d)
-{
- if (d)
- d->ref();
-}
-
-QGstPipeline &QGstPipeline::operator=(const QGstPipeline &o)
-{
- if (o.d)
- o.d->ref();
- if (d)
- d->deref();
- QGstBin::operator=(o);
- d = o.d;
- return *this;
-}
-
-QGstPipeline::QGstPipeline(const char *name)
- : QGstBin(GST_BIN(gst_pipeline_new(name)), NeedsRef)
-{
- d = new QGstPipelinePrivate(gst_pipeline_get_bus(pipeline()));
- d->ref();
-}
-
-QGstPipeline::QGstPipeline(GstPipeline *p)
- : QGstBin(&p->bin, NeedsRef)
-{
- d = new QGstPipelinePrivate(gst_pipeline_get_bus(pipeline()));
- d->ref();
-}
-
-QGstPipeline::~QGstPipeline()
-{
- if (d)
- d->deref();
-}
-
-QProperty<bool> *QGstPipeline::inStoppedState()
-{
- Q_ASSERT(d);
- return &d->inStoppedState;
-}
-
-void QGstPipeline::setFlushOnConfigChanges(bool flush)
-{
- d->m_flushOnConfigChanges = flush;
-}
-
-void QGstPipeline::installMessageFilter(QGstreamerSyncMessageFilter *filter)
-{
- Q_ASSERT(d);
- d->installMessageFilter(filter);
-}
-
-void QGstPipeline::removeMessageFilter(QGstreamerSyncMessageFilter *filter)
-{
- Q_ASSERT(d);
- d->removeMessageFilter(filter);
-}
-
-void QGstPipeline::installMessageFilter(QGstreamerBusMessageFilter *filter)
-{
- Q_ASSERT(d);
- d->installMessageFilter(filter);
-}
-
-void QGstPipeline::removeMessageFilter(QGstreamerBusMessageFilter *filter)
-{
- Q_ASSERT(d);
- d->removeMessageFilter(filter);
-}
-
-GstStateChangeReturn QGstPipeline::setState(GstState state)
-{
- auto retval = gst_element_set_state(element(), state);
- if (d->m_pendingFlush) {
- d->m_pendingFlush = false;
- flush();
- }
- return retval;
-}
-
-void QGstPipeline::beginConfig()
-{
- if (!d)
- return;
- Q_ASSERT(!isNull());
-
- ++d->m_configCounter;
- if (d->m_configCounter > 1)
- return;
-
- d->m_savedState = state();
- if (d->m_savedState == GST_STATE_PLAYING)
- setStateSync(GST_STATE_PAUSED);
-}
-
-void QGstPipeline::endConfig()
-{
- if (!d)
- return;
- Q_ASSERT(!isNull());
-
- --d->m_configCounter;
- if (d->m_configCounter)
- return;
-
- if (d->m_flushOnConfigChanges)
- d->m_pendingFlush = true;
- if (d->m_savedState == GST_STATE_PLAYING)
- setState(GST_STATE_PLAYING);
- d->m_savedState = GST_STATE_NULL;
-}
-
-void QGstPipeline::flush()
-{
- seek(position(), d->m_rate);
-}
-
-bool QGstPipeline::seek(qint64 pos, double rate)
-{
- // 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;
- bool success = gst_element_seek(element(), rate, GST_FORMAT_TIME,
- GstSeekFlags(GST_SEEK_FLAG_FLUSH),
- GST_SEEK_TYPE_SET, pos,
- GST_SEEK_TYPE_SET, -1);
- if (!success)
- return false;
-
- d->m_position = pos;
- return true;
-}
-
-bool QGstPipeline::setPlaybackRate(double rate)
-{
- if (rate == d->m_rate)
- return false;
- seek(position(), rate);
- return true;
-}
-
-double QGstPipeline::playbackRate() const
-{
- return d->m_rate;
-}
-
-bool QGstPipeline::setPosition(qint64 pos)
-{
- return seek(pos, d->m_rate);
-}
-
-qint64 QGstPipeline::position() const
-{
- gint64 pos;
- if (gst_element_query_position(element(), GST_FORMAT_TIME, &pos))
- d->m_position = pos;
- return d->m_position;
-}
-
-qint64 QGstPipeline::duration() const
-{
- gint64 d;
- if (!gst_element_query_duration(element(), GST_FORMAT_TIME, &d))
- return 0.;
- return d;
-}
-
-QT_END_NAMESPACE
-
-#include "qgstpipeline.moc"
-
diff --git a/src/multimedia/platform/gstreamer/common/qgstpipeline_p.h b/src/multimedia/platform/gstreamer/common/qgstpipeline_p.h
deleted file mode 100644
index 6ffaf33d6..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstpipeline_p.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef qgstpipeline_p_H
-#define qgstpipeline_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 <private/qtmultimediaglobal_p.h>
-#include <QObject>
-
-#include <private/qgst_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerMessage;
-
-class QGstreamerSyncMessageFilter {
-public:
- //returns true if message was processed and should be dropped, false otherwise
- virtual bool processSyncMessage(const QGstreamerMessage &message) = 0;
-};
-
-
-class QGstreamerBusMessageFilter {
-public:
- //returns true if message was processed and should be dropped, false otherwise
- virtual bool processBusMessage(const QGstreamerMessage &message) = 0;
-};
-
-class QGstPipelinePrivate;
-
-class QGstPipeline : public QGstBin
-{
- QGstPipelinePrivate *d = nullptr;
-public:
- constexpr QGstPipeline() = default;
- QGstPipeline(const QGstPipeline &o);
- QGstPipeline &operator=(const QGstPipeline &o);
- QGstPipeline(const char *name);
- QGstPipeline(GstPipeline *p);
- ~QGstPipeline();
-
- // This is needed to help us avoid sending QVideoFrames or audio buffers to the
- // application while we're prerolling the pipeline.
- // QMediaPlayer is still in a stopped state, while we put the gstreamer pipeline into a
- // Paused state so that we can get the required metadata of the stream and also have a fast
- // transition to play.
- QProperty<bool> *inStoppedState();
-
- void setFlushOnConfigChanges(bool flush);
-
- void installMessageFilter(QGstreamerSyncMessageFilter *filter);
- void removeMessageFilter(QGstreamerSyncMessageFilter *filter);
- void installMessageFilter(QGstreamerBusMessageFilter *filter);
- void removeMessageFilter(QGstreamerBusMessageFilter *filter);
-
- GstStateChangeReturn setState(GstState state);
-
- GstPipeline *pipeline() const { return GST_PIPELINE_CAST(m_object); }
-
- void dumpGraph(const char *fileName)
- {
- if (isNull())
- return;
-
-#if 1 //def QT_GST_CAPTURE_DEBUG
- GST_DEBUG_BIN_TO_DOT_FILE(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),
- fileName);
-#else
- Q_UNUSED(fileName);
-#endif
- }
-
- void beginConfig();
- void endConfig();
-
- void flush();
-
- bool seek(qint64 pos, double rate);
- bool setPlaybackRate(double rate);
- double playbackRate() const;
-
- bool setPosition(qint64 pos);
- qint64 position() const;
-
- qint64 duration() const;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstreameraudioinput.cpp b/src/multimedia/platform/gstreamer/common/qgstreameraudioinput.cpp
deleted file mode 100644
index cd1233c1d..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreameraudioinput.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qgstreameraudioinput_p.h>
-#include <private/qgstreameraudiodevice_p.h>
-#include <qaudiodevice.h>
-#include <qaudioinput.h>
-
-#include <QtCore/qloggingcategory.h>
-#include <QtNetwork/qnetworkaccessmanager.h>
-#include <QtNetwork/qnetworkreply.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-Q_LOGGING_CATEGORY(qLcMediaAudioInput, "qt.multimedia.audioInput")
-
-QT_BEGIN_NAMESPACE
-
-QGstreamerAudioInput::QGstreamerAudioInput(QAudioInput *parent)
- : QObject(parent),
- QPlatformAudioInput(parent),
- gstAudioInput("audioInput")
-{
- audioSrc = QGstElement("autoaudiosrc", "autoaudiosrc");
- audioVolume = QGstElement("volume", "volume");
- gstAudioInput.add(audioSrc, audioVolume);
- audioSrc.link(audioVolume);
-
- gstAudioInput.addGhostPad(audioVolume, "src");
-}
-
-QGstreamerAudioInput::~QGstreamerAudioInput()
-{
- gstAudioInput.setStateSync(GST_STATE_NULL);
-}
-
-int QGstreamerAudioInput::volume() const
-{
- return m_volume;
-}
-
-bool QGstreamerAudioInput::isMuted() const
-{
- return m_muted;
-}
-
-void QGstreamerAudioInput::setVolume(float vol)
-{
- if (vol == m_volume)
- return;
- m_volume = vol;
- audioVolume.set("volume", vol);
- emit volumeChanged(m_volume);
-}
-
-void QGstreamerAudioInput::setMuted(bool muted)
-{
- if (muted == m_muted)
- return;
- m_muted = muted;
- audioVolume.set("mute", muted);
- emit mutedChanged(muted);
-}
-
-void QGstreamerAudioInput::setAudioDevice(const QAudioDevice &device)
-{
- if (device == m_audioDevice)
- return;
- qCDebug(qLcMediaAudioInput) << "setAudioInput" << device.description() << device.isNull();
- m_audioDevice = device;
-
- QGstElement newSrc;
- auto *deviceInfo = static_cast<const QGStreamerAudioDeviceInfo *>(m_audioDevice.handle());
- if (deviceInfo && deviceInfo->gstDevice)
- newSrc = gst_device_create_element(deviceInfo->gstDevice, "audiosrc");
-
- if (newSrc.isNull())
- newSrc = QGstElement("autoaudiosrc", "audiosrc");
-
- // FIXME: most probably source can be disconnected outside of idle probe
- audioSrc.staticPad("src").doInIdleProbe([&](){
- audioSrc.unlink(audioVolume);
- });
- audioSrc.setStateSync(GST_STATE_NULL);
- gstAudioInput.remove(audioSrc);
- audioSrc = newSrc;
- gstAudioInput.add(audioSrc);
- audioSrc.link(audioVolume);
- audioSrc.syncStateWithParent();
-}
-
-QAudioDevice QGstreamerAudioInput::audioInput() const
-{
- return m_audioDevice;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreameraudioinput_p.h b/src/multimedia/platform/gstreamer/common/qgstreameraudioinput_p.h
deleted file mode 100644
index a0e7d96ab..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreameraudioinput_p.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERAUDIOINPUT_P_H
-#define QGSTREAMERAUDIOINPUT_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 <private/qtmultimediaglobal_p.h>
-#include <qaudiodevice.h>
-
-#include <QtCore/qobject.h>
-
-#include <private/qgst_p.h>
-#include <private/qgstpipeline_p.h>
-#include <private/qplatformaudioinput_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerMessage;
-class QAudioDevice;
-
-class Q_MULTIMEDIA_EXPORT QGstreamerAudioInput : public QObject, public QPlatformAudioInput
-{
- Q_OBJECT
-
-public:
- QGstreamerAudioInput(QAudioInput *parent);
- ~QGstreamerAudioInput();
-
- int volume() const;
- bool isMuted() const;
-
- bool setAudioInput(const QAudioDevice &);
- QAudioDevice audioInput() const;
-
- void setAudioDevice(const QAudioDevice &) override;
- void setVolume(float volume) override;
- void setMuted(bool muted) override;
-
- QGstElement gstElement() const { return gstAudioInput; }
-
-Q_SIGNALS:
- void mutedChanged(bool);
- void volumeChanged(int);
-
-private:
- float m_volume = 1.;
- bool m_muted = false;
-
- QAudioDevice m_audioDevice;
-
- // Gst elements
- QGstBin gstAudioInput;
-
- QGstElement audioSrc;
- QGstElement audioVolume;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstreameraudiooutput.cpp b/src/multimedia/platform/gstreamer/common/qgstreameraudiooutput.cpp
deleted file mode 100644
index 6338c1ee0..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreameraudiooutput.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qgstreameraudiooutput_p.h>
-#include <private/qgstreameraudiodevice_p.h>
-#include <qaudiodevice.h>
-#include <qaudiooutput.h>
-
-#include <QtCore/qloggingcategory.h>
-#include <QtNetwork/qnetworkaccessmanager.h>
-#include <QtNetwork/qnetworkreply.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-Q_LOGGING_CATEGORY(qLcMediaAudioOutput, "qt.multimedia.audiooutput")
-
-QT_BEGIN_NAMESPACE
-
-QGstreamerAudioOutput::QGstreamerAudioOutput(QAudioOutput *parent)
- : QObject(parent),
- QPlatformAudioOutput(parent),
- gstAudioOutput("audioOutput")
-{
- audioQueue = QGstElement("queue", "audioQueue");
- audioConvert = QGstElement("audioconvert", "audioConvert");
- audioResample = QGstElement("audioresample", "audioResample");
- audioVolume = QGstElement("volume", "volume");
- audioSink = QGstElement("autoaudiosink", "autoAudioSink");
- gstAudioOutput.add(audioQueue, audioConvert, audioResample, audioVolume, audioSink);
- audioQueue.link(audioConvert, audioResample, audioVolume, audioSink);
-
- gstAudioOutput.addGhostPad(audioQueue, "sink");
-}
-
-QGstreamerAudioOutput::~QGstreamerAudioOutput()
-{
- gstAudioOutput.setStateSync(GST_STATE_NULL);
-}
-
-void QGstreamerAudioOutput::setVolume(float vol)
-{
- audioVolume.set("volume", vol);
-}
-
-void QGstreamerAudioOutput::setMuted(bool muted)
-{
- audioVolume.set("mute", muted);
-}
-
-void QGstreamerAudioOutput::setPipeline(const QGstPipeline &pipeline)
-{
- gstPipeline = pipeline;
-}
-
-void QGstreamerAudioOutput::setAudioDevice(const QAudioDevice &info)
-{
- if (info == m_audioOutput)
- return;
- qCDebug(qLcMediaAudioOutput) << "setAudioOutput" << info.description() << info.isNull();
- m_audioOutput = info;
-
- QGstElement newSink;
- auto *deviceInfo = static_cast<const QGStreamerAudioDeviceInfo *>(m_audioOutput.handle());
- if (deviceInfo && deviceInfo->gstDevice)
- newSink = gst_device_create_element(deviceInfo->gstDevice , "audiosink");
-
- if (newSink.isNull())
- newSink = QGstElement("autoaudiosink", "audiosink");
-
- audioVolume.staticPad("src").doInIdleProbe([&](){
- audioVolume.unlink(audioSink);
- gstAudioOutput.remove(audioSink);
- gstAudioOutput.add(newSink);
- newSink.syncStateWithParent();
- audioVolume.link(newSink);
- });
-
- audioSink.setStateSync(GST_STATE_NULL);
- audioSink = newSink;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreameraudiooutput_p.h b/src/multimedia/platform/gstreamer/common/qgstreameraudiooutput_p.h
deleted file mode 100644
index c3b33c4f4..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreameraudiooutput_p.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERAUDIOOUTPUT_P_H
-#define QGSTREAMERAUDIOOUTPUT_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 <private/qtmultimediaglobal_p.h>
-#include <qaudiodevice.h>
-
-#include <QtCore/qobject.h>
-
-#include <private/qgst_p.h>
-#include <private/qgstpipeline_p.h>
-#include <private/qplatformaudiooutput_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerMessage;
-class QAudioDevice;
-
-class Q_MULTIMEDIA_EXPORT QGstreamerAudioOutput : public QObject, public QPlatformAudioOutput
-{
- Q_OBJECT
-
-public:
- QGstreamerAudioOutput(QAudioOutput *parent);
- ~QGstreamerAudioOutput();
-
- void setAudioDevice(const QAudioDevice &) override;
- void setVolume(float volume) override;
- void setMuted(bool muted) override;
-
- void setPipeline(const QGstPipeline &pipeline);
-
- QGstElement gstElement() const { return gstAudioOutput; }
-
-Q_SIGNALS:
- void mutedChanged(bool);
- void volumeChanged(int);
-
-private:
- QAudioDevice m_audioOutput;
-
- // Gst elements
- QGstPipeline gstPipeline;
- QGstBin gstAudioOutput;
-
- QGstElement audioQueue;
- QGstElement audioConvert;
- QGstElement audioResample;
- QGstElement audioVolume;
- QGstElement audioSink;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe.cpp b/src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe.cpp
deleted file mode 100644
index 3af8000bb..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamerbufferprobe_p.h"
-#include "qgstutils_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QGstreamerBufferProbe::QGstreamerBufferProbe(Flags flags)
- : m_flags(flags)
-{
-}
-
-QGstreamerBufferProbe::~QGstreamerBufferProbe() = default;
-
-void QGstreamerBufferProbe::addProbeToPad(GstPad *pad, bool downstream)
-{
- if (GstCaps *caps = gst_pad_get_current_caps(pad)) {
- probeCaps(caps);
- gst_caps_unref(caps);
- }
- if (m_flags & ProbeCaps) {
- m_capsProbeId = gst_pad_add_probe(
- pad,
- downstream
- ? GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM
- : GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
- capsProbe,
- this,
- nullptr);
- }
- if (m_flags & ProbeBuffers) {
- m_bufferProbeId = gst_pad_add_probe(
- pad, GST_PAD_PROBE_TYPE_BUFFER, bufferProbe, this, nullptr);
- }
-}
-
-void QGstreamerBufferProbe::removeProbeFromPad(GstPad *pad)
-{
- if (m_capsProbeId != -1) {
- gst_pad_remove_probe(pad, m_capsProbeId);
- m_capsProbeId = -1;
- }
- if (m_bufferProbeId != -1) {
- gst_pad_remove_probe(pad, m_bufferProbeId);
- m_bufferProbeId = -1;
- }
-}
-
-void QGstreamerBufferProbe::probeCaps(GstCaps *)
-{
-}
-
-bool QGstreamerBufferProbe::probeBuffer(GstBuffer *)
-{
- return true;
-}
-
-GstPadProbeReturn QGstreamerBufferProbe::capsProbe(GstPad *, GstPadProbeInfo *info, gpointer user_data)
-{
- QGstreamerBufferProbe * const control = static_cast<QGstreamerBufferProbe *>(user_data);
-
- if (GstEvent * const event = gst_pad_probe_info_get_event(info)) {
- if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS) {
- GstCaps *caps;
- gst_event_parse_caps(event, &caps);
-
- control->probeCaps(caps);
- }
- }
- return GST_PAD_PROBE_OK;
-}
-
-GstPadProbeReturn QGstreamerBufferProbe::bufferProbe(
- GstPad *, GstPadProbeInfo *info, gpointer user_data)
-{
- QGstreamerBufferProbe * const control = static_cast<QGstreamerBufferProbe *>(user_data);
- if (GstBuffer * const buffer = gst_pad_probe_info_get_buffer(info))
- return control->probeBuffer(buffer) ? GST_PAD_PROBE_OK : GST_PAD_PROBE_DROP;
- return GST_PAD_PROBE_OK;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe_p.h b/src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe_p.h
deleted file mode 100644
index d3ca9db2e..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamerbufferprobe_p.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERBUFFERPROBE_H
-#define QGSTREAMERBUFFERPROBE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtmultimediaglobal_p.h>
-#include <gst/gst.h>
-
-#include <QtCore/qglobal.h>
-
-
-QT_BEGIN_NAMESPACE
-
-class Q_MULTIMEDIA_EXPORT QGstreamerBufferProbe
-{
-public:
- enum Flags
- {
- ProbeCaps = 0x01,
- ProbeBuffers = 0x02,
- ProbeAll = ProbeCaps | ProbeBuffers
- };
-
- explicit QGstreamerBufferProbe(Flags flags = ProbeAll);
- virtual ~QGstreamerBufferProbe();
-
- void addProbeToPad(GstPad *pad, bool downstream = true);
- void removeProbeFromPad(GstPad *pad);
-
-protected:
- virtual void probeCaps(GstCaps *caps);
- virtual bool probeBuffer(GstBuffer *buffer);
-
-private:
- static GstPadProbeReturn capsProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
- static GstPadProbeReturn bufferProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
- int m_capsProbeId = -1;
- int m_bufferProbeId = -1;
- const Flags m_flags;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERBUFFERPROBE_H
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
deleted file mode 100644
index 2c05c0cfe..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
+++ /dev/null
@@ -1,864 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qgstreamermediaplayer_p.h>
-#include <private/qgstpipeline_p.h>
-#include <private/qgstreamermetadata_p.h>
-#include <private/qgstreamerformatinfo_p.h>
-#include <private/qgstreameraudiooutput_p.h>
-#include <private/qgstreamervideooutput_p.h>
-#include <private/qgstreamervideosink_p.h>
-#include "private/qgstreamermessage_p.h"
-#include <private/qgstreameraudiodevice_p.h>
-#include <private/qgstappsrc_p.h>
-#include <qaudiodevice.h>
-
-#include <QtCore/qdir.h>
-#include <QtCore/qsocketnotifier.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qloggingcategory.h>
-#include <QtNetwork/qnetworkaccessmanager.h>
-#include <QtNetwork/qnetworkreply.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-Q_LOGGING_CATEGORY(qLcMediaPlayer, "qt.multimedia.player")
-
-QT_BEGIN_NAMESPACE
-
-QGstreamerMediaPlayer::TrackSelector::TrackSelector(TrackType type, const char *name)
- : selector(QGstElement("input-selector", name)),
- type(type)
-{
- selector.set("sync-streams", true);
-
- if (type == SubtitleStream) {
- selector.set("sync-mode", 1 /*clock*/);
- selector.set("cache-buffers", true);
- }
-
- nullTrack = selector.getRequestPad("sink_%u");
-}
-
-QGstPad QGstreamerMediaPlayer::TrackSelector::createInputPad()
-{
- auto pad = selector.getRequestPad("sink_%u");
- tracks.append(pad);
- return pad;
-}
-
-void QGstreamerMediaPlayer::TrackSelector::removeAllInputPads()
-{
- for (auto &pad : tracks)
- selector.releaseRequestPad(pad);
- tracks.clear();
-}
-
-void QGstreamerMediaPlayer::TrackSelector::removeInputPad(QGstPad pad)
-{
- selector.releaseRequestPad(pad);
- tracks.removeOne(pad);
-}
-
-QGstPad QGstreamerMediaPlayer::TrackSelector::inputPad(int index)
-{
- if (index == -1)
- return nullTrack;
- if (index >= 0 && index < tracks.count())
- return tracks[index];
- return {};
-}
-
-QGstreamerMediaPlayer::TrackSelector &QGstreamerMediaPlayer::trackSelector(TrackType type)
-{
- auto &ts = trackSelectors[type];
- Q_ASSERT(ts.type == type);
- return ts;
-}
-
-QGstreamerMediaPlayer::QGstreamerMediaPlayer(QMediaPlayer *parent)
- : QObject(parent),
- QPlatformMediaPlayer(parent),
- trackSelectors{{{ VideoStream, "videoInputSelector" },
- { AudioStream, "audioInputSelector" },
- { SubtitleStream, "subTitleInputSelector" }}},
- playerPipeline("playerPipeline")
-{
- playerPipeline.setFlushOnConfigChanges(true);
-
- gstVideoOutput = new QGstreamerVideoOutput(this);
- gstVideoOutput->setPipeline(playerPipeline);
-
- 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));
-
- /* Taken from gstdicoverer.c:
- * This is ugly. We get the GType of decodebin so we can quickly detect
- * when a decodebin is added to uridecodebin so we can set the
- * post-stream-topology setting to TRUE */
- auto decodebin = QGstElement("decodebin", nullptr);
- decodebinType = G_OBJECT_TYPE(decodebin.element());
- connect(&positionUpdateTimer, &QTimer::timeout, this, &QGstreamerMediaPlayer::updatePosition);
-}
-
-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
-{
- if (playerPipeline.isNull() || m_url.isEmpty())
- return 0;
-
- return playerPipeline.position()/1e6;
-}
-
-qint64 QGstreamerMediaPlayer::duration() const
-{
- return m_duration;
-}
-
-float QGstreamerMediaPlayer::bufferProgress() const
-{
- return m_bufferProgress/100.;
-}
-
-QMediaTimeRange QGstreamerMediaPlayer::availablePlaybackRanges() const
-{
- return QMediaTimeRange();
-}
-
-qreal QGstreamerMediaPlayer::playbackRate() const
-{
- return playerPipeline.playbackRate();
-}
-
-void QGstreamerMediaPlayer::setPlaybackRate(qreal rate)
-{
- if (playerPipeline.setPlaybackRate(rate))
- playbackRateChanged(rate);
-}
-
-void QGstreamerMediaPlayer::setPosition(qint64 pos)
-{
- qint64 currentPos = playerPipeline.position()/1e6;
- if (pos == currentPos)
- return;
- playerPipeline.finishStateChange();
- playerPipeline.setPosition(pos*1e6);
- qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << pos << playerPipeline.position()/1e6;
- if (mediaStatus() == QMediaPlayer::EndOfMedia)
- mediaStatusChanged(QMediaPlayer::LoadedMedia);
- positionChanged(pos);
-}
-
-void QGstreamerMediaPlayer::play()
-{
- if (state() == QMediaPlayer::PlayingState || m_url.isEmpty())
- return;
-
- *playerPipeline.inStoppedState() = false;
- if (mediaStatus() == QMediaPlayer::EndOfMedia) {
- playerPipeline.setPosition(0);
- updatePosition();
- }
-
- qCDebug(qLcMediaPlayer) << "play().";
- int ret = playerPipeline.setState(GST_STATE_PLAYING);
- if (m_requiresSeekOnPlay) {
- // Flushing the pipeline is required to get track changes
- // immediately, when they happen while paused.
- playerPipeline.flush();
- m_requiresSeekOnPlay = false;
- }
- if (ret == GST_STATE_CHANGE_FAILURE)
- qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the playing state.";
- if (mediaStatus() == QMediaPlayer::LoadedMedia)
- mediaStatusChanged(QMediaPlayer::BufferedMedia);
- emit stateChanged(QMediaPlayer::PlayingState);
- positionUpdateTimer.start(100);
-}
-
-void QGstreamerMediaPlayer::pause()
-{
- if (state() == QMediaPlayer::PausedState || m_url.isEmpty())
- return;
-
- positionUpdateTimer.stop();
- if (*playerPipeline.inStoppedState()) {
- *playerPipeline.inStoppedState() = false;
- playerPipeline.flush();
- }
- int ret = playerPipeline.setState(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);
- mediaStatusChanged(QMediaPlayer::BufferedMedia);
- }
- updatePosition();
- emit stateChanged(QMediaPlayer::PausedState);
-}
-
-void QGstreamerMediaPlayer::stop()
-{
- if (state() == QMediaPlayer::StoppedState)
- return;
- stopOrEOS(false);
-}
-
-void QGstreamerMediaPlayer::stopOrEOS(bool eos)
-{
- positionUpdateTimer.stop();
- *playerPipeline.inStoppedState() = 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();
- emit stateChanged(QMediaPlayer::StoppedState);
- mediaStatusChanged(eos ? QMediaPlayer::EndOfMedia : QMediaPlayer::LoadedMedia);
-}
-
-bool QGstreamerMediaPlayer::processBusMessage(const QGstreamerMessage &message)
-{
- if (message.isNull())
- return false;
-
-// qCDebug(qLcMediaPlayer) << "received bus message from" << message.source().name() << message.type() << (message.type() == GST_MESSAGE_TAG);
-
- GstMessage* gm = message.rawMessage();
- switch (message.type()) {
- case GST_MESSAGE_TAG: {
- // #### This isn't ideal. We shouldn't catch stream specific tags here, rather the global ones
- GstTagList *tag_list;
- gst_message_parse_tag(gm, &tag_list);
- //qCDebug(qLcMediaPlayer) << "Got tags: " << message.source().name() << gst_tag_list_to_string(tag_list);
- auto metaData = QGstreamerMetaData::fromGstTagList(tag_list);
- for (auto k : metaData.keys())
- m_metaData.insert(k, metaData.value(k));
- break;
- }
- case GST_MESSAGE_DURATION_CHANGED: {
- qint64 d = playerPipeline.duration()/1e6;
- qCDebug(qLcMediaPlayer) << " duration changed message" << d;
- if (d != m_duration) {
- m_duration = d;
- emit durationChanged(duration());
- }
- return false;
- }
- case GST_MESSAGE_EOS:
- stopOrEOS(true);
- break;
- case GST_MESSAGE_BUFFERING: {
- qCDebug(qLcMediaPlayer) << " buffering message";
- int progress = 0;
- gst_message_parse_buffering(gm, &progress);
- m_bufferProgress = progress;
- mediaStatusChanged(m_bufferProgress == 100 ? QMediaPlayer::BufferedMedia : QMediaPlayer::BufferingMedia);
- emit bufferProgressChanged(m_bufferProgress/100.);
- break;
- }
- case GST_MESSAGE_STATE_CHANGED: {
- if (message.source() != playerPipeline)
- return false;
-
- GstState oldState;
- GstState newState;
- GstState pending;
-
- gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
- qCDebug(qLcMediaPlayer) << " state changed message" << oldState << newState << pending;
-
-#ifdef DEBUG_PLAYBIN
- static QStringList states = {
- QStringLiteral("GST_STATE_VOID_PENDING"), QStringLiteral("GST_STATE_NULL"),
- QStringLiteral("GST_STATE_READY"), QStringLiteral("GST_STATE_PAUSED"),
- QStringLiteral("GST_STATE_PLAYING") };
-
- qCDebug(qLcMediaPlayer) << QStringLiteral("state changed: old: %1 new: %2 pending: %3") \
- .arg(states[oldState]) \
- .arg(states[newState]) \
- .arg(states[pending]);
-#endif
-
- switch (newState) {
- case GST_STATE_VOID_PENDING:
- case GST_STATE_NULL:
- case GST_STATE_READY:
- seekableChanged(false);
- break;
- case GST_STATE_PAUSED:
- {
- if (prerolling) {
- qCDebug(qLcMediaPlayer) << "Preroll done, setting status to Loaded";
- prerolling = false;
- GST_DEBUG_BIN_TO_DOT_FILE(playerPipeline.bin(), GST_DEBUG_GRAPH_SHOW_ALL, "playerPipeline");
-
- parseStreamsAndMetadata();
-
- qint64 d = playerPipeline.duration()/1e6;
- if (d != m_duration) {
- m_duration = d;
- qCDebug(qLcMediaPlayer) << " duration changed" << d;
- emit durationChanged(duration());
- }
-
- emit tracksChanged();
- mediaStatusChanged(QMediaPlayer::LoadedMedia);
- }
-
- break;
- }
- case GST_STATE_PLAYING:
- mediaStatusChanged(QMediaPlayer::BufferedMedia);
- break;
- }
- break;
- }
- case GST_MESSAGE_ERROR: {
- GError *err;
- gchar *debug;
- gst_message_parse_error(gm, &err, &debug);
- if (err->domain == GST_STREAM_ERROR && err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND)
- emit error(QMediaPlayer::FormatError, tr("Cannot play stream of type: <unknown>"));
- else
- emit error(QMediaPlayer::ResourceError, QString::fromUtf8(err->message));
- playerPipeline.dumpGraph("error");
- mediaStatusChanged(QMediaPlayer::InvalidMedia);
- g_error_free(err);
- g_free(debug);
- break;
- }
- case GST_MESSAGE_WARNING: {
- GError *err;
- gchar *debug;
- gst_message_parse_warning (gm, &err, &debug);
- qCWarning(qLcMediaPlayer) << "Warning:" << QString::fromUtf8(err->message);
- playerPipeline.dumpGraph("warning");
- g_error_free (err);
- g_free (debug);
- break;
- }
- case GST_MESSAGE_INFO: {
- if (qLcMediaPlayer().isDebugEnabled()) {
- GError *err;
- gchar *debug;
- gst_message_parse_info (gm, &err, &debug);
- qCDebug(qLcMediaPlayer) << "Info:" << QString::fromUtf8(err->message);
- g_error_free (err);
- g_free (debug);
- }
- break;
- }
- case GST_MESSAGE_SEGMENT_START: {
- qCDebug(qLcMediaPlayer) << " segment start message, updating position";
- QGstStructure structure(gst_message_get_structure(gm));
- auto p = structure["position"].toInt64();
- if (p) {
- qint64 position = (*p)/1000000;
- emit positionChanged(position);
- }
- break;
- }
- case GST_MESSAGE_ELEMENT: {
- QGstStructure structure(gst_message_get_structure(gm));
- auto type = structure.name();
- if (type == "stream-topology") {
- topology.free();
- topology = structure.copy();
- }
- break;
- }
-
- default:
-// qCDebug(qLcMediaPlayer) << " default message handler, doing nothing";
-
- break;
- }
-
- return false;
-}
-
-bool QGstreamerMediaPlayer::processSyncMessage(const QGstreamerMessage &message)
-{
-#if QT_CONFIG(gstreamer_gl)
- if (message.type() != GST_MESSAGE_NEED_CONTEXT)
- return false;
- const gchar *type = nullptr;
- gst_message_parse_context_type (message.rawMessage(), &type);
- if (strcmp(type, GST_GL_DISPLAY_CONTEXT_TYPE))
- return false;
- if (!gstVideoOutput || !gstVideoOutput->gstreamerVideoSink())
- return false;
- auto *context = gstVideoOutput->gstreamerVideoSink()->gstGlDisplayContext();
- if (!context)
- return false;
- gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message.rawMessage())), context);
- playerPipeline.dumpGraph("need_context");
- return true;
-#else
- Q_UNUSED(message);
- return false;
-#endif
-}
-
-QUrl QGstreamerMediaPlayer::media() const
-{
- return m_url;
-}
-
-const QIODevice *QGstreamerMediaPlayer::mediaStream() const
-{
- return m_stream;
-}
-
-void QGstreamerMediaPlayer::decoderPadAdded(const QGstElement &src, const QGstPad &pad)
-{
- if (src != decoder)
- return;
-
- auto caps = pad.currentCaps();
- auto type = caps.at(0).name();
- qCDebug(qLcMediaPlayer) << "Received new pad" << pad.name() << "from" << src.name() << "type" << type;
- qCDebug(qLcMediaPlayer) << " " << caps.toString();
-
- TrackType streamType = NTrackTypes;
- if (type.startsWith("video/x-raw")) {
- streamType = VideoStream;
- } else if (type.startsWith("audio/x-raw")) {
- streamType = AudioStream;
- } else if (type.startsWith("text/")) {
- streamType = SubtitleStream;
- } else {
- qCWarning(qLcMediaPlayer) << "Ignoring unknown media stream:" << pad.name() << type;
- return;
- }
-
- auto &ts = trackSelector(streamType);
- connectOutput(ts);
-
- QGstPad sinkPad = ts.createInputPad();
- if (!pad.link(sinkPad)) {
- qCWarning(qLcMediaPlayer) << "Failed to add track, cannot link pads";
- return;
- }
- qCDebug(qLcMediaPlayer) << "Adding track";
-
- if (ts.trackCount() == 1) {
- if (streamType == VideoStream) {
- ts.setActiveInputPad(sinkPad);
- emit videoAvailableChanged(true);
- }
- else if (streamType == AudioStream) {
- ts.setActiveInputPad(sinkPad);
- emit audioAvailableChanged(true);
- }
- }
-
- if (!prerolling)
- emit tracksChanged();
-
- decoderOutputMap.insert(pad.name(), sinkPad);
-}
-
-void QGstreamerMediaPlayer::decoderPadRemoved(const QGstElement &src, const QGstPad &pad)
-{
- if (src != decoder)
- return;
-
- qCDebug(qLcMediaPlayer) << "Removed pad" << pad.name() << "from" << src.name();
- auto track = decoderOutputMap.value(pad.name());
- if (track.isNull())
- return;
-
- auto ts = std::find_if(std::begin(trackSelectors), std::end(trackSelectors),
- [&](TrackSelector &ts){ return ts.selector == track.parent(); });
- if (ts == std::end(trackSelectors))
- return;
-
- qCDebug(qLcMediaPlayer) << " was linked to pad" << track.name() << "from" << ts->selector.name();
- ts->removeInputPad(track);
-
- if (ts->trackCount() == 0) {
- removeOutput(*ts);
- if (ts->type == AudioStream)
- audioAvailableChanged(false);
- else if (ts->type == VideoStream)
- videoAvailableChanged(false);
- }
-
- if (!prerolling)
- tracksChanged();
-}
-
-void QGstreamerMediaPlayer::removeAllOutputs()
-{
- for (auto &ts : trackSelectors) {
- removeOutput(ts);
- ts.removeAllInputPads();
- }
- audioAvailableChanged(false);
- videoAvailableChanged(false);
-}
-
-void QGstreamerMediaPlayer::connectOutput(TrackSelector &ts)
-{
- if (ts.isConnected)
- return;
-
- QGstElement e;
- switch (ts.type) {
- case AudioStream:
- e = gstAudioOutput ? gstAudioOutput->gstElement() : QGstElement{};
- break;
- case VideoStream:
- e = gstVideoOutput ? gstVideoOutput->gstElement() : QGstElement{};
- break;
- case SubtitleStream:
- gstVideoOutput->linkSubtitleStream(ts.selector);
- break;
- default:
- return;
- }
-
- if (!e.isNull()) {
- qCDebug(qLcMediaPlayer) << "connecting output for track type" << ts.type;
- playerPipeline.add(e);
- ts.selector.link(e);
- e.setState(GST_STATE_PAUSED);
- }
-
- ts.isConnected = true;
-}
-
-void QGstreamerMediaPlayer::removeOutput(TrackSelector &ts)
-{
- if (!ts.isConnected)
- return;
-
- QGstElement e;
- switch (ts.type) {
- case AudioStream:
- e = gstAudioOutput ? gstAudioOutput->gstElement() : QGstElement{};
- break;
- case VideoStream:
- e = gstVideoOutput ? gstVideoOutput->gstElement() : QGstElement{};
- break;
- case SubtitleStream:
- // TODO: unlink subtitle stream
- break;
- default:
- break;
- }
-
- if (!e.isNull()) {
- qCDebug(qLcMediaPlayer) << "removing output for track type" << ts.type;
- e.setState(GST_STATE_NULL);
- playerPipeline.remove(e);
- }
-
- ts.isConnected = false;
-}
-
-void QGstreamerMediaPlayer::uridecodebinElementAddedCallback(GstElement */*uridecodebin*/, GstElement *child, QGstreamerMediaPlayer *that)
-{
- QGstElement c(child);
- qCDebug(qLcMediaPlayer) << "New element added to uridecodebin:" << c.name();
-
- if (G_OBJECT_TYPE(child) == that->decodebinType) {
- qCDebug(qLcMediaPlayer) << " -> setting post-stream-topology property";
- c.set("post-stream-topology", true);
- } else if (!qstrcmp(gst_element_get_name(child), "source")) {
- GstBaseSrc *src = GST_BASE_SRC(child);
- bool seekable = src && GST_BASE_SRC_GET_CLASS(src)->is_seekable(src);
- that->seekableChanged(seekable);
- }
-}
-
-void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream)
-{
- qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << "setting location to" << content;
-
- prerolling = true;
-
- bool ret = playerPipeline.setStateSync(GST_STATE_NULL);
- if (!ret)
- qCDebug(qLcMediaPlayer) << "Unable to set the pipeline to the stopped state.";
-
- m_url = content;
- m_stream = stream;
-
- if (!src.isNull())
- playerPipeline.remove(src);
- if (!decoder.isNull())
- playerPipeline.remove(decoder);
- src = QGstElement();
- decoder = QGstElement();
- removeAllOutputs();
- seekableChanged(false);
-
- if (m_duration != 0) {
- m_duration = 0;
- durationChanged(0);
- }
- stateChanged(QMediaPlayer::StoppedState);
- if (position() != 0)
- positionChanged(0);
- mediaStatusChanged(QMediaPlayer::NoMedia);
- if (!m_metaData.isEmpty()) {
- m_metaData.clear();
- metaDataChanged();
- }
-
- if (content.isEmpty())
- return;
-
- if (m_stream) {
- if (!m_appSrc)
- m_appSrc = new QGstAppSrc(this);
- src = m_appSrc->element();
- decoder = QGstElement("decodebin", "decoder");
- decoder.set("post-stream-topology", true);
- playerPipeline.add(src, decoder);
- src.link(decoder);
-
- m_appSrc->setup(m_stream);
- seekableChanged(!stream->isSequential());
- } else {
- // use uridecodebin
- decoder = QGstElement("uridecodebin", "uridecoder");
- playerPipeline.add(decoder);
- // can't set post-stream-topology to true, as uridecodebin doesn't have the property. Use a hack
- decoder.connect("element-added", GCallback(QGstreamerMediaPlayer::uridecodebinElementAddedCallback), this);
-
- decoder.set("uri", content.toEncoded().constData());
- if (m_bufferProgress != 0) {
- m_bufferProgress = 0;
- emit bufferProgressChanged(0.);
- }
- }
- decoder.onPadAdded<&QGstreamerMediaPlayer::decoderPadAdded>(this);
- decoder.onPadRemoved<&QGstreamerMediaPlayer::decoderPadRemoved>(this);
-
- mediaStatusChanged(QMediaPlayer::LoadingMedia);
-
- if (state() == QMediaPlayer::PlayingState) {
- int ret = playerPipeline.setState(GST_STATE_PLAYING);
- if (ret == GST_STATE_CHANGE_FAILURE)
- qCWarning(qLcMediaPlayer) << "Unable to set the pipeline to the playing state.";
- } else {
- int ret = playerPipeline.setState(GST_STATE_PAUSED);
- if (!ret)
- qCWarning(qLcMediaPlayer) << "Unable to set the pipeline to the paused state.";
- }
-
- playerPipeline.setPosition(0);
- positionChanged(0);
-}
-
-void QGstreamerMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
-{
- if (gstAudioOutput == output)
- return;
-
- auto &ts = trackSelector(AudioStream);
-
- playerPipeline.beginConfig();
- if (gstAudioOutput) {
- removeOutput(ts);
- gstAudioOutput->setPipeline({});
- }
- gstAudioOutput = static_cast<QGstreamerAudioOutput *>(output);
- if (gstAudioOutput) {
- gstAudioOutput->setPipeline(playerPipeline);
- connectOutput(ts);
- }
- playerPipeline.endConfig();
-}
-
-QMediaMetaData QGstreamerMediaPlayer::metaData() const
-{
- return m_metaData;
-}
-
-void QGstreamerMediaPlayer::setVideoSink(QVideoSink *sink)
-{
- gstVideoOutput->setVideoSink(sink);
-}
-
-static QGstStructure endOfChain(const QGstStructure &s)
-{
- QGstStructure e = s;
- while (1) {
- auto next = e["next"].toStructure();
- if (!next.isNull())
- e = next;
- else
- break;
- }
- return e;
-}
-
-void QGstreamerMediaPlayer::parseStreamsAndMetadata()
-{
- qCDebug(qLcMediaPlayer) << "============== parse topology ============";
- if (topology.isNull()) {
- qCDebug(qLcMediaPlayer) << " null topology";
- return;
- }
- auto caps = topology["caps"].toCaps();
- auto structure = caps.at(0);
- auto fileFormat = QGstreamerFormatInfo::fileFormatForCaps(structure);
- qCDebug(qLcMediaPlayer) << caps.toString() << 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()) {
- GstTagList *tagList = nullptr;
- gst_structure_get(topology.structure, "tags", GST_TYPE_TAG_LIST, &tagList, nullptr);
- const auto metaData = QGstreamerMetaData::fromGstTagList(tagList);
- for (auto k : metaData.keys())
- m_metaData.insert(k, metaData.value(k));
- }
-
- auto demux = endOfChain(topology);
- auto next = demux["next"];
- if (!next.isList()) {
- qCDebug(qLcMediaPlayer) << " no additional streams";
- emit metaDataChanged();
- return;
- }
-
- // collect stream info
- int size = next.listSize();
- for (int i = 0; i < size; ++i) {
- auto val = next.at(i);
- caps = val.toStructure()["caps"].toCaps();
- structure = caps.at(0);
- if (structure.name().startsWith("audio/")) {
- auto codec = QGstreamerFormatInfo::audioCodecForCaps(structure);
- m_metaData.insert(QMediaMetaData::AudioCodec, QVariant::fromValue(codec));
- qCDebug(qLcMediaPlayer) << " audio" << caps.toString() << (int)codec;
- } else if (structure.name().startsWith("video/")) {
- auto codec = QGstreamerFormatInfo::videoCodecForCaps(structure);
- m_metaData.insert(QMediaMetaData::VideoCodec, QVariant::fromValue(codec));
- qCDebug(qLcMediaPlayer) << " video" << caps.toString() << (int)codec;
- auto framerate = structure["framerate"].getFraction();
- if (framerate)
- m_metaData.insert(QMediaMetaData::VideoFrameRate, *framerate);
- auto width = structure["width"].toInt();
- auto height = structure["height"].toInt();
- if (width && height)
- m_metaData.insert(QMediaMetaData::Resolution, QSize(*width, *height));
- }
- }
-
- auto sinkPad = trackSelector(VideoStream).activeInputPad();
- if (!sinkPad.isNull()) {
- bool hasTags = g_object_class_find_property (G_OBJECT_GET_CLASS (sinkPad.object()), "tags") != NULL;
-
- GstTagList *tl = nullptr;
- g_object_get(sinkPad.object(), "tags", &tl, nullptr);
- qCDebug(qLcMediaPlayer) << " tags=" << hasTags << (tl ? gst_tag_list_to_string(tl) : "(null)");
- }
-
-
- qCDebug(qLcMediaPlayer) << "============== end parse topology ============";
- emit metaDataChanged();
- playerPipeline.dumpGraph("playback");
-}
-
-int QGstreamerMediaPlayer::trackCount(QPlatformMediaPlayer::TrackType type)
-{
- return trackSelector(type).trackCount();
-}
-
-QMediaMetaData QGstreamerMediaPlayer::trackMetaData(QPlatformMediaPlayer::TrackType type, int index)
-{
- auto track = trackSelector(type).inputPad(index);
- if (track.isNull())
- return {};
-
- GstTagList *tagList = nullptr;
- g_object_get(track.object(), "tags", &tagList, nullptr);
-
- return tagList ? QGstreamerMetaData::fromGstTagList(tagList) : QMediaMetaData{};
-}
-
-int QGstreamerMediaPlayer::activeTrack(TrackType type)
-{
- return trackSelector(type).activeInputIndex();
-}
-
-void QGstreamerMediaPlayer::setActiveTrack(TrackType type, int index)
-{
- auto &ts = trackSelector(type);
- auto track = ts.inputPad(index);
- if (track.isNull())
- return;
-
- if (type == QPlatformMediaPlayer::SubtitleStream)
- gstVideoOutput->flushSubtitles();
-
- qCDebug(qLcMediaPlayer) << "Setting active track type" << type << "to" << index;
- ts.setActiveInputPad(track);
-
- // seek to force an immediate change of the stream
- if (playerPipeline.state() == GST_STATE_PLAYING)
- playerPipeline.flush();
- else
- m_requiresSeekOnPlay = true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
deleted file mode 100644
index a811e2832..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERMEDIAPLAYER_P_H
-#define QGSTREAMERMEDIAPLAYER_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/qstack.h>
-#include <private/qplatformmediaplayer_p.h>
-#include <private/qtmultimediaglobal_p.h>
-#include <qurl.h>
-#include <private/qgst_p.h>
-#include <private/qgstpipeline_p.h>
-
-#include <QtCore/qtimer.h>
-
-#include <array>
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkAccessManager;
-class QGstreamerMessage;
-class QGstAppSrc;
-class QGstreamerAudioOutput;
-class QGstreamerVideoOutput;
-
-class Q_MULTIMEDIA_EXPORT QGstreamerMediaPlayer
- : public QObject,
- public QPlatformMediaPlayer,
- public QGstreamerBusMessageFilter,
- public QGstreamerSyncMessageFilter
-{
- Q_OBJECT
-
-public:
- QGstreamerMediaPlayer(QMediaPlayer *parent = 0);
- ~QGstreamerMediaPlayer();
-
- qint64 position() const override;
- qint64 duration() const override;
-
- float bufferProgress() const override;
-
- QMediaTimeRange availablePlaybackRanges() const override;
-
- qreal playbackRate() const override;
- void setPlaybackRate(qreal rate) override;
-
- QUrl media() const override;
- const QIODevice *mediaStream() const override;
- void setMedia(const QUrl&, QIODevice *) override;
-
- bool streamPlaybackSupported() const override { return true; }
-
- void setAudioOutput(QPlatformAudioOutput *output) override;
-
- QMediaMetaData metaData() const override;
-
- void setVideoSink(QVideoSink *sink) override;
-
- int trackCount(TrackType) override;
- QMediaMetaData trackMetaData(TrackType /*type*/, int /*streamNumber*/) override;
- int activeTrack(TrackType) override;
- void setActiveTrack(TrackType, int /*streamNumber*/) override;
-
- void setPosition(qint64 pos) override;
-
- void play() override;
- void pause() override;
- void stop() override;
-
- bool processBusMessage(const QGstreamerMessage& message) override;
- bool processSyncMessage(const QGstreamerMessage& message) override;
-
-public Q_SLOTS:
- void updatePosition() { positionChanged(position()); }
-
-private:
- struct TrackSelector {
- TrackSelector(TrackType, const char *name);
- QGstPad createInputPad();
- void removeInputPad(QGstPad pad);
- void removeAllInputPads();
- QGstPad inputPad(int index);
- int activeInputIndex() const { return tracks.indexOf(activeInputPad()); }
- QGstPad activeInputPad() const { return selector.getObject("active-pad"); }
- void setActiveInputPad(QGstPad input) { selector.set("active-pad", input); }
- int trackCount() const { return tracks.count(); }
-
- QGstElement selector;
- TrackType type;
- QList<QGstPad> tracks;
- QGstPad nullTrack;
- bool isConnected = false;
- };
-
- friend class QGstreamerStreamsControl;
- void decoderPadAdded(const QGstElement &src, const QGstPad &pad);
- void decoderPadRemoved(const QGstElement &src, const QGstPad &pad);
- static void uridecodebinElementAddedCallback(GstElement *uridecodebin, GstElement *child, QGstreamerMediaPlayer *that);
- void parseStreamsAndMetadata();
- void connectOutput(TrackSelector &ts);
- void removeOutput(TrackSelector &ts);
- void removeAllOutputs();
- void stopOrEOS(bool eos);
-
- std::array<TrackSelector, NTrackTypes> trackSelectors;
- TrackSelector &trackSelector(TrackType type);
-
- QMediaMetaData m_metaData;
-
- int m_bufferProgress = -1;
- QUrl m_url;
- QIODevice *m_stream = nullptr;
-
- bool prerolling = false;
- bool m_requiresSeekOnPlay = false;
- qint64 m_duration = 0;
- QTimer positionUpdateTimer;
-
- QGstAppSrc *m_appSrc = nullptr;
-
- GType decodebinType;
- QGstStructure topology;
-
- // Gst elements
- QGstPipeline playerPipeline;
- QGstElement src;
- QGstElement decoder;
-
- QGstreamerAudioOutput *gstAudioOutput = nullptr;
- QGstreamerVideoOutput *gstVideoOutput = nullptr;
-
- // QGstElement streamSynchronizer;
-
- QHash<QByteArray, QGstPad> decoderOutputMap;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermessage.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermessage.cpp
deleted file mode 100644
index 950cc46cb..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamermessage.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <gst/gst.h>
-
-#include "qgstreamermessage_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QGstreamerMessage
- \internal
-*/
-
-QGstreamerMessage::QGstreamerMessage(GstMessage* message):
- m_message(message)
-{
- gst_message_ref(m_message);
-}
-
-QGstreamerMessage::QGstreamerMessage(QGstreamerMessage const& m):
- m_message(m.m_message)
-{
- gst_message_ref(m_message);
-}
-
-
-QGstreamerMessage::~QGstreamerMessage()
-{
- if (m_message != nullptr)
- gst_message_unref(m_message);
-}
-
-GstMessage* QGstreamerMessage::rawMessage() const
-{
- return m_message;
-}
-
-QGstreamerMessage& QGstreamerMessage::operator=(QGstreamerMessage const& rhs)
-{
- if (rhs.m_message != m_message) {
- if (rhs.m_message != nullptr)
- gst_message_ref(rhs.m_message);
-
- if (m_message != nullptr)
- gst_message_unref(m_message);
-
- m_message = rhs.m_message;
- }
-
- return *this;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermessage_p.h b/src/multimedia/platform/gstreamer/common/qgstreamermessage_p.h
deleted file mode 100644
index 8d5ff440e..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamermessage_p.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERMESSAGE_P_H
-#define QGSTREAMERMESSAGE_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 <private/qtmultimediaglobal_p.h>
-#include <private/qgst_p.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QGstreamerMessage
-{
-public:
- QGstreamerMessage() = default;
- QGstreamerMessage(GstMessage* message);
- QGstreamerMessage(QGstreamerMessage const& m);
- ~QGstreamerMessage();
-
- bool isNull() const { return !m_message; }
- GstMessageType type() const { return GST_MESSAGE_TYPE(m_message); }
- QGstObject source() const { return QGstObject(GST_MESSAGE_SRC(m_message), QGstObject::NeedsRef); }
-
- GstMessage* rawMessage() const;
-
- QGstreamerMessage& operator=(QGstreamerMessage const& rhs);
-
-private:
- GstMessage* m_message = nullptr;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QGstreamerMessage);
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermetadata.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermetadata.cpp
deleted file mode 100644
index 3cf3146a3..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamermetadata.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamermetadata_p.h"
-#include <QDebug>
-#include <QtMultimedia/qmediametadata.h>
-#include <QtCore/qdatetime.h>
-
-#include <gst/gstversion.h>
-#include <private/qgstutils_p.h>
-
-QT_BEGIN_NAMESPACE
-
-struct {
- const char *tag;
- QMediaMetaData::Key key;
-} gstTagToMetaDataKey[] = {
- { GST_TAG_TITLE, QMediaMetaData::Title },
- { GST_TAG_COMMENT, QMediaMetaData::Comment },
- { GST_TAG_DESCRIPTION, QMediaMetaData::Description },
- { GST_TAG_GENRE, QMediaMetaData::Genre },
- { GST_TAG_DATE_TIME, QMediaMetaData::Date },
- { GST_TAG_DATE, QMediaMetaData::Date },
-
- { GST_TAG_LANGUAGE_CODE, QMediaMetaData::Language },
-
- { GST_TAG_ORGANIZATION, QMediaMetaData::Publisher },
- { GST_TAG_COPYRIGHT, QMediaMetaData::Copyright },
-
- // Media
- { GST_TAG_DURATION, QMediaMetaData::Duration },
-
- // Audio
- { GST_TAG_BITRATE, QMediaMetaData::AudioBitRate },
- { GST_TAG_AUDIO_CODEC, QMediaMetaData::AudioCodec },
-
- // Music
- { GST_TAG_ALBUM, QMediaMetaData::AlbumTitle },
- { GST_TAG_ALBUM_ARTIST, QMediaMetaData::AlbumArtist },
- { GST_TAG_ARTIST, QMediaMetaData::ContributingArtist },
- { GST_TAG_TRACK_NUMBER, QMediaMetaData::TrackNumber },
-
- { GST_TAG_PREVIEW_IMAGE, QMediaMetaData::ThumbnailImage },
- { GST_TAG_IMAGE, QMediaMetaData::CoverArtImage },
-
- // Image/Video
- { "resolution", QMediaMetaData::Resolution },
- { GST_TAG_IMAGE_ORIENTATION, QMediaMetaData::Orientation },
-
- // Video
- { GST_TAG_VIDEO_CODEC, QMediaMetaData::VideoCodec },
-
- // Movie
- { GST_TAG_PERFORMER, QMediaMetaData::LeadPerformer },
-
- { nullptr, QMediaMetaData::Title }
-};
-
-static QMediaMetaData::Key tagToKey(const char *tag)
-{
- auto *map = gstTagToMetaDataKey;
- while (map->tag) {
- if (!strcmp(map->tag, tag))
- return map->key;
- ++map;
- }
- return QMediaMetaData::Key(-1);
-}
-
-static const char *keyToTag(QMediaMetaData::Key key)
-{
- auto *map = gstTagToMetaDataKey;
- while (map->tag) {
- if (map->key == key)
- return map->tag;
- ++map;
- }
- return nullptr;
-}
-
-//internal
-static void addTagToMap(const GstTagList *list,
- const gchar *tag,
- gpointer user_data)
-{
- QMediaMetaData::Key key = tagToKey(tag);
- if (key == QMediaMetaData::Key(-1))
- return;
-
- auto *map = reinterpret_cast<QHash<QMediaMetaData::Key, QVariant>* >(user_data);
-
- GValue val;
- val.g_type = 0;
- gst_tag_list_copy_value(&val, list, tag);
-
-
- switch( G_VALUE_TYPE(&val) ) {
- case G_TYPE_STRING:
- {
- const gchar *str_value = g_value_get_string(&val);
- if (key == QMediaMetaData::Language) {
- map->insert(key, QLocale::codeToLanguage(QString::fromUtf8(str_value)));
- break;
- }
- map->insert(key, QString::fromUtf8(str_value));
- break;
- }
- case G_TYPE_INT:
- map->insert(key, g_value_get_int(&val));
- break;
- case G_TYPE_UINT:
- map->insert(key, g_value_get_uint(&val));
- break;
- case G_TYPE_LONG:
- map->insert(key, qint64(g_value_get_long(&val)));
- break;
- case G_TYPE_BOOLEAN:
- map->insert(key, g_value_get_boolean(&val));
- break;
- case G_TYPE_CHAR:
- map->insert(key, g_value_get_schar(&val));
- break;
- case G_TYPE_DOUBLE:
- map->insert(key, g_value_get_double(&val));
- break;
- default:
- // GST_TYPE_DATE is a function, not a constant, so pull it out of the switch
- if (G_VALUE_TYPE(&val) == G_TYPE_DATE) {
- const GDate *date = (const GDate *)g_value_get_boxed(&val);
- if (g_date_valid(date)) {
- int year = g_date_get_year(date);
- int month = g_date_get_month(date);
- int day = g_date_get_day(date);
- // don't insert if we already have a datetime.
- if (!map->contains(key))
- map->insert(key, QDateTime(QDate(year, month, day), QTime()));
- }
- } else if (G_VALUE_TYPE(&val) == GST_TYPE_DATE_TIME) {
- const GstDateTime *dateTime = (const GstDateTime *)g_value_get_boxed(&val);
- int year = gst_date_time_has_year(dateTime) ? gst_date_time_get_year(dateTime) : 0;
- int month = gst_date_time_has_month(dateTime) ? gst_date_time_get_month(dateTime) : 0;
- int day = gst_date_time_has_day(dateTime) ? gst_date_time_get_day(dateTime) : 0;
- int hour = 0;
- int minute = 0;
- int second = 0;
- float tz = 0;
- if (gst_date_time_has_time(dateTime)) {
- hour = gst_date_time_get_hour(dateTime);
- minute = gst_date_time_get_minute(dateTime);
- second = gst_date_time_get_second(dateTime);
- tz = gst_date_time_get_time_zone_offset(dateTime);
- }
- QDateTime qDateTime(QDate(year, month, day), QTime(hour, minute, second),
- Qt::OffsetFromUTC, tz * 60 * 60);
- map->insert(key, qDateTime);
- } else if (G_VALUE_TYPE(&val) == GST_TYPE_SAMPLE) {
- GstSample *sample = (GstSample *)g_value_get_boxed(&val);
- GstCaps* caps = gst_sample_get_caps(sample);
- if (caps && !gst_caps_is_empty(caps)) {
- GstStructure *structure = gst_caps_get_structure(caps, 0);
- const gchar *name = gst_structure_get_name(structure);
- if (QByteArray(name).startsWith("image/")) {
- GstBuffer *buffer = gst_sample_get_buffer(sample);
- if (buffer) {
- GstMapInfo info;
- gst_buffer_map(buffer, &info, GST_MAP_READ);
- map->insert(key, QImage::fromData(info.data, info.size, name));
- gst_buffer_unmap(buffer, &info);
- }
- }
- }
- } else if (G_VALUE_TYPE(&val) == GST_TYPE_FRACTION) {
- int nom = gst_value_get_fraction_numerator(&val);
- int denom = gst_value_get_fraction_denominator(&val);
-
- if (denom > 0) {
- map->insert(key, double(nom)/denom);
- }
- }
- break;
- }
-
- g_value_unset(&val);
-}
-
-
-QGstreamerMetaData QGstreamerMetaData::fromGstTagList(const GstTagList *tags)
-{
- QGstreamerMetaData m;
- gst_tag_list_foreach(tags, addTagToMap, &m.data);
- return m;
-}
-
-
-void QGstreamerMetaData::setMetaData(GstElement *element) const
-{
- if (!GST_IS_TAG_SETTER(element))
- return;
-
- gst_tag_setter_reset_tags(GST_TAG_SETTER(element));
-
- for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) {
- const char *tagName = keyToTag(it.key());
- if (!tagName)
- continue;
- const QVariant &tagValue = it.value();
-
- switch (tagValue.typeId()) {
- case QMetaType::QString:
- gst_tag_setter_add_tags(GST_TAG_SETTER(element),
- GST_TAG_MERGE_REPLACE,
- tagName,
- tagValue.toString().toUtf8().constData(),
- nullptr);
- break;
- case QMetaType::Int:
- case QMetaType::LongLong:
- gst_tag_setter_add_tags(GST_TAG_SETTER(element),
- GST_TAG_MERGE_REPLACE,
- tagName,
- tagValue.toInt(),
- nullptr);
- break;
- case QMetaType::Double:
- gst_tag_setter_add_tags(GST_TAG_SETTER(element),
- GST_TAG_MERGE_REPLACE,
- tagName,
- tagValue.toDouble(),
- nullptr);
- break;
- case QMetaType::QDateTime: {
- QDateTime date = tagValue.toDateTime();
- gst_tag_setter_add_tags(GST_TAG_SETTER(element),
- GST_TAG_MERGE_REPLACE,
- tagName,
- gst_date_time_new(date.offsetFromUtc() / 60. / 60.,
- date.date().year(), date.date().month(), date.date().day(),
- date.time().hour(), date.time().minute(), date.time().second()),
- nullptr);
- break;
- }
- case QMetaType::QLocale: {
- QString language = QLocale::languageToCode(tagValue.value<QLocale::Language>());
- gst_tag_setter_add_tags(GST_TAG_SETTER(element),
- GST_TAG_MERGE_REPLACE,
- tagName,
- language.toUtf8().constData(),
- nullptr);
- }
-
- default:
- break;
- }
- }
-}
-
-void QGstreamerMetaData::setMetaData(GstBin *bin) const
-{
- GstIterator *elements = gst_bin_iterate_all_by_interface(bin, GST_TYPE_TAG_SETTER);
- GValue item = G_VALUE_INIT;
- while (gst_iterator_next(elements, &item) == GST_ITERATOR_OK) {
- GstElement * const element = GST_ELEMENT(g_value_get_object(&item));
- setMetaData(element);
- }
- gst_iterator_free(elements);
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermetadata_p.h b/src/multimedia/platform/gstreamer/common/qgstreamermetadata_p.h
deleted file mode 100644
index 53b29f548..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamermetadata_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERMETADATA_H
-#define QGSTREAMERMETADATA_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 <qmediametadata.h>
-#include <qvariant.h>
-
-#include <gst/gst.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerMetaData : public QMediaMetaData
-{
-public:
- static QGstreamerMetaData fromGstTagList(const GstTagList *tags);
- GstTagList *toGstTagList() const;
-
- void setMetaData(GstBin *bin) const;
- void setMetaData(GstElement *element) const;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERMETADATA_H
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp
deleted file mode 100644
index 36e0823d8..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qgstreamervideooutput_p.h>
-#include <private/qgstreamervideosink_p.h>
-#include <private/qgstsubtitlesink_p.h>
-#include <qvideosink.h>
-
-#include <QtCore/qloggingcategory.h>
-#include <qthread.h>
-
-Q_LOGGING_CATEGORY(qLcMediaVideoOutput, "qt.multimedia.videooutput")
-
-QT_BEGIN_NAMESPACE
-
-QGstreamerVideoOutput::QGstreamerVideoOutput(QObject *parent)
- : QObject(parent),
- gstVideoOutput("videoOutput")
-{
- videoQueue = QGstElement("queue", "videoQueue");
- videoConvert = QGstElement("videoconvert", "videoConvert");
- videoSink = QGstElement("fakesink", "fakeVideoSink");
- gstVideoOutput.add(videoQueue, videoConvert, videoSink);
- if (!videoQueue.link(videoConvert, videoSink))
- qCDebug(qLcMediaVideoOutput) << ">>>>>> linking failed";
-
- gstVideoOutput.addGhostPad(videoQueue, "sink");
-}
-
-QGstreamerVideoOutput::~QGstreamerVideoOutput()
-{
- gstVideoOutput.setStateSync(GST_STATE_NULL);
-}
-
-void QGstreamerVideoOutput::setVideoSink(QVideoSink *sink)
-{
- auto *gstVideoSink = sink ? static_cast<QGstreamerVideoSink *>(sink->platformVideoSink()) : nullptr;
- if (gstVideoSink == m_videoSink)
- return;
-
- if (m_videoSink)
- m_videoSink->setPipeline({});
-
- m_videoSink = gstVideoSink;
- if (m_videoSink)
- m_videoSink->setPipeline(gstPipeline);
-
- QGstElement gstSink;
- if (m_videoSink) {
- gstSink = m_videoSink->gstSink();
- isFakeSink = false;
- } else {
- gstSink = QGstElement("fakesink", "fakevideosink");
- isFakeSink = true;
- }
-
- if (videoSink == gstSink)
- return;
-
- gstPipeline.beginConfig();
- if (!videoSink.isNull()) {
- videoSink.setStateSync(GST_STATE_NULL);
- gstVideoOutput.remove(videoSink);
- }
- videoSink = gstSink;
- gstVideoOutput.add(videoSink);
-
- videoConvert.link(videoSink);
- GstEvent *event = gst_event_new_reconfigure();
- gst_element_send_event(videoSink.element(), event);
- videoSink.setState(GST_STATE_PAUSED);
-
- doLinkSubtitleStream();
-
- gstPipeline.endConfig();
-
- 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());
-
-}
-
-void QGstreamerVideoOutput::setPipeline(const QGstPipeline &pipeline)
-{
- gstPipeline = pipeline;
- if (m_videoSink)
- m_videoSink->setPipeline(gstPipeline);
-}
-
-void QGstreamerVideoOutput::linkSubtitleStream(QGstElement src)
-{
- qCDebug(qLcMediaVideoOutput) << "link subtitle stream" << src.isNull();
- if (src == subtitleSrc)
- return;
-
- gstPipeline.beginConfig();
- subtitleSrc = src;
- doLinkSubtitleStream();
- gstPipeline.endConfig();
-}
-
-void QGstreamerVideoOutput::doLinkSubtitleStream()
-{
- if (!subtitleSink.isNull()) {
- subtitleSink.setStateSync(GST_STATE_NULL);
- gstPipeline.remove(subtitleSink);
- subtitleSink = {};
- }
- if (!m_videoSink || subtitleSrc.isNull())
- return;
- if (subtitleSink.isNull()) {
- subtitleSink = m_videoSink->subtitleSink();
- gstPipeline.add(subtitleSink);
- }
- if (!subtitleSrc.link(subtitleSink))
- qCDebug(qLcMediaVideoOutput) << "link subtitle stream failed";
-}
-
-void QGstreamerVideoOutput::setIsPreview()
-{
- // configures the queue to be fast and lightweight for camera preview
- // also avoids blocking the queue in case we have an encodebin attached to the tee as well
- videoQueue.set("leaky", 2 /*downstream*/);
- videoQueue.set("silent", true);
- videoQueue.set("max-size-buffers", 1);
- videoQueue.set("max-size-bytes", 0);
- videoQueue.set("max-size-time", 0);
-}
-
-void QGstreamerVideoOutput::flushSubtitles()
-{
- if (!subtitleSink.isNull()) {
- auto pad = subtitleSink.staticPad("sink");
- auto *event = gst_event_new_flush_start();
- pad.sendEvent(event);
- event = gst_event_new_flush_stop(false);
- pad.sendEvent(event);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h
deleted file mode 100644
index 41e8da413..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERVIDEOOUTPUT_P_H
-#define QGSTREAMERVIDEOOUTPUT_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/qobject.h>
-#include <private/qtmultimediaglobal_p.h>
-#include <private/qgst_p.h>
-#include <private/qgstpipeline_p.h>
-#include <qwaitcondition.h>
-#include <qmutex.h>
-#include <qpointer.h>
-#include <private/qgstreamervideosink_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QVideoSink;
-
-class Q_MULTIMEDIA_EXPORT QGstreamerVideoOutput : public QObject
-{
- Q_OBJECT
-
-public:
- QGstreamerVideoOutput(QObject *parent = 0);
- ~QGstreamerVideoOutput();
-
- void setVideoSink(QVideoSink *sink);
- QGstreamerVideoSink *gstreamerVideoSink() const { return m_videoSink; }
-
- void setPipeline(const QGstPipeline &pipeline);
-
- QGstElement gstElement() const { return gstVideoOutput; }
- void linkSubtitleStream(QGstElement subtitleSrc);
-
- void setIsPreview();
- void flushSubtitles();
-
-private:
- void doLinkSubtitleStream();
-
- QPointer<QGstreamerVideoSink> m_videoSink;
- bool isFakeSink = true;
-
- // Gst elements
- QGstPipeline gstPipeline;
-
- QGstBin gstVideoOutput;
- QGstElement videoQueue;
- QGstElement videoConvert;
- QGstElement videoSink;
-
- QGstElement subtitleSrc;
- QGstElement subtitleSink;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp b/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp
deleted file mode 100644
index f682e8665..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamervideooverlay_p.h"
-
-#include <QtGui/qguiapplication.h>
-#include "qgstutils_p.h"
-#include "private/qgst_p.h"
-#include "private/qgstreamermessage_p.h"
-#include "private/qgstreamervideosink_p.h"
-
-#include <gst/video/videooverlay.h>
-
-#include <QtMultimedia/private/qtmultimediaglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-struct ElementMap
-{
- const char *qtPlatform;
- const char *gstreamerElement;
-};
-
-// Ordered by descending priority
-static constexpr ElementMap elementMap[] =
-{
- { "xcb", "xvimagesink" },
- { "xcb", "ximagesink" },
-
- // wayland
- { "wayland", "waylandsink" }
-};
-
-static bool qt_gst_element_is_functioning(QGstElement element)
-{
- GstStateChangeReturn ret = element.setState(GST_STATE_READY);
- if (ret == GST_STATE_CHANGE_SUCCESS) {
- element.setState(GST_STATE_NULL);
- return true;
- }
-
- return false;
-}
-
-static QGstElement findBestVideoSink()
-{
- QString platform = QGuiApplication::platformName();
-
- // First, try some known video sinks, depending on the Qt platform plugin in use.
- for (auto i : elementMap) {
- if (platform != QLatin1String(i.qtPlatform))
- continue;
- QGstElement choice(i.gstreamerElement, i.gstreamerElement);
- if (choice.isNull())
- continue;
-
- if (qt_gst_element_is_functioning(choice))
- return choice;
- }
-
- // We need a native window ID to use the GstVideoOverlay interface.
- // Bail out if the Qt platform plugin in use cannot provide a sensible WId.
- if (platform != QLatin1String("xcb") && platform != QLatin1String("wayland"))
- return {};
-
- QGstElement choice;
- // If none of the known video sinks are available, try to find one that implements the
- // GstVideoOverlay interface and has autoplugging rank.
- GList *list = qt_gst_video_sinks();
- for (GList *item = list; item != nullptr; item = item->next) {
- GstElementFactory *f = GST_ELEMENT_FACTORY(item->data);
-
- if (!gst_element_factory_has_interface(f, "GstVideoOverlay"))
- continue;
-
- choice = QGstElement(gst_element_factory_create(f, nullptr));
- if (choice.isNull())
- continue;
-
- if (qt_gst_element_is_functioning(choice))
- break;
- choice = {};
- }
-
- gst_plugin_feature_list_free(list);
- if (choice.isNull())
- qWarning() << "Could not find a valid windowed video sink";
-
- return choice;
-}
-
-QGstreamerVideoOverlay::QGstreamerVideoOverlay(QGstreamerVideoSink *parent, const QByteArray &elementName)
- : QObject(parent)
- , QGstreamerBufferProbe(QGstreamerBufferProbe::ProbeCaps)
- , m_gstreamerVideoSink(parent)
-{
- QGstElement sink;
- if (!elementName.isEmpty())
- sink = QGstElement(elementName.constData(), nullptr);
- else
- sink = findBestVideoSink();
-
- setVideoSink(sink);
-}
-
-QGstreamerVideoOverlay::~QGstreamerVideoOverlay()
-{
- if (!m_videoSink.isNull()) {
- QGstPad pad = m_videoSink.staticPad("sink");
- removeProbeFromPad(pad.pad());
- }
-}
-
-QGstElement QGstreamerVideoOverlay::videoSink() const
-{
- return m_videoSink;
-}
-
-void QGstreamerVideoOverlay::setVideoSink(QGstElement sink)
-{
- if (sink.isNull())
- return;
-
- m_videoSink = sink;
-
- QGstPad pad = m_videoSink.staticPad("sink");
- addProbeToPad(pad.pad());
-
- auto *klass = G_OBJECT_GET_CLASS(m_videoSink.object());
- m_hasForceAspectRatio = g_object_class_find_property(klass, "force-aspect-ratio");
- m_hasFullscreen = g_object_class_find_property(klass, "fullscreen");
-}
-
-QSize QGstreamerVideoOverlay::nativeVideoSize() const
-{
- return m_nativeVideoSize;
-}
-
-void QGstreamerVideoOverlay::setWindowHandle(WId id)
-{
- m_windowId = id;
-
- if (!m_videoSink.isNull() && GST_IS_VIDEO_OVERLAY(m_videoSink.object())) {
- applyRenderRect();
-
- // Properties need to be reset when changing the winId.
- setAspectRatioMode(m_aspectRatioMode);
- setFullScreen(m_fullScreen);
- applyRenderRect();
- }
-}
-
-void QGstreamerVideoOverlay::setRenderRectangle(const QRect &rect)
-{
- renderRect = rect;
- applyRenderRect();
-}
-
-void QGstreamerVideoOverlay::applyRenderRect()
-{
- if (!m_windowId)
- return;
-
- int x = -1;
- int y = -1;
- int w = -1;
- int h = -1;
-
- if (!renderRect.isEmpty()) {
- x = renderRect.x();
- y = renderRect.y();
- w = renderRect.width();
- h = renderRect.height();
- QSize scaledVideo = m_nativeVideoSize.scaled(w, h, m_aspectRatioMode);
- x += (w - scaledVideo.width())/2;
- y += (h - scaledVideo.height())/2;
- w = scaledVideo.width();
- h = scaledVideo.height();
- }
-
- if (!m_videoSink.isNull() && GST_IS_VIDEO_OVERLAY(m_videoSink.object()))
- gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_videoSink.object()), x, y, w, h);
-}
-
-void QGstreamerVideoOverlay::probeCaps(GstCaps *caps)
-{
- QSize size = QGstCaps(caps).at(0).resolution();
- if (size != m_nativeVideoSize) {
- m_nativeVideoSize = size;
- m_gstreamerVideoSink->setNativeSize(m_nativeVideoSize);
- applyRenderRect();
- }
-}
-
-void QGstreamerVideoOverlay::setAspectRatioMode(Qt::AspectRatioMode mode)
-{
- m_aspectRatioMode = mode;
- if (m_hasForceAspectRatio)
- m_videoSink.set("force-aspect-ratio", (mode == Qt::KeepAspectRatio));
-}
-
-void QGstreamerVideoOverlay::setFullScreen(bool fullscreen)
-{
- m_fullScreen = fullscreen;
- if (m_hasFullscreen)
- m_videoSink.set("fullscreen", fullscreen);
-}
-
-bool QGstreamerVideoOverlay::processSyncMessage(const QGstreamerMessage &message)
-{
- if (!gst_is_video_overlay_prepare_window_handle_message(message.rawMessage()))
- return false;
- gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(m_videoSink.object()), m_windowId);
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay_p.h b/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay_p.h
deleted file mode 100644
index 234fc56ff..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay_p.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERVIDEOOVERLAY_P_H
-#define QGSTREAMERVIDEOOVERLAY_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 <private/qgstpipeline_p.h>
-#include <private/qgstreamerbufferprobe_p.h>
-#include <private/qgst_p.h>
-#include <QtGui/qwindowdefs.h>
-
-QT_BEGIN_NAMESPACE
-class QGstreamerVideoSink;
-
-class Q_MULTIMEDIA_EXPORT QGstreamerVideoOverlay
- : public QObject
- , public QGstreamerSyncMessageFilter
- , private QGstreamerBufferProbe
-{
- Q_OBJECT
-public:
- explicit QGstreamerVideoOverlay(QGstreamerVideoSink *parent = 0, const QByteArray &elementName = QByteArray());
- virtual ~QGstreamerVideoOverlay();
-
- QGstElement videoSink() const;
- void setVideoSink(QGstElement);
- QSize nativeVideoSize() const;
-
- void setWindowHandle(WId id);
- void setRenderRectangle(const QRect &rect);
-
- void setAspectRatioMode(Qt::AspectRatioMode mode);
- void setFullScreen(bool fullscreen);
-
- bool processSyncMessage(const QGstreamerMessage &message) override;
-
- bool isNull() const { return m_videoSink.isNull(); }
-
-Q_SIGNALS:
- void nativeVideoSizeChanged();
- void activeChanged();
-
-private:
- void probeCaps(GstCaps *caps) override;
- void applyRenderRect();
-
- QGstreamerVideoSink *m_gstreamerVideoSink = nullptr;
- QGstElement m_videoSink;
- QSize m_nativeVideoSize;
-
- bool m_hasForceAspectRatio = false;
- bool m_hasFullscreen = false;
- Qt::AspectRatioMode m_aspectRatioMode = Qt::KeepAspectRatio;
- bool m_fullScreen = false;
-
- WId m_windowId = 0;
- QRect renderRect;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERVIDEOOVERLAY_P_H
-
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp b/src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp
deleted file mode 100644
index ca7daf6eb..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamervideosink_p.h"
-#include "private/qgstvideorenderersink_p.h"
-#include "private/qgstsubtitlesink_p.h"
-#include <private/qgstutils_p.h>
-#include <QtGui/private/qrhi_p.h>
-
-#if QT_CONFIG(gstreamer_gl)
-#include <QtGui/private/qrhigles2_p.h>
-#include <QGuiApplication>
-#include <QtGui/qopenglcontext.h>
-#include <QWindow>
-#include <qpa/qplatformnativeinterface.h>
-#include <gst/gl/gstglconfig.h>
-
-#if GST_GL_HAVE_WINDOW_X11
-# include <gst/gl/x11/gstgldisplay_x11.h>
-#endif
-#if GST_GL_HAVE_PLATFORM_EGL
-# include <gst/gl/egl/gstgldisplay_egl.h>
-# include <EGL/egl.h>
-# include <EGL/eglext.h>
-#endif
-#if GST_GL_HAVE_WINDOW_WAYLAND
-# include <gst/gl/wayland/gstgldisplay_wayland.h>
-#endif
-#endif // #if QT_CONFIG(gstreamer_gl)
-
-#include <QtCore/qdebug.h>
-
-#include <QtCore/qloggingcategory.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(qLcMediaVideoSink, "qt.multimedia.videosink")
-
-QGstreamerVideoSink::QGstreamerVideoSink(QVideoSink *parent)
- : QPlatformVideoSink(parent)
-{
- sinkBin = QGstBin("videoSinkBin");
- // This is a hack for some iMX platforms. Thos 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 marked as
- // a regular supported video/x-raw format.
- //
- // To fix this, simply insert the element into the pipeline if it's available. Otherwise
- // we simply use an identity element.
- gstQueue = QGstElement("queue");
- auto imxVideoConvert = QGstElement("imxvideoconvert_g2d");
- if (!imxVideoConvert.isNull())
- gstPreprocess = imxVideoConvert;
- else
- gstPreprocess = QGstElement("identity");
- sinkBin.add(gstQueue, gstPreprocess);
- gstQueue.link(gstPreprocess);
- sinkBin.addGhostPad(gstQueue, "sink");
-
- gstSubtitleSink = GST_ELEMENT(QGstSubtitleSink::createSink(this));
-}
-
-QGstreamerVideoSink::~QGstreamerVideoSink()
-{
- unrefGstContexts();
-
- setPipeline(QGstPipeline());
-}
-
-QGstElement QGstreamerVideoSink::gstSink()
-{
- updateSinkElement();
- return sinkBin;
-}
-
-void QGstreamerVideoSink::setPipeline(QGstPipeline pipeline)
-{
- gstPipeline = pipeline;
-}
-
-void QGstreamerVideoSink::setRhi(QRhi *rhi)
-{
- if (rhi && rhi->backend() != QRhi::OpenGLES2)
- rhi = nullptr;
- if (m_rhi == rhi)
- return;
-
- m_rhi = rhi;
- updateGstContexts();
- if (!gstQtSink.isNull()) {
- // force creation of a new sink with proper caps
- createQtSink();
- updateSinkElement();
- }
-}
-
-void QGstreamerVideoSink::createQtSink()
-{
- gstQtSink = QGstElement(reinterpret_cast<GstElement *>(QGstVideoRendererSink::createSink(this)));
-}
-
-void QGstreamerVideoSink::updateSinkElement()
-{
- QGstElement newSink;
- if (gstQtSink.isNull())
- createQtSink();
- newSink = gstQtSink;
-
- if (newSink == gstVideoSink)
- return;
-
- gstPipeline.beginConfig();
-
- if (!gstVideoSink.isNull()) {
- gstVideoSink.setStateSync(GST_STATE_NULL);
- sinkBin.remove(gstVideoSink);
- }
-
- gstVideoSink = newSink;
- sinkBin.add(gstVideoSink);
- if (!gstPreprocess.link(gstVideoSink))
- qCDebug(qLcMediaVideoSink) << "couldn't link preprocess and sink";
- gstVideoSink.setState(GST_STATE_PAUSED);
-
- gstPipeline.endConfig();
- gstPipeline.dumpGraph("updateVideoSink");
-}
-
-void QGstreamerVideoSink::unrefGstContexts()
-{
- if (m_gstGlDisplayContext)
- gst_context_unref(m_gstGlDisplayContext);
- m_gstGlDisplayContext = nullptr;
- if (m_gstGlLocalContext)
- gst_context_unref(m_gstGlLocalContext);
- m_gstGlLocalContext = nullptr;
- m_eglDisplay = nullptr;
- m_eglImageTargetTexture2D = nullptr;
-}
-
-void QGstreamerVideoSink::updateGstContexts()
-{
- unrefGstContexts();
-
-#if QT_CONFIG(gstreamer_gl)
- if (!m_rhi || m_rhi->backend() != QRhi::OpenGLES2)
- return;
-
- auto *nativeHandles = static_cast<const QRhiGles2NativeHandles *>(m_rhi->nativeHandles());
- auto glContext = nativeHandles->context;
- Q_ASSERT(glContext);
-
- const QString platform = QGuiApplication::platformName();
- QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface();
- m_eglDisplay = pni->nativeResourceForIntegration("egldisplay");
- qDebug() << "platform is" << platform << m_eglDisplay;
-
- GstGLDisplay *gstGlDisplay = nullptr;
- const char *contextName = "eglcontext";
- GstGLPlatform glPlatform = GST_GL_PLATFORM_EGL;
- // use the egl display if we have one
- if (m_eglDisplay) {
-#if GST_GL_HAVE_PLATFORM_EGL
- gstGlDisplay = (GstGLDisplay *)gst_gl_display_egl_new_with_egl_display(m_eglDisplay);
- m_eglImageTargetTexture2D = eglGetProcAddress("glEGLImageTargetTexture2DOES");
-#endif
- } else {
- auto display = pni->nativeResourceForIntegration("display");
-
- if (display) {
-#if GST_GL_HAVE_WINDOW_X11
- if (platform == QLatin1String("xcb")) {
- contextName = "glxcontext";
- glPlatform = GST_GL_PLATFORM_GLX;
-
- gstGlDisplay = (GstGLDisplay *)gst_gl_display_x11_new_with_display((Display *)display);
- }
-#endif
-#if GST_GL_HAVE_WINDOW_WAYLAND
- if (platform.startsWith(QLatin1String("wayland"))) {
- Q_ASSERT(!gstGlDisplay);
- gstGlDisplay = (GstGLDisplay *)gst_gl_display_wayland_new_with_display((struct wl_display *)display);
- }
-#endif
- }
- }
-
- if (!gstGlDisplay) {
- qWarning() << "Could not create GstGLDisplay";
- return;
- }
-
- void *nativeContext = pni->nativeResourceForContext(contextName, glContext);
- if (!nativeContext)
- qWarning() << "Could not find resource for" << contextName;
-
- GstGLAPI glApi = QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL ? GST_GL_API_OPENGL : GST_GL_API_GLES2;
- GstGLContext *appContext = gst_gl_context_new_wrapped(gstGlDisplay, (guintptr)nativeContext, glPlatform, glApi);
- if (!appContext)
- qWarning() << "Could not create wrappped context for platform:" << glPlatform;
-
- GstGLContext *displayContext = nullptr;
- GError *error = nullptr;
- gst_gl_display_create_context(gstGlDisplay, appContext, &displayContext, &error);
- if (error) {
- qWarning() << "Could not create display context:" << error->message;
- g_clear_error(&error);
- }
-
- if (appContext)
- gst_object_unref(appContext);
-
- m_gstGlDisplayContext = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, false);
- gst_context_set_gl_display(m_gstGlDisplayContext, gstGlDisplay);
-
- m_gstGlLocalContext = gst_context_new("gst.gl.local_context", false);
- GstStructure *structure = gst_context_writable_structure(m_gstGlLocalContext);
- gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, displayContext, nullptr);
-
- if (!gstPipeline.isNull())
- gst_element_set_context(gstPipeline.element(), m_gstGlLocalContext);
-#endif // #if QT_CONFIG(gstreamer_gl)
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h b/src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h
deleted file mode 100644
index a049bc465..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERVIDEOWINDOW_H
-#define QGSTREAMERVIDEOWINDOW_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtmultimediaglobal_p.h>
-#include <private/qplatformvideosink_p.h>
-
-#include <private/qgstpipeline_p.h>
-#include <private/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 Q_MULTIMEDIA_EXPORT QGstreamerVideoSink
- : public QPlatformVideoSink
-{
- Q_OBJECT
-public:
- explicit QGstreamerVideoSink(QVideoSink *parent = 0);
- ~QGstreamerVideoSink();
-
- void setRhi(QRhi *rhi) override;
- QRhi *rhi() const { return m_rhi; }
-
- QGstElement gstSink();
- QGstElement subtitleSink() const { return gstSubtitleSink; }
-
- void setPipeline(QGstPipeline pipeline);
-
- GstContext *gstGlDisplayContext() const { return m_gstGlDisplayContext; }
- GstContext *gstGlLocalContext() const { return m_gstGlLocalContext; }
- Qt::HANDLE eglDisplay() const { return m_eglDisplay; }
- QFunctionPointer eglImageTargetTexture2D() const { return m_eglImageTargetTexture2D; }
-
-private:
- void createQtSink();
- void updateSinkElement();
-
- void unrefGstContexts();
- void updateGstContexts();
-
- QGstPipeline gstPipeline;
- QGstBin sinkBin;
- QGstElement gstQueue;
- QGstElement gstPreprocess;
- QGstElement gstVideoSink;
- QGstElement gstQtSink;
- QGstElement gstSubtitleSink;
-
- QRhi *m_rhi = nullptr;
-
- Qt::HANDLE m_eglDisplay = nullptr;
- QFunctionPointer m_eglImageTargetTexture2D = nullptr;
- GstContext *m_gstGlLocalContext = nullptr;
- GstContext *m_gstGlDisplayContext = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstsubtitlesink.cpp b/src/multimedia/platform/gstreamer/common/qgstsubtitlesink.cpp
deleted file mode 100644
index d9b76d57f..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstsubtitlesink.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QDebug>
-#include <QThread>
-#include <QEvent>
-
-#include "qgstreamervideosink_p.h"
-#include "qgstsubtitlesink_p.h"
-#include "qgstutils_p.h"
-
-QT_BEGIN_NAMESPACE
-
-static GstBaseSinkClass *sink_parent_class;
-static thread_local QGstreamerVideoSink *current_sink;
-
-#define ST_SINK(s) QGstSubtitleSink *sink(reinterpret_cast<QGstSubtitleSink *>(s))
-
-QGstSubtitleSink *QGstSubtitleSink::createSink(QGstreamerVideoSink *sink)
-{
- current_sink = sink;
-
- QGstSubtitleSink *gstSink = reinterpret_cast<QGstSubtitleSink *>(
- g_object_new(QGstSubtitleSink::get_type(), nullptr));
- g_object_set(gstSink, "async", false, nullptr);
-
- return gstSink;
-}
-
-GType QGstSubtitleSink::get_type()
-{
- static GType type = 0;
-
- if (type == 0) {
- static const GTypeInfo info =
- {
- sizeof(QGstSubtitleSinkClass), // class_size
- base_init, // base_init
- nullptr, // base_finalize
- class_init, // class_init
- nullptr, // class_finalize
- nullptr, // class_data
- sizeof(QGstSubtitleSink), // instance_size
- 0, // n_preallocs
- instance_init, // instance_init
- nullptr // value_table
- };
-
- type = g_type_register_static(
- GST_TYPE_BASE_SINK, "QGstSubtitleSink", &info, GTypeFlags(0));
-
- // Register the sink type to be used in custom piplines.
- // When surface is ready the sink can be used.
- gst_element_register(nullptr, "qtsubtitlesink", GST_RANK_PRIMARY, type);
- }
-
- return type;
-}
-
-void QGstSubtitleSink::class_init(gpointer g_class, gpointer class_data)
-{
- Q_UNUSED(class_data);
-
- sink_parent_class = reinterpret_cast<GstBaseSinkClass *>(g_type_class_peek_parent(g_class));
-
- GstBaseSinkClass *base_sink_class = reinterpret_cast<GstBaseSinkClass *>(g_class);
- base_sink_class->render = QGstSubtitleSink::render;
- base_sink_class->get_caps = QGstSubtitleSink::get_caps;
- base_sink_class->set_caps = QGstSubtitleSink::set_caps;
- base_sink_class->propose_allocation = QGstSubtitleSink::propose_allocation;
- base_sink_class->wait_event = QGstSubtitleSink::wait_event;
-
- GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class);
- element_class->change_state = QGstSubtitleSink::change_state;
- gst_element_class_set_metadata(element_class,
- "Qt built-in subtitle sink",
- "Sink/Subtitle",
- "Qt default built-in subtitle sink",
- "The Qt Company");
-
- GObjectClass *object_class = reinterpret_cast<GObjectClass *>(g_class);
- object_class->finalize = QGstSubtitleSink::finalize;
-}
-
-void QGstSubtitleSink::base_init(gpointer g_class)
-{
- static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE(
- "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("ANY"));
-
- gst_element_class_add_pad_template(
- GST_ELEMENT_CLASS(g_class), gst_static_pad_template_get(&sink_pad_template));
-}
-
-void QGstSubtitleSink::instance_init(GTypeInstance *instance, gpointer g_class)
-{
- Q_UNUSED(g_class);
- ST_SINK(instance);
-
- Q_ASSERT(current_sink);
- sink->sink = current_sink;
- current_sink = nullptr;
-}
-
-void QGstSubtitleSink::finalize(GObject *object)
-{
- // Chain up
- G_OBJECT_CLASS(sink_parent_class)->finalize(object);
-}
-
-GstStateChangeReturn QGstSubtitleSink::change_state(GstElement *element, GstStateChange transition)
-{
- return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition);
-}
-
-GstCaps *QGstSubtitleSink::get_caps(GstBaseSink *base, GstCaps *filter)
-{
- return sink_parent_class->get_caps(base, filter);
-}
-
-gboolean QGstSubtitleSink::set_caps(GstBaseSink *base, GstCaps *caps)
-{
- qDebug() << "set_caps:" << QGstCaps(caps).toString();
- return sink_parent_class->set_caps(base, caps);
-}
-
-gboolean QGstSubtitleSink::propose_allocation(GstBaseSink *base, GstQuery *query)
-{
- return sink_parent_class->propose_allocation(base, query);
-}
-
-GstFlowReturn QGstSubtitleSink::wait_event(GstBaseSink *base, GstEvent *event)
-{
- GstFlowReturn retval = sink_parent_class->wait_event(base, event);
- ST_SINK(base);
- if (event->type == GST_EVENT_GAP) {
-// qDebug() << "gap, clearing subtitle";
- sink->sink->setSubtitleText(QString());
- }
- return retval;
-}
-
-GstFlowReturn QGstSubtitleSink::render(GstBaseSink *base, GstBuffer *buffer)
-{
- ST_SINK(base);
- GstMemory *mem = gst_buffer_get_memory(buffer, 0);
- GstMapInfo info;
- QString subtitle;
- if (gst_memory_map(mem, &info, GST_MAP_READ))
- subtitle = QString::fromUtf8(info.data);
- gst_memory_unmap(mem, &info);
-// qDebug() << "render" << buffer << subtitle;
- sink->sink->setSubtitleText(subtitle);
- return GST_FLOW_OK;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstsubtitlesink_p.h b/src/multimedia/platform/gstreamer/common/qgstsubtitlesink_p.h
deleted file mode 100644
index aa9127c7d..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstsubtitlesink_p.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTSUBTITLESINK_P_H
-#define QGSTSUBTITLESINK_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/qtmultimediaglobal_p.h>
-
-#include <QtCore/qlist.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qqueue.h>
-#include <QtCore/qpointer.h>
-#include <QtCore/qwaitcondition.h>
-#include <private/qgst_p.h>
-#include <gst/base/gstbasesink.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerVideoSink;
-
-class Q_MULTIMEDIA_EXPORT QGstSubtitleSink
-{
-public:
- GstBaseSink parent;
-
- static QGstSubtitleSink *createSink(QGstreamerVideoSink *sink);
-
-private:
- static GType get_type();
- static void class_init(gpointer g_class, gpointer class_data);
- static void base_init(gpointer g_class);
- static void instance_init(GTypeInstance *instance, gpointer g_class);
-
- static void finalize(GObject *object);
-
- static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
-
- static GstCaps *get_caps(GstBaseSink *sink, GstCaps *filter);
- static gboolean set_caps(GstBaseSink *sink, GstCaps *caps);
-
- static gboolean propose_allocation(GstBaseSink *sink, GstQuery *query);
-
- static GstFlowReturn wait_event(GstBaseSink * sink, GstEvent * event);
- static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer);
-
-private:
- QGstreamerVideoSink *sink = nullptr;
-};
-
-
-class QGstSubtitleSinkClass
-{
-public:
- GstBaseSinkClass parent_class;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstutils.cpp b/src/multimedia/platform/gstreamer/common/qgstutils.cpp
deleted file mode 100644
index 3a0215e35..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstutils.cpp
+++ /dev/null
@@ -1,423 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtMultimedia/private/qtmultimediaglobal_p.h>
-#include "qgstutils_p.h"
-
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qregularexpression.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qset.h>
-#include <QtCore/qstringlist.h>
-#include <QtGui/qimage.h>
-#include <qaudioformat.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtMultimedia/qvideoframeformat.h>
-#include <private/qmultimediautils_p.h>
-
-#include <gst/audio/audio.h>
-#include <gst/video/video.h>
-
-template<typename T, int N> constexpr int lengthOf(const T (&)[N]) { return N; }
-
-QT_BEGIN_NAMESPACE
-
-
-namespace {
-
-static const char *audioSampleFormatNames[QAudioFormat::NSampleFormats] = {
- nullptr,
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- "U8",
- "S16LE",
- "S32LE",
- "F32LE"
-#else
- "U8",
- "S16BE",
- "S32BE",
- "F32BE"
-#endif
-};
-
-static QAudioFormat::SampleFormat gstSampleFormatToSampleFormat(const char *fmt)
-{
- if (fmt) {
- for (int i = 1; i < QAudioFormat::NSampleFormats; ++i) {
- if (strcmp(fmt, audioSampleFormatNames[i]))
- continue;
- return QAudioFormat::SampleFormat(i);
- }
- }
- return QAudioFormat::Unknown;
-}
-
-}
-
-/*
- Returns audio format for a sample \a sample.
- If the buffer doesn't have a valid audio format, an empty QAudioFormat is returned.
-*/
-QAudioFormat QGstUtils::audioFormatForSample(GstSample *sample)
-{
- QGstCaps caps = gst_sample_get_caps(sample);
- if (caps.isNull())
- return QAudioFormat();
- return audioFormatForCaps(caps);
-}
-
-QAudioFormat QGstUtils::audioFormatForCaps(QGstCaps caps)
-{
- QAudioFormat format;
- QGstStructure s = caps.at(0);
- if (s.name() != "audio/x-raw")
- return format;
-
- auto rate = s["rate"].toInt();
- auto channels = s["channels"].toInt();
- QAudioFormat::SampleFormat fmt = gstSampleFormatToSampleFormat(s["format"].toString());
- if (!rate || !channels || fmt == QAudioFormat::Unknown)
- return format;
-
- format.setSampleRate(*rate);
- format.setChannelCount(*channels);
- format.setSampleFormat(fmt);
-
- return format;
-}
-
-/*
- Builds GstCaps for an audio format \a format.
- Returns 0 if the audio format is not valid.
-
- \note Caller must unreference GstCaps.
-*/
-
-QGstMutableCaps QGstUtils::capsForAudioFormat(const QAudioFormat &format)
-{
- if (!format.isValid())
- return {};
-
- auto sampleFormat = format.sampleFormat();
- return gst_caps_new_simple(
- "audio/x-raw",
- "format" , G_TYPE_STRING, audioSampleFormatNames[sampleFormat],
- "rate" , G_TYPE_INT , format.sampleRate(),
- "channels", G_TYPE_INT , format.channelCount(),
- "layout" , G_TYPE_STRING, "interleaved",
- nullptr);
-}
-
-QList<QAudioFormat::SampleFormat> QGValue::getSampleFormats() const
-{
- if (!GST_VALUE_HOLDS_LIST(value))
- return {};
-
- QList<QAudioFormat::SampleFormat> formats;
- guint nFormats = gst_value_list_get_size(value);
- for (guint f = 0; f < nFormats; ++f) {
- QGValue v = gst_value_list_get_value(value, f);
- auto *name = v.toString();
- QAudioFormat::SampleFormat fmt = gstSampleFormatToSampleFormat(name);
- if (fmt == QAudioFormat::Unknown)
- continue;;
- formats.append(fmt);
- }
- return formats;
-}
-
-namespace {
-
-struct VideoFormat
-{
- QVideoFrameFormat::PixelFormat pixelFormat;
- GstVideoFormat gstFormat;
-};
-
-static const VideoFormat qt_videoFormatLookup[] =
-{
- { QVideoFrameFormat::Format_YUV420P, GST_VIDEO_FORMAT_I420 },
- { QVideoFrameFormat::Format_YUV422P, GST_VIDEO_FORMAT_Y42B },
- { QVideoFrameFormat::Format_YV12 , GST_VIDEO_FORMAT_YV12 },
- { QVideoFrameFormat::Format_UYVY , GST_VIDEO_FORMAT_UYVY },
- { QVideoFrameFormat::Format_YUYV , GST_VIDEO_FORMAT_YUY2 },
- { QVideoFrameFormat::Format_NV12 , GST_VIDEO_FORMAT_NV12 },
- { QVideoFrameFormat::Format_NV21 , GST_VIDEO_FORMAT_NV21 },
- { QVideoFrameFormat::Format_AYUV , GST_VIDEO_FORMAT_AYUV },
- { QVideoFrameFormat::Format_Y8 , GST_VIDEO_FORMAT_GRAY8 },
- { QVideoFrameFormat::Format_XRGB8888 , GST_VIDEO_FORMAT_xRGB },
- { QVideoFrameFormat::Format_XBGR8888 , GST_VIDEO_FORMAT_xBGR },
- { QVideoFrameFormat::Format_RGBX8888 , GST_VIDEO_FORMAT_RGBx },
- { QVideoFrameFormat::Format_BGRX8888 , GST_VIDEO_FORMAT_BGRx },
- { QVideoFrameFormat::Format_ARGB8888, GST_VIDEO_FORMAT_ARGB },
- { QVideoFrameFormat::Format_ABGR8888, GST_VIDEO_FORMAT_ABGR },
- { QVideoFrameFormat::Format_RGBA8888, GST_VIDEO_FORMAT_RGBA },
- { QVideoFrameFormat::Format_BGRA8888, GST_VIDEO_FORMAT_BGRA },
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- { QVideoFrameFormat::Format_Y16 , GST_VIDEO_FORMAT_GRAY16_LE },
- { QVideoFrameFormat::Format_P010 , GST_VIDEO_FORMAT_P010_10LE },
-#else
- { QVideoFrameFormat::Format_Y16 , GST_VIDEO_FORMAT_GRAY16_BE },
- { QVideoFrameFormat::Format_P010 , GST_VIDEO_FORMAT_P010_10BE },
-#endif
-};
-
-static int indexOfVideoFormat(QVideoFrameFormat::PixelFormat format)
-{
- for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i)
- if (qt_videoFormatLookup[i].pixelFormat == format)
- return i;
-
- return -1;
-}
-
-static int indexOfVideoFormat(GstVideoFormat format)
-{
- for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i)
- if (qt_videoFormatLookup[i].gstFormat == format)
- return i;
-
- return -1;
-}
-
-}
-
-QVideoFrameFormat QGstCaps::formatForCaps(GstVideoInfo *info) const
-{
- GstVideoInfo vidInfo;
- GstVideoInfo *infoPtr = info ? info : &vidInfo;
-
- if (gst_video_info_from_caps(infoPtr, caps)) {
- int index = indexOfVideoFormat(infoPtr->finfo->format);
-
- if (index != -1) {
- QVideoFrameFormat format(
- QSize(infoPtr->width, infoPtr->height),
- qt_videoFormatLookup[index].pixelFormat);
-
- if (infoPtr->fps_d > 0)
- format.setFrameRate(qreal(infoPtr->fps_n) / infoPtr->fps_d);
-
- return format;
- }
- }
- return QVideoFrameFormat();
-}
-
-void QGstMutableCaps::addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats, const char *modifier)
-{
- GValue list = {};
- g_value_init(&list, GST_TYPE_LIST);
-
- for (QVideoFrameFormat::PixelFormat format : formats) {
- int index = indexOfVideoFormat(format);
- if (index == -1)
- continue;
- GValue item = {};
-
- g_value_init(&item, G_TYPE_STRING);
- g_value_set_string(&item, gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat));
- gst_value_list_append_value(&list, &item);
- g_value_unset(&item);
- }
- QGValue v(&list);
- auto *structure = gst_structure_new("video/x-raw",
- "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1,
- "width" , GST_TYPE_INT_RANGE, 1, INT_MAX,
- "height" , GST_TYPE_INT_RANGE, 1, INT_MAX,
- nullptr);
- gst_structure_set_value(structure, "format", &list);
- gst_caps_append_structure(caps, structure);
- g_value_unset(&list);
-
- if (modifier)
- gst_caps_set_features(caps, size() - 1, gst_caps_features_from_string(modifier));
-}
-
-QGstMutableCaps QGstMutableCaps::fromCameraFormat(const QCameraFormat &format)
-{
- QGstMutableCaps caps;
- caps.create();
-
- QSize size = format.resolution();
- GstStructure *structure = nullptr;
-// int num = 0;
-// int den = 1;
-// if (format.maxFrameRate() > 0)
-// qt_real_to_fraction(1. / format.maxFrameRate(), &num, &den);
-// qDebug() << "fromCameraFormat" << format.maxFrameRate() << num << den;
-
- if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
- structure = gst_structure_new("image/jpeg",
- "width" , G_TYPE_INT, size.width(),
- "height" , G_TYPE_INT, size.height(),
-// "framerate", GST_TYPE_FRACTION, den, num,
- nullptr);
- } else {
- int index = indexOfVideoFormat(format.pixelFormat());
- if (index < 0)
- return QGstMutableCaps();
- auto gstFormat = qt_videoFormatLookup[index].gstFormat;
- structure = gst_structure_new("video/x-raw",
- "format" , G_TYPE_STRING, gst_video_format_to_string(gstFormat),
- "width" , G_TYPE_INT, size.width(),
- "height" , G_TYPE_INT, size.height(),
-// "framerate", GST_TYPE_FRACTION, den, num,
- nullptr);
- }
- gst_caps_append_structure(caps.caps, structure);
- return caps;
-}
-
-void QGstUtils::setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer)
-{
- // GStreamer uses nanoseconds, Qt uses microseconds
- qint64 startTime = GST_BUFFER_TIMESTAMP(buffer);
- if (startTime >= 0) {
- frame->setStartTime(startTime/G_GINT64_CONSTANT (1000));
-
- qint64 duration = GST_BUFFER_DURATION(buffer);
- if (duration >= 0)
- frame->setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000));
- }
-}
-
-QSize QGstStructure::resolution() const
-{
- QSize size;
-
- int w, h;
- if (structure &&
- gst_structure_get_int(structure, "width", &w) &&
- gst_structure_get_int(structure, "height", &h)) {
- size.rwidth() = w;
- size.rheight() = h;
- }
-
- return size;
-}
-
-QVideoFrameFormat::PixelFormat QGstStructure::pixelFormat() const
-{
- QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
-
- if (!structure)
- return pixelFormat;
-
- if (gst_structure_has_name(structure, "video/x-raw")) {
- const gchar *s = gst_structure_get_string(structure, "format");
- if (s) {
- GstVideoFormat format = gst_video_format_from_string(s);
- int index = indexOfVideoFormat(format);
-
- if (index != -1)
- pixelFormat = qt_videoFormatLookup[index].pixelFormat;
- }
- } else if (gst_structure_has_name(structure, "image/jpeg")) {
- pixelFormat = QVideoFrameFormat::Format_Jpeg;
- }
-
- return pixelFormat;
-}
-
-QGRange<float> QGstStructure::frameRateRange() const
-{
- float minRate = 0.;
- float maxRate = 0.;
-
- if (!structure)
- return {0.f, 0.f};
-
- auto extractFraction = [] (const GValue *v) -> float {
- return (float)gst_value_get_fraction_numerator(v)/(float)gst_value_get_fraction_denominator(v);
- };
- auto extractFrameRate = [&] (const GValue *v) {
- auto insert = [&] (float min, float max) {
- if (max > maxRate)
- maxRate = max;
- if (min < minRate)
- minRate = min;
- };
-
- if (GST_VALUE_HOLDS_FRACTION(v)) {
- float rate = extractFraction(v);
- insert(rate, rate);
- } else if (GST_VALUE_HOLDS_FRACTION_RANGE(v)) {
- auto *min = gst_value_get_fraction_range_max(v);
- auto *max = gst_value_get_fraction_range_max(v);
- insert(extractFraction(min), extractFraction(max));
- }
- };
-
- const GValue *gstFrameRates = gst_structure_get_value(structure, "framerate");
- if (gstFrameRates) {
- if (GST_VALUE_HOLDS_LIST(gstFrameRates)) {
- guint nFrameRates = gst_value_list_get_size(gstFrameRates);
- for (guint f = 0; f < nFrameRates; ++f) {
- extractFrameRate(gst_value_list_get_value(gstFrameRates, f));
- }
- } else {
- extractFrameRate(gstFrameRates);
- }
- } else {
- const GValue *min = gst_structure_get_value(structure, "min-framerate");
- const GValue *max = gst_structure_get_value(structure, "max-framerate");
- if (min && max) {
- minRate = extractFraction(min);
- maxRate = extractFraction(max);
- }
- }
-
- return {minRate, maxRate};
-}
-
-GList *qt_gst_video_sinks()
-{
- GList *list = nullptr;
-
- list = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO,
- GST_RANK_MARGINAL);
-
- return list;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstutils_p.h b/src/multimedia/platform/gstreamer/common/qgstutils_p.h
deleted file mode 100644
index a0dc51a56..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstutils_p.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTUTILS_P_H
-#define QGSTUTILS_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 <private/qtmultimediaglobal_p.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmap.h>
-#include <QtCore/qset.h>
-#include <private/qgst_p.h>
-#include <gst/video/video.h>
-#include <qaudioformat.h>
-#include <qcamera.h>
-#include <qvideoframe.h>
-#include <QDebug>
-
-QT_BEGIN_NAMESPACE
-
-class QSize;
-class QVariant;
-class QByteArray;
-class QImage;
-class QVideoFrameFormat;
-
-namespace QGstUtils {
- Q_MULTIMEDIA_EXPORT QAudioFormat audioFormatForSample(GstSample *sample);
- QAudioFormat audioFormatForCaps(QGstCaps caps);
- Q_MULTIMEDIA_EXPORT QGstMutableCaps capsForAudioFormat(const QAudioFormat &format);
-
- void setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer);
-}
-
-Q_MULTIMEDIA_EXPORT GList *qt_gst_video_sinks();
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp b/src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp
deleted file mode 100644
index 878b4d410..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstvideobuffer_p.h"
-#include "qgstreamervideosink_p.h"
-#include "qvideotexturehelper_p.h"
-#include <qpa/qplatformnativeinterface.h>
-#include <qguiapplication.h>
-
-#include <gst/video/video.h>
-#include <gst/video/video-frame.h>
-#include <gst/video/gstvideometa.h>
-#include <gst/pbutils/gstpluginsbaseversion.h>
-
-#include "qgstutils_p.h"
-
-#if QT_CONFIG(gstreamer_gl)
-#include <QtGui/private/qrhi_p.h>
-#include <QtGui/private/qrhigles2_p.h>
-#include <QtGui/qopenglcontext.h>
-#include <QtGui/qopenglfunctions.h>
-#include <QtGui/qopengl.h>
-
-#include <gst/gl/gstglconfig.h>
-#include <gst/gl/gstglmemory.h>
-#include <gst/gl/gstglsyncmeta.h>
-#include <gst/allocators/gstdmabuf.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-// keep things building without drm_fourcc.h
-#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
- ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
-
-#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */
-#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */
-#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
-#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */
-#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */
-#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
-#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
-#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
-#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */
-#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
-#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
-#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
-
-QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, QGstreamerVideoSink *sink,
- const QVideoFrameFormat &frameFormat,
- QGstCaps::MemoryFormat format)
- : QAbstractVideoBuffer((sink && sink->rhi() && format != QGstCaps::CpuMemory) ?
- QVideoFrame::RhiTextureHandle : QVideoFrame::NoHandle, sink ? sink->rhi() : nullptr)
- , memoryFormat(format)
- , m_frameFormat(frameFormat)
- , m_videoInfo(info)
- , m_buffer(buffer)
-{
- gst_buffer_ref(m_buffer);
- if (sink) {
- eglDisplay = sink->eglDisplay();
- eglImageTargetTexture2D = sink->eglImageTargetTexture2D();
- }
-}
-
-QGstVideoBuffer::~QGstVideoBuffer()
-{
- unmap();
-
- gst_buffer_unref(m_buffer);
- if (m_syncBuffer)
- gst_buffer_unref(m_syncBuffer);
-
- if (m_ownTextures && glContext) {
- int planes = 0;
- for (planes = 0; planes < 3; ++planes) {
- if (m_textures[planes] == 0)
- break;
- }
-#if QT_CONFIG(gstreamer_gl)
- if (rhi) {
- rhi->makeThreadLocalNativeContextCurrent();
- QOpenGLFunctions functions(glContext);
- functions.glDeleteTextures(planes, m_textures);
- }
-#endif
- }
-}
-
-
-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)
- | ((mode & QVideoFrame::WriteOnly) ? GST_MAP_WRITE : 0));
-
- MapData mapData;
- if (mode == QVideoFrame::NotMapped || m_mode != QVideoFrame::NotMapped)
- return mapData;
-
- if (m_videoInfo.finfo->n_planes == 0) { // Encoded
- if (gst_buffer_map(m_buffer, &m_frame.map[0], flags)) {
- mapData.nPlanes = 1;
- mapData.bytesPerLine[0] = -1;
- mapData.size[0] = m_frame.map[0].size;
- mapData.data[0] = static_cast<uchar *>(m_frame.map[0].data);
-
- m_mode = mode;
- }
- } else if (gst_video_frame_map(&m_frame, &m_videoInfo, m_buffer, flags)) {
- mapData.nPlanes = GST_VIDEO_FRAME_N_PLANES(&m_frame);
-
- for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES(&m_frame); ++i) {
- mapData.bytesPerLine[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&m_frame, i);
- mapData.data[i] = static_cast<uchar *>(GST_VIDEO_FRAME_PLANE_DATA(&m_frame, i));
- mapData.size[i] = mapData.bytesPerLine[i]*GST_VIDEO_FRAME_COMP_HEIGHT(&m_frame, i);
- }
-
- m_mode = mode;
- }
- return mapData;
-}
-
-void QGstVideoBuffer::unmap()
-{
- if (m_mode != QVideoFrame::NotMapped) {
- if (m_videoInfo.finfo->n_planes == 0)
- gst_buffer_unmap(m_buffer, &m_frame.map[0]);
- else
- gst_video_frame_unmap(&m_frame);
- }
- m_mode = QVideoFrame::NotMapped;
-}
-
-#if QT_CONFIG(gstreamer_gl)
-static int
-fourccFromVideoInfo(const GstVideoInfo * info, int plane)
-{
- GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- const gint rgba_fourcc = DRM_FORMAT_ABGR8888;
- const gint rgb_fourcc = DRM_FORMAT_BGR888;
- const gint rg_fourcc = DRM_FORMAT_GR88;
-#else
- const gint rgba_fourcc = DRM_FORMAT_RGBA8888;
- const gint rgb_fourcc = DRM_FORMAT_RGB888;
- const gint rg_fourcc = DRM_FORMAT_RG88;
-#endif
-
- GST_DEBUG ("Getting DRM fourcc for %s plane %i",
- gst_video_format_to_string (format), plane);
-
- switch (format) {
- case GST_VIDEO_FORMAT_RGB16:
- case GST_VIDEO_FORMAT_BGR16:
- return DRM_FORMAT_RGB565;
-
- case GST_VIDEO_FORMAT_RGB:
- case GST_VIDEO_FORMAT_BGR:
- return rgb_fourcc;
-
- case GST_VIDEO_FORMAT_RGBA:
- case GST_VIDEO_FORMAT_RGBx:
- case GST_VIDEO_FORMAT_BGRA:
- case GST_VIDEO_FORMAT_BGRx:
- case GST_VIDEO_FORMAT_ARGB:
- case GST_VIDEO_FORMAT_xRGB:
- case GST_VIDEO_FORMAT_ABGR:
- case GST_VIDEO_FORMAT_xBGR:
- case GST_VIDEO_FORMAT_AYUV:
-#if GST_CHECK_PLUGINS_BASE_VERSION(1,16,0)
- case GST_VIDEO_FORMAT_VUYA:
-#endif
- return rgba_fourcc;
-
- case GST_VIDEO_FORMAT_GRAY8:
- return DRM_FORMAT_R8;
-
- case GST_VIDEO_FORMAT_YUY2:
- case GST_VIDEO_FORMAT_UYVY:
- case GST_VIDEO_FORMAT_GRAY16_LE:
- case GST_VIDEO_FORMAT_GRAY16_BE:
- return rg_fourcc;
-
- case GST_VIDEO_FORMAT_NV12:
- case GST_VIDEO_FORMAT_NV21:
- return plane == 0 ? DRM_FORMAT_R8 : rg_fourcc;
-
- case GST_VIDEO_FORMAT_I420:
- case GST_VIDEO_FORMAT_YV12:
- case GST_VIDEO_FORMAT_Y41B:
- case GST_VIDEO_FORMAT_Y42B:
- case GST_VIDEO_FORMAT_Y444:
- return DRM_FORMAT_R8;
-
-#if GST_CHECK_PLUGINS_BASE_VERSION(1,16,0)
- case GST_VIDEO_FORMAT_BGR10A2_LE:
- return DRM_FORMAT_BGRA1010102;
-#endif
-
-// case GST_VIDEO_FORMAT_RGB10A2_LE:
-// return DRM_FORMAT_RGBA1010102;
-
- case GST_VIDEO_FORMAT_P010_10LE:
-// case GST_VIDEO_FORMAT_P012_LE:
-// case GST_VIDEO_FORMAT_P016_LE:
- return plane == 0 ? DRM_FORMAT_R16 : DRM_FORMAT_GR1616;
-
- case GST_VIDEO_FORMAT_P010_10BE:
-// case GST_VIDEO_FORMAT_P012_BE:
-// case GST_VIDEO_FORMAT_P016_BE:
- return plane == 0 ? DRM_FORMAT_R16 : DRM_FORMAT_RG1616;
-
- default:
- GST_ERROR ("Unsupported format for DMABuf.");
- return -1;
- }
-}
-#endif
-
-void QGstVideoBuffer::mapTextures()
-{
- if (!rhi)
- return;
-
-#if QT_CONFIG(gstreamer_gl)
- if (memoryFormat == QGstCaps::GLTexture) {
- auto *mem = GST_GL_BASE_MEMORY_CAST(gst_buffer_peek_memory(m_buffer, 0));
- Q_ASSERT(mem);
- if (!gst_video_frame_map(&m_frame, &m_videoInfo, m_buffer, GstMapFlags(GST_MAP_READ|GST_MAP_GL))) {
- qWarning() << "Could not map GL textures";
- } else {
- auto *sync_meta = gst_buffer_get_gl_sync_meta(m_buffer);
-
- if (!sync_meta) {
- m_syncBuffer = gst_buffer_new();
- sync_meta = gst_buffer_add_gl_sync_meta(mem->context, m_syncBuffer);
- }
- gst_gl_sync_meta_set_sync_point (sync_meta, mem->context);
- gst_gl_sync_meta_wait (sync_meta, mem->context);
-
- int nPlanes = m_frame.info.finfo->n_planes;
- for (int i = 0; i < nPlanes; ++i) {
- m_textures[i] = *(guint32 *)m_frame.data[i];
- }
- gst_video_frame_unmap(&m_frame);
- }
- }
-#if GST_GL_HAVE_PLATFORM_EGL
- else if (memoryFormat == QGstCaps::DMABuf) {
- if (m_textures[0])
- return;
- Q_ASSERT(gst_is_dmabuf_memory(gst_buffer_peek_memory(m_buffer, 0)));
- Q_ASSERT(eglDisplay);
- Q_ASSERT(eglImageTargetTexture2D);
-
- auto *nativeHandles = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
- glContext = nativeHandles->context;
- if (!glContext) {
- qWarning() << "no GL context";
- return;
- }
-
- if (!gst_video_frame_map(&m_frame, &m_videoInfo, m_buffer, GstMapFlags(GST_MAP_READ))) {
- qDebug() << "Couldn't map DMA video frame";
- return;
- }
-
- int nPlanes = GST_VIDEO_FRAME_N_PLANES(&m_frame);
-// int width = GST_VIDEO_FRAME_WIDTH(&m_frame);
-// int height = GST_VIDEO_FRAME_HEIGHT(&m_frame);
- Q_ASSERT(GST_VIDEO_FRAME_N_PLANES(&m_frame) == gst_buffer_n_memory(m_buffer));
-
- QOpenGLFunctions functions(glContext);
- functions.glGenTextures(nPlanes, m_textures);
- m_ownTextures = true;
-
-// qDebug() << Qt::hex << "glGenTextures: glerror" << glGetError() << "egl error" << eglGetError();
-// qDebug() << "converting DMA buffer nPlanes=" << nPlanes << m_textures[0] << m_textures[1] << m_textures[2];
-
- for (int i = 0; i < nPlanes; ++i) {
- auto offset = GST_VIDEO_FRAME_PLANE_OFFSET(&m_frame, i);
- auto stride = GST_VIDEO_FRAME_PLANE_STRIDE(&m_frame, i);
- int planeWidth = GST_VIDEO_FRAME_COMP_WIDTH(&m_frame, i);
- int planeHeight = GST_VIDEO_FRAME_COMP_HEIGHT(&m_frame, i);
- auto mem = gst_buffer_peek_memory(m_buffer, i);
- int fd = gst_dmabuf_memory_get_fd(mem);
-
-// qDebug() << " plane" << i << "size" << width << height << "stride" << stride << "offset" << offset << "fd=" << fd;
- // ### do we need to open/close the fd?
- // ### can we convert several planes at once?
- // Get the correct DRM_FORMATs from the texture format in the description
- EGLAttrib const attribute_list[] = {
- EGL_WIDTH, planeWidth,
- EGL_HEIGHT, planeHeight,
- EGL_LINUX_DRM_FOURCC_EXT, fourccFromVideoInfo(&m_videoInfo, i),
- EGL_DMA_BUF_PLANE0_FD_EXT, fd,
- EGL_DMA_BUF_PLANE0_OFFSET_EXT, (EGLAttrib)offset,
- EGL_DMA_BUF_PLANE0_PITCH_EXT, stride,
- EGL_NONE
- };
- EGLImage image = eglCreateImage(eglDisplay,
- EGL_NO_CONTEXT,
- EGL_LINUX_DMA_BUF_EXT,
- nullptr,
- attribute_list);
- if (image == EGL_NO_IMAGE_KHR) {
- qWarning() << "could not create EGL image for plane" << i << Qt::hex << eglGetError();
- }
-// qDebug() << Qt::hex << "eglCreateImage: glerror" << glGetError() << "egl error" << eglGetError();
- functions.glBindTexture(GL_TEXTURE_2D, m_textures[i]);
-// qDebug() << Qt::hex << "bind texture: glerror" << glGetError() << "egl error" << eglGetError();
- auto EGLImageTargetTexture2D = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglImageTargetTexture2D;
- EGLImageTargetTexture2D(GL_TEXTURE_2D, image);
-// qDebug() << Qt::hex << "glerror" << glGetError() << "egl error" << eglGetError();
- eglDestroyImage(eglDisplay, image);
- }
- gst_video_frame_unmap(&m_frame);
- }
-#endif
-#endif
- m_texturesUploaded = true;
-}
-
-quint64 QGstVideoBuffer::textureHandle(int plane) const
-{
- return m_textures[plane];
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h b/src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h
deleted file mode 100644
index bcd60539b..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTVIDEOBUFFER_P_H
-#define QGSTVIDEOBUFFER_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 <private/qtmultimediaglobal_p.h>
-#include <private/qabstractvideobuffer_p.h>
-#include <QtCore/qvariant.h>
-
-#include <private/qgst_p.h>
-#include <gst/video/video.h>
-
-QT_BEGIN_NAMESPACE
-class QVideoFrameFormat;
-class QGstreamerVideoSink;
-class QOpenGLContext;
-
-class Q_MULTIMEDIA_EXPORT QGstVideoBuffer : public QAbstractVideoBuffer
-{
-public:
-
- QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, QGstreamerVideoSink *sink,
- const QVideoFrameFormat &frameFormat, QGstCaps::MemoryFormat format);
- QGstVideoBuffer(GstBuffer *buffer, const QVideoFrameFormat &format, const GstVideoInfo &info)
- : QGstVideoBuffer(buffer, info, nullptr, format, QGstCaps::CpuMemory)
- {}
- ~QGstVideoBuffer();
-
- GstBuffer *buffer() const { return m_buffer; }
- QVideoFrame::MapMode mapMode() const override;
-
- MapData map(QVideoFrame::MapMode mode) override;
- void unmap() override;
-
- void mapTextures() override;
- quint64 textureHandle(int plane) const override;
-private:
- QGstCaps::MemoryFormat memoryFormat = QGstCaps::CpuMemory;
- QVideoFrameFormat m_frameFormat;
- mutable GstVideoInfo m_videoInfo;
- mutable GstVideoFrame m_frame;
- GstBuffer *m_buffer = nullptr;
- GstBuffer *m_syncBuffer = nullptr;
- QVideoFrame::MapMode m_mode = QVideoFrame::NotMapped;
- QOpenGLContext *glContext = nullptr;
- Qt::HANDLE eglDisplay = nullptr;
- QFunctionPointer eglImageTargetTexture2D = nullptr;
- uint m_textures[3] = {};
- bool m_texturesUploaded = false;
- bool m_ownTextures = false;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp b/src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp
deleted file mode 100644
index a74fa1b4b..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp
+++ /dev/null
@@ -1,601 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <qvideoframe.h>
-#include <qvideosink.h>
-#include <QDebug>
-#include <QMap>
-#include <QThread>
-#include <QEvent>
-#include <QCoreApplication>
-
-#include <private/qfactoryloader_p.h>
-#include "qgstvideobuffer_p.h"
-#include "qgstreamervideosink_p.h"
-
-#include "qgstvideorenderersink_p.h"
-
-#include <gst/video/video.h>
-#include <gst/video/gstvideometa.h>
-
-#include "qgstutils_p.h"
-
-#include <QtGui/private/qrhi_p.h>
-#if QT_CONFIG(gstreamer_gl)
-#include <gst/gl/gl.h>
-#endif // #if QT_CONFIG(gstreamer_gl)
-
-// DMA support
-#include <gst/allocators/gstdmabuf.h>
-
-//#define DEBUG_VIDEO_SURFACE_SINK
-
-QT_BEGIN_NAMESPACE
-
-QGstVideoRenderer::QGstVideoRenderer(QGstreamerVideoSink *sink)
- : m_sink(sink)
-{
- createSurfaceCaps();
-}
-
-QGstVideoRenderer::~QGstVideoRenderer()
-{
-}
-
-void QGstVideoRenderer::createSurfaceCaps()
-{
- QRhi *rhi = m_sink->rhi();
- Q_UNUSED(rhi);
-
- QGstMutableCaps caps;
- caps.create();
-
- // All the formats that both we and gstreamer support
- auto formats = QList<QVideoFrameFormat::PixelFormat>()
- << QVideoFrameFormat::Format_YUV420P
- << QVideoFrameFormat::Format_YUV422P
- << QVideoFrameFormat::Format_YV12
- << QVideoFrameFormat::Format_UYVY
- << QVideoFrameFormat::Format_YUYV
- << QVideoFrameFormat::Format_NV12
- << QVideoFrameFormat::Format_NV21
- << QVideoFrameFormat::Format_AYUV
- << QVideoFrameFormat::Format_P010
- << QVideoFrameFormat::Format_XRGB8888
- << QVideoFrameFormat::Format_XBGR8888
- << QVideoFrameFormat::Format_RGBX8888
- << QVideoFrameFormat::Format_BGRX8888
- << QVideoFrameFormat::Format_ARGB8888
- << QVideoFrameFormat::Format_ABGR8888
- << QVideoFrameFormat::Format_RGBA8888
- << QVideoFrameFormat::Format_BGRA8888
- << QVideoFrameFormat::Format_Y8
- << QVideoFrameFormat::Format_Y16
- ;
-#if QT_CONFIG(gstreamer_gl)
- if (rhi && rhi->backend() == QRhi::OpenGLES2) {
- caps.addPixelFormats(formats, GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
- if (m_sink->eglDisplay() && m_sink->eglImageTargetTexture2D()) {
- // We currently do not handle planar DMA buffers, as it's somewhat unclear how to
- // convert the planar EGLImage into something we can use from OpenGL
- auto singlePlaneFormats = QList<QVideoFrameFormat::PixelFormat>()
- << QVideoFrameFormat::Format_UYVY
- << QVideoFrameFormat::Format_YUYV
- << QVideoFrameFormat::Format_AYUV
- << QVideoFrameFormat::Format_XRGB8888
- << QVideoFrameFormat::Format_XBGR8888
- << QVideoFrameFormat::Format_RGBX8888
- << QVideoFrameFormat::Format_BGRX8888
- << QVideoFrameFormat::Format_ARGB8888
- << QVideoFrameFormat::Format_ABGR8888
- << QVideoFrameFormat::Format_RGBA8888
- << QVideoFrameFormat::Format_BGRA8888
- << QVideoFrameFormat::Format_Y8
- << QVideoFrameFormat::Format_Y16
- ;
- caps.addPixelFormats(singlePlaneFormats, GST_CAPS_FEATURE_MEMORY_DMABUF);
- }
- }
-#endif
- caps.addPixelFormats(formats);
-
- m_surfaceCaps = caps;
-}
-
-QGstMutableCaps QGstVideoRenderer::caps()
-{
- QMutexLocker locker(&m_mutex);
-
- return m_surfaceCaps;
-}
-
-bool QGstVideoRenderer::start(GstCaps *caps)
-{
-// qDebug() << "QGstVideoRenderer::start" << QGstCaps(caps).toString();
- QMutexLocker locker(&m_mutex);
-
- if (m_active) {
- m_flush = true;
- m_stop = true;
- }
-
- m_startCaps = QGstMutableCaps(caps, QGstMutableCaps::NeedsRef);
-
- /*
- 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 = {};
- }
-
- return m_active;
-}
-
-void QGstVideoRenderer::stop()
-{
- QMutexLocker locker(&m_mutex);
-
- if (!m_active)
- 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;
-}
-
-void QGstVideoRenderer::flush()
-{
- QMutexLocker locker(&m_mutex);
-
- m_flush = true;
- m_renderBuffer = nullptr;
- m_renderCondition.wakeAll();
-
- notify();
-}
-
-GstFlowReturn QGstVideoRenderer::render(GstBuffer *buffer)
-{
- QMutexLocker locker(&m_mutex);
-
- m_renderReturn = GST_FLOW_OK;
- m_renderBuffer = buffer;
-
- waitForAsyncEvent(&locker, &m_renderCondition, 300);
-
- m_renderBuffer = nullptr;
-
- return m_renderReturn;
-}
-
-bool QGstVideoRenderer::query(GstQuery *query)
-{
-#if QT_CONFIG(gstreamer_gl)
- if (GST_QUERY_TYPE(query) == GST_QUERY_CONTEXT) {
- const gchar *type;
- gst_query_parse_context_type(query, &type);
-
- if (strcmp(type, "gst.gl.local_context") != 0)
- return false;
-
- auto *gstGlContext = m_sink->gstGlLocalContext();
- if (!gstGlContext)
- return false;
-
- gst_query_set_context(query, gstGlContext);
-
- return true;
- }
-#else
- Q_UNUSED(query);
-#endif
- return false;
-}
-
-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;
- }
- } 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 = nullptr;
-
- if (m_sink) {
- locker->unlock();
-
- m_flushed = true;
- m_format = startCaps.formatForCaps(&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) {
- GstBuffer *buffer = m_renderBuffer;
- m_renderBuffer = nullptr;
- m_renderReturn = GST_FLOW_ERROR;
-
- if (m_active && m_sink) {
- gst_buffer_ref(buffer);
-
- locker->unlock();
-
- m_flushed = false;
-
- auto 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) {
-#ifdef DEBUG_VIDEO_SURFACE_SINK
- qDebug() << Q_FUNC_INFO << " Update viewport on Metadata: [" << meta->height << "x" << meta->width << " | " << meta->x << "x" << meta->y << "]";
-#endif \
- //Update viewport if data is not the same
- m_format.setViewport(vp);
- }
- }
-
- QGstVideoBuffer *videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo, m_sink, m_format, memoryFormat);
- QVideoFrame frame(videoBuffer, m_format);
- QGstUtils::setFrameTimeStamps(&frame, buffer);
-
- m_sink->setVideoFrame(frame);
-
- gst_buffer_unref(buffer);
-
- 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 *sink_parent_class;
-static thread_local QGstreamerVideoSink *current_sink;
-
-#define VO_SINK(s) QGstVideoRendererSink *sink(reinterpret_cast<QGstVideoRendererSink *>(s))
-
-QGstVideoRendererSink *QGstVideoRendererSink::createSink(QGstreamerVideoSink *sink)
-{
- setSink(sink);
- 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;
-}
-
-void QGstVideoRendererSink::setSink(QGstreamerVideoSink *sink)
-{
- current_sink = sink;
- get_type();
-}
-
-GType QGstVideoRendererSink::get_type()
-{
- static GType type = 0;
-
- if (type == 0) {
- static const GTypeInfo info =
- {
- sizeof(QGstVideoRendererSinkClass), // class_size
- base_init, // base_init
- nullptr, // base_finalize
- class_init, // class_init
- nullptr, // class_finalize
- nullptr, // class_data
- sizeof(QGstVideoRendererSink), // instance_size
- 0, // n_preallocs
- instance_init, // instance_init
- nullptr // value_table
- };
-
- type = g_type_register_static(
- GST_TYPE_VIDEO_SINK, "QGstVideoRendererSink", &info, GTypeFlags(0));
-
- // Register the sink type to be used in custom piplines.
- // When surface is ready the sink can be used.
- gst_element_register(nullptr, "qtvideosink", GST_RANK_PRIMARY, type);
- }
-
- return type;
-}
-
-void QGstVideoRendererSink::class_init(gpointer g_class, gpointer class_data)
-{
- Q_UNUSED(class_data);
-
- sink_parent_class = reinterpret_cast<GstVideoSinkClass *>(g_type_class_peek_parent(g_class));
-
- GstVideoSinkClass *video_sink_class = reinterpret_cast<GstVideoSinkClass *>(g_class);
- video_sink_class->show_frame = QGstVideoRendererSink::show_frame;
-
- GstBaseSinkClass *base_sink_class = reinterpret_cast<GstBaseSinkClass *>(g_class);
- base_sink_class->get_caps = QGstVideoRendererSink::get_caps;
- base_sink_class->set_caps = QGstVideoRendererSink::set_caps;
- base_sink_class->propose_allocation = QGstVideoRendererSink::propose_allocation;
- base_sink_class->stop = QGstVideoRendererSink::stop;
- base_sink_class->unlock = QGstVideoRendererSink::unlock;
- base_sink_class->query = QGstVideoRendererSink::query;
-
- GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class);
- element_class->change_state = QGstVideoRendererSink::change_state;
- gst_element_class_set_metadata(element_class,
- "Qt built-in video renderer sink",
- "Sink/Video",
- "Qt default built-in video renderer sink",
- "The Qt Company");
-
- GObjectClass *object_class = reinterpret_cast<GObjectClass *>(g_class);
- object_class->finalize = QGstVideoRendererSink::finalize;
-}
-
-void QGstVideoRendererSink::base_init(gpointer g_class)
-{
- static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE(
- "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS(
- "video/x-raw, "
- "framerate = (fraction) [ 0, MAX ], "
- "width = (int) [ 1, MAX ], "
- "height = (int) [ 1, MAX ]"));
-
- gst_element_class_add_pad_template(
- GST_ELEMENT_CLASS(g_class), gst_static_pad_template_get(&sink_pad_template));
-}
-
-void QGstVideoRendererSink::instance_init(GTypeInstance *instance, gpointer g_class)
-{
- Q_UNUSED(g_class);
- VO_SINK(instance);
-
- Q_ASSERT(current_sink);
-
- sink->renderer = new QGstVideoRenderer(current_sink);
- sink->renderer->moveToThread(current_sink->thread());
- current_sink = nullptr;
-}
-
-void QGstVideoRendererSink::finalize(GObject *object)
-{
- VO_SINK(object);
-
- delete sink->renderer;
-
- // Chain up
- G_OBJECT_CLASS(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(sink_parent_class)->change_state(element, transition);
-}
-
-GstCaps *QGstVideoRendererSink::get_caps(GstBaseSink *base, GstCaps *filter)
-{
- VO_SINK(base);
-
- QGstMutableCaps caps = sink->renderer->caps();
- if (filter)
- caps = gst_caps_intersect(caps.get(), filter);
-
- gst_caps_ref(caps.get());
- return caps.get();
-}
-
-gboolean QGstVideoRendererSink::set_caps(GstBaseSink *base, GstCaps *caps)
-{
- VO_SINK(base);
-
-#ifdef DEBUG_VIDEO_SURFACE_SINK
- qDebug() << "set_caps:";
- qDebug() << caps;
-#endif
-
- if (!caps) {
- sink->renderer->stop();
-
- return TRUE;
- } else if (sink->renderer->start(caps)) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-gboolean QGstVideoRendererSink::propose_allocation(GstBaseSink *base, GstQuery *query)
-{
- VO_SINK(base);
- return sink->renderer->proposeAllocation(query);
-}
-
-gboolean QGstVideoRendererSink::stop(GstBaseSink *base)
-{
- VO_SINK(base);
- sink->renderer->stop();
- return TRUE;
-}
-
-gboolean QGstVideoRendererSink::unlock(GstBaseSink *base)
-{
- VO_SINK(base);
- sink->renderer->unlock();
- return TRUE;
-}
-
-GstFlowReturn QGstVideoRendererSink::show_frame(GstVideoSink *base, GstBuffer *buffer)
-{
- VO_SINK(base);
- return sink->renderer->render(buffer);
-}
-
-gboolean QGstVideoRendererSink::query(GstBaseSink *base, GstQuery *query)
-{
- VO_SINK(base);
- if (sink->renderer->query(query))
- return TRUE;
-
- return GST_BASE_SINK_CLASS(sink_parent_class)->query(base, query);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h b/src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h
deleted file mode 100644
index 9cbd6b5b2..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTVIDEORENDERERSINK_P_H
-#define QGSTVIDEORENDERERSINK_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/qtmultimediaglobal_p.h>
-#include <gst/video/gstvideosink.h>
-#include <gst/video/video.h>
-
-#include <QtCore/qlist.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qqueue.h>
-#include <QtCore/qpointer.h>
-#include <QtCore/qwaitcondition.h>
-#include <qvideoframeformat.h>
-#include <qvideoframe.h>
-#include <private/qgstvideobuffer_p.h>
-#include <private/qgst_p.h>
-
-QT_BEGIN_NAMESPACE
-class QVideoSink;
-
-class QGstVideoRenderer : public QObject
-{
- Q_OBJECT
-public:
- QGstVideoRenderer(QGstreamerVideoSink *sink);
- ~QGstVideoRenderer();
-
- QGstMutableCaps caps();
-
- bool start(GstCaps *caps);
- void stop();
- void unlock();
- bool proposeAllocation(GstQuery *query);
-
- void flush();
-
- GstFlowReturn render(GstBuffer *buffer);
-
- bool event(QEvent *event) override;
- bool query(GstQuery *query);
-
-private slots:
- bool handleEvent(QMutexLocker<QMutex> *locker);
-
-private:
- void notify();
- bool waitForAsyncEvent(QMutexLocker<QMutex> *locker, QWaitCondition *condition, unsigned long time);
- void createSurfaceCaps();
-
- 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;
-
- QGstMutableCaps m_surfaceCaps;
-
- QGstMutableCaps m_startCaps;
- GstBuffer *m_renderBuffer = nullptr;
-
- bool m_notified = false;
- bool m_stop = false;
- bool m_flush = false;
-
- // --- only accessed from one thread
- QVideoFrameFormat m_format;
- GstVideoInfo m_videoInfo;
- bool m_flushed = true;
- QGstCaps::MemoryFormat memoryFormat = QGstCaps::CpuMemory;
-};
-
-class Q_MULTIMEDIA_EXPORT QGstVideoRendererSink
-{
-public:
- GstVideoSink parent;
-
- static QGstVideoRendererSink *createSink(QGstreamerVideoSink *surface);
- static void setSink(QGstreamerVideoSink *surface);
-
-private:
- static GType get_type();
- static void class_init(gpointer g_class, gpointer class_data);
- static void base_init(gpointer g_class);
- static void instance_init(GTypeInstance *instance, gpointer g_class);
-
- 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);
- static gboolean set_caps(GstBaseSink *sink, GstCaps *caps);
-
- static gboolean propose_allocation(GstBaseSink *sink, GstQuery *query);
-
- static gboolean stop(GstBaseSink *sink);
-
- static gboolean unlock(GstBaseSink *sink);
-
- static GstFlowReturn show_frame(GstVideoSink *sink, GstBuffer *buffer);
- static gboolean query(GstBaseSink *element, GstQuery *query);
-
-private:
- QGstVideoRenderer *renderer = nullptr;
-};
-
-
-class QGstVideoRendererSinkClass
-{
-public:
- GstVideoSinkClass parent_class;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera.cpp
deleted file mode 100644
index 1ee0244ef..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera.cpp
+++ /dev/null
@@ -1,738 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <qcameradevice.h>
-
-#include "qgstreamercamera_p.h"
-#include "qgstreamerimagecapture_p.h"
-#include <private/qgstreamermediadevices_p.h>
-#include <private/qgstreamerintegration_p.h>
-#include <qmediacapturesession.h>
-
-#if QT_CONFIG(linux_v4l)
-#include <linux/videodev2.h>
-#include <private/qcore_unix_p.h>
-#endif
-
-#include <QtCore/qdebug.h>
-
-QGstreamerCamera::QGstreamerCamera(QCamera *camera)
- : QPlatformCamera(camera)
-{
- gstCamera = QGstElement("videotestsrc");
- gstCapsFilter = QGstElement("capsfilter", "videoCapsFilter");
- gstDecode = QGstElement("identity");
- gstVideoConvert = QGstElement("videoconvert", "videoConvert");
- gstVideoScale = QGstElement("videoscale", "videoScale");
- gstCameraBin = QGstBin("camerabin");
- gstCameraBin.add(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
- gstCamera.link(gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
- gstCameraBin.addGhostPad(gstVideoScale, "src");
-}
-
-QGstreamerCamera::~QGstreamerCamera()
-{
-#if QT_CONFIG(linux_v4l)
- if (v4l2FileDescriptor >= 0)
- qt_safe_close(v4l2FileDescriptor);
- v4l2FileDescriptor = -1;
-#endif
- gstCameraBin.setStateSync(GST_STATE_NULL);
-}
-
-bool QGstreamerCamera::isActive() const
-{
- return m_active;
-}
-
-void QGstreamerCamera::setActive(bool active)
-{
- if (m_active == active)
- return;
- if (m_cameraDevice.isNull() && active)
- return;
-
- m_active = active;
-
- emit activeChanged(active);
-}
-
-void QGstreamerCamera::setCamera(const QCameraDevice &camera)
-{
- if (m_cameraDevice == camera)
- return;
- qDebug() << "setCamera" << camera;
-
- m_cameraDevice = camera;
-
- QGstElement gstNewCamera;
- if (camera.isNull()) {
- gstNewCamera = QGstElement("videotestsrc");
- } else {
- auto *devices = static_cast<QGstreamerMediaDevices *>(QGstreamerIntegration::instance()->devices());
- auto *device = devices->videoDevice(camera.id());
- gstNewCamera = gst_device_create_element(device, "camerasrc");
- QGstStructure properties = gst_device_get_properties(device);
- if (properties.name() == "v4l2deviceprovider")
- m_v4l2Device = QString::fromUtf8(properties["device.path"].toString());
- }
-
- QCameraFormat f = findBestCameraFormat(camera);
- auto caps = QGstMutableCaps::fromCameraFormat(f);
- auto gstNewDecode = QGstElement(f.pixelFormat() == QVideoFrameFormat::Format_Jpeg ? "jpegdec" : "identity");
-
- gstCamera.setStateSync(GST_STATE_NULL);
- gstDecode.setStateSync(GST_STATE_NULL);
-
- gstCamera.unlink(gstCapsFilter);
- gstCapsFilter.unlink(gstDecode);
- gstDecode.unlink(gstVideoConvert);
-
- gstCameraBin.remove(gstCamera);
- gstCameraBin.remove(gstDecode);
-
- gstCapsFilter.set("caps", caps);
-
- gstCameraBin.add(gstNewCamera, gstNewDecode);
-
- gstNewDecode.link(gstVideoConvert);
- gstCapsFilter.link(gstNewDecode);
-
- if (!gstNewCamera.link(gstCapsFilter))
- qWarning() << "linking camera failed" << gstCamera.name() << caps.toString();
-
- // Start sending frames once pipeline is linked
- // FIXME: put camera to READY state before linking to decoder as in the NULL state it does not know its true caps
- gstCapsFilter.syncStateWithParent();
- gstNewDecode.syncStateWithParent();
- gstNewCamera.syncStateWithParent();
-
- gstCamera = gstNewCamera;
- gstDecode = gstNewDecode;
-
- updateCameraProperties();
-}
-
-bool QGstreamerCamera::setCameraFormat(const QCameraFormat &format)
-{
- if (!format.isNull() && !m_cameraDevice.videoFormats().contains(format))
- return false;
-
- qDebug() << "Set camera format";
-
- QCameraFormat f = format;
- if (f.isNull())
- f = findBestCameraFormat(m_cameraDevice);
-
- auto caps = QGstMutableCaps::fromCameraFormat(f);
-
- auto newGstDecode = QGstElement(f.pixelFormat() == QVideoFrameFormat::Format_Jpeg ? "jpegdec" : "identity");
- gstCameraBin.add(newGstDecode);
- newGstDecode.syncStateWithParent();
-
- gstCamera.staticPad("src").doInIdleProbe([&](){
- gstCamera.unlink(gstCapsFilter);
- gstCapsFilter.unlink(gstDecode);
- gstDecode.unlink(gstVideoConvert);
-
- gstCapsFilter.set("caps", caps);
-
- newGstDecode.link(gstVideoConvert);
- gstCapsFilter.link(newGstDecode);
- if (!gstCamera.link(gstCapsFilter))
- qWarning() << "linking filtered camera to decoder failed" << gstCamera.name() << caps.toString();
- });
-
- gstDecode.setStateSync(GST_STATE_NULL);
- gstCameraBin.remove(gstDecode);
-
- gstDecode = newGstDecode;
-
- return true;
-}
-
-void QGstreamerCamera::updateCameraProperties()
-{
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera()) {
- initV4L2Controls();
- return;
- }
-#endif
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography())
- gst_photography_set_white_balance_mode(p, GST_PHOTOGRAPHY_WB_MODE_AUTO);
- QCamera::Features f = QCamera::Feature::ColorTemperature | QCamera::Feature::ExposureCompensation |
- QCamera::Feature::IsoSensitivity | QCamera::Feature::ManualExposureTime;
- supportedFeaturesChanged(f);
-#endif
-
-}
-
-#if QT_CONFIG(gstreamer_photography)
-GstPhotography *QGstreamerCamera::photography() const
-{
- if (!gstCamera.isNull() && GST_IS_PHOTOGRAPHY(gstCamera.element()))
- return GST_PHOTOGRAPHY(gstCamera.element());
- return nullptr;
-}
-#endif
-
-void QGstreamerCamera::setFocusMode(QCamera::FocusMode mode)
-{
- if (mode == focusMode())
- return;
-
-#if QT_CONFIG(gstreamer_photography)
- auto p = photography();
- if (p) {
- GstPhotographyFocusMode photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_NORMAL;
-
- switch (mode) {
- case QCamera::FocusModeAutoNear:
- photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_MACRO;
- break;
- case QCamera::FocusModeAutoFar:
- // not quite, but hey :)
- Q_FALLTHROUGH();
- case QCamera::FocusModeHyperfocal:
- photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_HYPERFOCAL;
- break;
- case QCamera::FocusModeInfinity:
- photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_INFINITY;
- break;
- case QCamera::FocusModeManual:
- photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_MANUAL;
- break;
- default: // QCamera::FocusModeAuto:
- break;
- }
-
- if (gst_photography_set_focus_mode(p, photographyMode))
- focusModeChanged(mode);
- }
-#endif
-}
-
-bool QGstreamerCamera::isFocusModeSupported(QCamera::FocusMode mode) const
-{
-#if QT_CONFIG(gstreamer_photography)
- if (photography())
- return true;
-#endif
- return mode == QCamera::FocusModeAuto;
-}
-
-void QGstreamerCamera::setFlashMode(QCamera::FlashMode mode)
-{
- Q_UNUSED(mode);
-
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- GstPhotographyFlashMode flashMode;
- gst_photography_get_flash_mode(p, &flashMode);
-
- switch (mode) {
- case QCamera::FlashAuto:
- flashMode = GST_PHOTOGRAPHY_FLASH_MODE_AUTO;
- break;
- case QCamera::FlashOff:
- flashMode = GST_PHOTOGRAPHY_FLASH_MODE_OFF;
- break;
- case QCamera::FlashOn:
- flashMode = GST_PHOTOGRAPHY_FLASH_MODE_ON;
- break;
- }
-
- if (gst_photography_set_flash_mode(p, flashMode))
- flashModeChanged(mode);
- }
-#endif
-}
-
-bool QGstreamerCamera::isFlashModeSupported(QCamera::FlashMode mode) const
-{
-#if QT_CONFIG(gstreamer_photography)
- if (photography())
- return true;
-#endif
-
- return mode == QCamera::FlashAuto;
-}
-
-bool QGstreamerCamera::isFlashReady() const
-{
-#if QT_CONFIG(gstreamer_photography)
- if (photography())
- return true;
-#endif
-
- return false;
-}
-
-void QGstreamerCamera::setExposureMode(QCamera::ExposureMode mode)
-{
- Q_UNUSED(mode);
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera() && v4l2AutoExposureSupported && v4l2ManualExposureSupported) {
- if (mode != QCamera::ExposureAuto && mode != QCamera::ExposureManual)
- return;
- int value = QCamera::ExposureAuto ? V4L2_EXPOSURE_AUTO : V4L2_EXPOSURE_MANUAL;
- setV4L2Parameter(V4L2_CID_EXPOSURE_AUTO, value);
- exposureModeChanged(mode);
- return;
- }
-#endif
-
-#if QT_CONFIG(gstreamer_photography)
- auto *p = photography();
- if (!p)
- return;
-
- GstPhotographySceneMode sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
-
- switch (mode) {
- case QCamera::ExposureManual:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_MANUAL;
- break;
- case QCamera::ExposurePortrait:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT;
- break;
- case QCamera::ExposureSports:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SPORT;
- break;
- case QCamera::ExposureNight:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT;
- break;
- case QCamera::ExposureAuto:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
- break;
- case QCamera::ExposureLandscape:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE;
- break;
- case QCamera::ExposureSnow:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SNOW;
- break;
- case QCamera::ExposureBeach:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_BEACH;
- break;
- case QCamera::ExposureAction:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_ACTION;
- break;
- case QCamera::ExposureNightPortrait:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT_PORTRAIT;
- break;
- case QCamera::ExposureTheatre:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_THEATRE;
- break;
- case QCamera::ExposureSunset:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SUNSET;
- break;
- case QCamera::ExposureSteadyPhoto:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_STEADY_PHOTO;
- break;
- case QCamera::ExposureFireworks:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_FIREWORKS;
- break;
- case QCamera::ExposureParty:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_PARTY;
- break;
- case QCamera::ExposureCandlelight:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_CANDLELIGHT;
- break;
- case QCamera::ExposureBarcode:
- sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_BARCODE;
- break;
- default:
- return;
- }
-
- if (gst_photography_set_scene_mode(p, sceneMode))
- exposureModeChanged(mode);
-#endif
-}
-
-bool QGstreamerCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
-{
- if (mode == QCamera::ExposureAuto)
- return true;
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera() && v4l2ManualExposureSupported && v4l2AutoExposureSupported)
- return mode == QCamera::ExposureManual;
-#endif
-#if QT_CONFIG(gstreamer_photography)
- if (photography())
- return true;
-#endif
-
- return false;
-}
-
-void QGstreamerCamera::setExposureCompensation(float compensation)
-{
- Q_UNUSED(compensation);
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera() && (v4l2MinExposureAdjustment != 0 || v4l2MaxExposureAdjustment != 0)) {
- int value = qBound(v4l2MinExposureAdjustment, (int)(compensation*1000), v4l2MaxExposureAdjustment);
- setV4L2Parameter(V4L2_CID_AUTO_EXPOSURE_BIAS, value);
- exposureCompensationChanged(value/1000.);
- return;
- }
-#endif
-
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- if (gst_photography_set_ev_compensation(p, compensation))
- exposureCompensationChanged(compensation);
- }
-#endif
-}
-
-void QGstreamerCamera::setManualIsoSensitivity(int iso)
-{
- Q_UNUSED(iso);
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera()) {
- if (!(supportedFeatures() & QCamera::Feature::IsoSensitivity))
- return;
- setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY_AUTO, iso <= 0 ? V4L2_ISO_SENSITIVITY_AUTO : V4L2_ISO_SENSITIVITY_MANUAL);
- if (iso > 0) {
- iso = qBound(minIso(), iso, maxIso());
- setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY, iso);
- }
- return;
- }
-#endif
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- if (gst_photography_set_iso_speed(p, iso))
- isoSensitivityChanged(iso);
- }
-#endif
-}
-
-int QGstreamerCamera::isoSensitivity() const
-{
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera()) {
- if (!(supportedFeatures() & QCamera::Feature::IsoSensitivity))
- return -1;
- return getV4L2Parameter(V4L2_CID_ISO_SENSITIVITY);
- }
-#endif
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- guint speed = 0;
- if (gst_photography_get_iso_speed(p, &speed))
- return speed;
- }
-#endif
- return 100;
-}
-
-void QGstreamerCamera::setManualExposureTime(float secs)
-{
- Q_UNUSED(secs);
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera() && v4l2ManualExposureSupported && v4l2AutoExposureSupported) {
- int exposure = qBound(v4l2MinExposure, qRound(secs*10000.), v4l2MaxExposure);
- setV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE, exposure);
- exposureTimeChanged(exposure/10000.);
- return;
- }
-#endif
-
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- if (gst_photography_set_exposure(p, guint(secs*1000000)))
- exposureTimeChanged(secs);
- }
-#endif
-}
-
-float QGstreamerCamera::exposureTime() const
-{
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera()) {
- return getV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE)/10000.;
- }
-#endif
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- guint32 exposure = 0;
- if (gst_photography_get_exposure(p, &exposure))
- return exposure/1000000.;
- }
-#endif
- return -1;
-}
-
-bool QGstreamerCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
-{
- if (mode == QCamera::WhiteBalanceAuto)
- return true;
-
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera()) {
- if (v4l2AutoWhiteBalanceSupported && v4l2ColorTemperatureSupported)
- return true;
- }
-#endif
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- Q_UNUSED(p);
- switch (mode) {
- case QCamera::WhiteBalanceAuto:
- case QCamera::WhiteBalanceSunlight:
- case QCamera::WhiteBalanceCloudy:
- case QCamera::WhiteBalanceShade:
- case QCamera::WhiteBalanceSunset:
- case QCamera::WhiteBalanceTungsten:
- case QCamera::WhiteBalanceFluorescent:
- return true;
- case QCamera::WhiteBalanceManual: {
-#if GST_CHECK_VERSION(1, 18, 0)
- GstPhotographyInterface *iface = GST_PHOTOGRAPHY_GET_INTERFACE(p);
- if (iface->set_color_temperature && iface->get_color_temperature)
- return true;
-#endif
- break;
- }
- default:
- break;
- }
- }
-#endif
-
- return mode == QCamera::WhiteBalanceAuto;
-}
-
-void QGstreamerCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
-{
- Q_ASSERT(isWhiteBalanceModeSupported(mode));
-
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera()) {
- int temperature = colorTemperatureForWhiteBalance(mode);
- int t = setV4L2ColorTemperature(temperature);
- if (t == 0)
- mode = QCamera::WhiteBalanceAuto;
- whiteBalanceModeChanged(mode);
- return;
- }
-#endif
-
-#if QT_CONFIG(gstreamer_photography)
- if (auto *p = photography()) {
- GstPhotographyWhiteBalanceMode gstMode = GST_PHOTOGRAPHY_WB_MODE_AUTO;
- switch (mode) {
- case QCamera::WhiteBalanceSunlight:
- gstMode = GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT;
- break;
- case QCamera::WhiteBalanceCloudy:
- gstMode = GST_PHOTOGRAPHY_WB_MODE_CLOUDY;
- break;
- case QCamera::WhiteBalanceShade:
- gstMode = GST_PHOTOGRAPHY_WB_MODE_SHADE;
- break;
- case QCamera::WhiteBalanceSunset:
- gstMode = GST_PHOTOGRAPHY_WB_MODE_SUNSET;
- break;
- case QCamera::WhiteBalanceTungsten:
- gstMode = GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN;
- break;
- case QCamera::WhiteBalanceFluorescent:
- gstMode = GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT;
- break;
- case QCamera::WhiteBalanceAuto:
- default:
- break;
- }
- if (gst_photography_set_white_balance_mode(p, gstMode)) {
- whiteBalanceModeChanged(mode);
- return;
- }
- }
-#endif
-}
-
-void QGstreamerCamera::setColorTemperature(int temperature)
-{
- if (temperature == 0) {
- setWhiteBalanceMode(QCamera::WhiteBalanceAuto);
- return;
- }
-
- Q_ASSERT(isWhiteBalanceModeSupported(QCamera::WhiteBalanceManual));
-
-#if QT_CONFIG(linux_v4l)
- if (isV4L2Camera()) {
- int t = setV4L2ColorTemperature(temperature);
- if (t)
- colorTemperatureChanged(t);
- return;
- }
-#endif
-
-#if QT_CONFIG(gstreamer_photography) && GST_CHECK_VERSION(1, 18, 0)
- if (auto *p = photography()) {
- GstPhotographyInterface *iface = GST_PHOTOGRAPHY_GET_INTERFACE(p);
- Q_ASSERT(iface->set_color_temperature);
- iface->set_color_temperature(p, temperature);
- return;
- }
-#endif
-}
-
-#if QT_CONFIG(linux_v4l)
-void QGstreamerCamera::initV4L2Controls()
-{
- v4l2AutoWhiteBalanceSupported = false;
- v4l2ColorTemperatureSupported = false;
- QCamera::Features features;
-
-
- const QString deviceName = v4l2Device();
- Q_ASSERT(!deviceName.isEmpty());
-
- v4l2FileDescriptor = qt_safe_open(deviceName.toLocal8Bit().constData(), O_RDONLY);
- if (v4l2FileDescriptor == -1) {
- qWarning() << "Unable to open the camera" << deviceName
- << "for read to query the parameter info:" << qt_error_string(errno);
- return;
- }
-
- struct v4l2_queryctrl queryControl;
- ::memset(&queryControl, 0, sizeof(queryControl));
- queryControl.id = V4L2_CID_AUTO_WHITE_BALANCE;
-
- if (::ioctl(v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
- v4l2AutoWhiteBalanceSupported = true;
- setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE, true);
- }
-
- ::memset(&queryControl, 0, sizeof(queryControl));
- queryControl.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE;
- if (::ioctl(v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
- v4l2MinColorTemp = queryControl.minimum;
- v4l2MaxColorTemp = queryControl.maximum;
- v4l2ColorTemperatureSupported = true;
- features |= QCamera::Feature::ColorTemperature;
- }
-
- ::memset(&queryControl, 0, sizeof(queryControl));
- queryControl.id = V4L2_CID_EXPOSURE_AUTO;
- if (::ioctl(v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
- v4l2AutoExposureSupported = true;
- }
-
- ::memset(&queryControl, 0, sizeof(queryControl));
- queryControl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
- if (::ioctl(v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
- v4l2ManualExposureSupported = true;
- v4l2MinExposure = queryControl.minimum;
- v4l2MaxExposure = queryControl.maximum;
- features |= QCamera::Feature::ManualExposureTime;
- }
-
- ::memset(&queryControl, 0, sizeof(queryControl));
- queryControl.id = V4L2_CID_AUTO_EXPOSURE_BIAS;
- if (::ioctl(v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
- v4l2MinExposureAdjustment = queryControl.minimum;
- v4l2MaxExposureAdjustment = queryControl.maximum;
- features |= QCamera::Feature::ExposureCompensation;
- }
-
- ::memset(&queryControl, 0, sizeof(queryControl));
- queryControl.id = V4L2_CID_ISO_SENSITIVITY_AUTO;
- if (::ioctl(v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
- queryControl.id = V4L2_CID_ISO_SENSITIVITY;
- if (::ioctl(v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
- features |= QCamera::Feature::IsoSensitivity;
- minIsoChanged(queryControl.minimum);
- maxIsoChanged(queryControl.minimum);
- }
- }
-
- supportedFeaturesChanged(features);
-}
-
-int QGstreamerCamera::setV4L2ColorTemperature(int temperature)
-{
- struct v4l2_control control;
- ::memset(&control, 0, sizeof(control));
-
- if (v4l2AutoWhiteBalanceSupported) {
- setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE, temperature == 0 ? true : false);
- } else if (temperature == 0) {
- temperature = 5600;
- }
-
- if (temperature != 0 && v4l2ColorTemperatureSupported) {
- temperature = qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp);
- if (!setV4L2Parameter(V4L2_CID_WHITE_BALANCE_TEMPERATURE, qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp)))
- temperature = 0;
- } else {
- temperature = 0;
- }
-
- return temperature;
-}
-
-bool QGstreamerCamera::setV4L2Parameter(quint32 id, qint32 value)
-{
- struct v4l2_control control{id, value};
- if (::ioctl(v4l2FileDescriptor, VIDIOC_S_CTRL, &control) != 0) {
- qWarning() << "Unable to set the V4L2 Parameter" << Qt::hex << id << "to" << value << qt_error_string(errno);
- return false;
- }
- return true;
-}
-
-int QGstreamerCamera::getV4L2Parameter(quint32 id) const
-{
- struct v4l2_control control{id, 0};
- if (::ioctl(v4l2FileDescriptor, VIDIOC_G_CTRL, &control) != 0) {
- qWarning() << "Unable to get the V4L2 Parameter" << Qt::hex << id << qt_error_string(errno);
- return 0;
- }
- return control.value;
-}
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera_p.h b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera_p.h
deleted file mode 100644
index 94f2f8678..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercamera_p.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#ifndef QGSTREAMERCAMERACONTROL_H
-#define QGSTREAMERCAMERACONTROL_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 <QHash>
-#include <private/qplatformcamera_p.h>
-#include "qgstreamermediacapture_p.h"
-#include <private/qgst_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerCamera : public QPlatformCamera
-{
- Q_OBJECT
-public:
- QGstreamerCamera(QCamera *camera);
- virtual ~QGstreamerCamera();
-
- bool isActive() const override;
- void setActive(bool active) override;
-
- void setCamera(const QCameraDevice &camera) override;
- bool setCameraFormat(const QCameraFormat &format) override;
-
- QGstElement gstElement() const { return gstCameraBin.element(); }
-#if QT_CONFIG(gstreamer_photography)
- GstPhotography *photography() const;
-#endif
-
- void setFocusMode(QCamera::FocusMode mode) override;
- bool isFocusModeSupported(QCamera::FocusMode mode) const override;
-
- void setFlashMode(QCamera::FlashMode mode) override;
- bool isFlashModeSupported(QCamera::FlashMode mode) const override;
- bool isFlashReady() const override;
-
- void setExposureMode(QCamera::ExposureMode) override;
- bool isExposureModeSupported(QCamera::ExposureMode mode) const override;
- void setExposureCompensation(float) override;
- void setManualIsoSensitivity(int) override;
- int isoSensitivity() const override;
- void setManualExposureTime(float) override;
- float exposureTime() const override;
-
- bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override;
- void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override;
- void setColorTemperature(int temperature) override;
-
- QString v4l2Device() const { return m_v4l2Device; }
- bool isV4L2Camera() const { return !m_v4l2Device.isEmpty(); }
-
-private:
- void updateCameraProperties();
-#if QT_CONFIG(linux_v4l)
- void initV4L2Controls();
- int setV4L2ColorTemperature(int temperature);
- bool setV4L2Parameter(quint32 id, qint32 value);
- int getV4L2Parameter(quint32 id) const;
-
- bool v4l2AutoWhiteBalanceSupported = false;
- bool v4l2ColorTemperatureSupported = false;
- bool v4l2AutoExposureSupported = false;
- bool v4l2ManualExposureSupported = false;
- qint32 v4l2MinColorTemp = 5600; // Daylight...
- qint32 v4l2MaxColorTemp = 5600;
- qint32 v4l2MinExposure = 0;
- qint32 v4l2MaxExposure = 0;
- qint32 v4l2MinExposureAdjustment = 0;
- qint32 v4l2MaxExposureAdjustment = 0;
- int v4l2FileDescriptor = -1;
-#endif
-
- QCameraDevice m_cameraDevice;
-
- QGstBin gstCameraBin;
- QGstElement gstCamera;
- QGstElement gstCapsFilter;
- QGstElement gstDecode;
- QGstElement gstVideoConvert;
- QGstElement gstVideoScale;
-
- bool m_active = false;
- QString m_v4l2Device;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERCAMERACONTROL_H
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture.cpp
deleted file mode 100644
index 2d943def2..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamerimagecapture_p.h"
-#include "qplatformcamera_p.h"
-#include <private/qplatformimagecapture_p.h>
-#include <private/qgstvideobuffer_p.h>
-#include <private/qgstutils_p.h>
-#include <private/qgstreamermetadata_p.h>
-#include <qvideoframeformat.h>
-#include "qmediastoragelocation_p.h"
-
-#include <QtCore/QDebug>
-#include <QtCore/QDir>
-#include <qstandardpaths.h>
-
-#include <qloggingcategory.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(qLcImageCapture, "qt.multimedia.imageCapture")
-
-QGstreamerImageCapture::QGstreamerImageCapture(QImageCapture *parent)
- : QPlatformImageCapture(parent),
- QGstreamerBufferProbe(ProbeBuffers)
-{
- bin = QGstBin("imageCaptureBin");
-
- queue = QGstElement("queue", "imageCaptureQueue");
- // configures the queue to be fast, lightweight and non blocking
- queue.set("leaky", 2 /*downstream*/);
- queue.set("silent", true);
- queue.set("max-size-buffers", 1);
- queue.set("max-size-bytes", 0);
- queue.set("max-size-time", 0);
-
- videoConvert = QGstElement("videoconvert", "imageCaptureConvert");
- encoder = QGstElement("jpegenc", "jpegEncoder");
- muxer = QGstElement("jifmux", "jpegMuxer");
- sink = QGstElement("fakesink","imageCaptureSink");
- // 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);
-
- bin.add(queue, videoConvert, encoder, muxer, sink);
- queue.link(videoConvert, encoder, muxer, sink);
- bin.addGhostPad(queue, "sink");
-
- addProbeToPad(queue.staticPad("src").pad(), false);
-
- sink.set("signal-handoffs", true);
- g_signal_connect(sink.object(), "handoff", G_CALLBACK(&QGstreamerImageCapture::saveImageFilter), this);
-}
-
-QGstreamerImageCapture::~QGstreamerImageCapture()
-{
- bin.setStateSync(GST_STATE_NULL);
-}
-
-bool QGstreamerImageCapture::isReadyForCapture() const
-{
- return m_session && !passImage && cameraActive;
-}
-
-int QGstreamerImageCapture::capture(const QString &fileName)
-{
- QString path = QMediaStorageLocation::generateFileName(fileName, QStandardPaths::PicturesLocation, QLatin1String("jpg"));
- return doCapture(path);
-}
-
-int QGstreamerImageCapture::captureToBuffer()
-{
- return doCapture(QString());
-}
-
-int QGstreamerImageCapture::doCapture(const QString &fileName)
-{
- qCDebug(qLcImageCapture) << "do capture";
- if (!m_session) {
- //emit error in the next event loop,
- //so application can associate it with returned request id.
- QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
- Q_ARG(int, -1),
- Q_ARG(int, QImageCapture::ResourceError),
- Q_ARG(QString, QPlatformImageCapture::msgImageCaptureNotSet()));
-
- qCDebug(qLcImageCapture) << "error 1";
- return -1;
- }
- if (!m_session->camera()) {
- //emit error in the next event loop,
- //so application can associate it with returned request id.
- QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
- Q_ARG(int, -1),
- Q_ARG(int, QImageCapture::ResourceError),
- Q_ARG(QString,tr("No camera available.")));
-
- qCDebug(qLcImageCapture) << "error 2";
- return -1;
- }
- if (passImage) {
- //emit error in the next event loop,
- //so application can associate it with returned request id.
- QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
- Q_ARG(int, -1),
- Q_ARG(int, QImageCapture::NotReadyError),
- Q_ARG(QString, QPlatformImageCapture::msgCameraNotReady()));
-
- qCDebug(qLcImageCapture) << "error 3";
- return -1;
- }
- m_lastId++;
-
- pendingImages.enqueue({m_lastId, fileName, QMediaMetaData{}});
- // let one image pass the pipeline
- passImage = true;
-
- emit readyForCaptureChanged(false);
- return m_lastId;
-}
-
-bool QGstreamerImageCapture::probeBuffer(GstBuffer *buffer)
-{
- if (!passImage)
- return false;
- qCDebug(qLcImageCapture) << "probe buffer";
-
- passImage = false;
-
- emit readyForCaptureChanged(isReadyForCapture());
-
- QGstCaps caps = gst_pad_get_current_caps(bin.staticPad("sink").pad());
- GstVideoInfo previewInfo;
- gst_video_info_from_caps(&previewInfo, caps.get());
-
- auto memoryFormat = caps.memoryFormat();
- auto fmt = QGstCaps(caps).formatForCaps(&previewInfo);
- auto *sink = m_session->gstreamerVideoSink();
- auto *gstBuffer = new QGstVideoBuffer(buffer, 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();
-
- emit imageExposed(imageData.id);
-
- qCDebug(qLcImageCapture) << "Image available!";
- emit imageAvailable(imageData.id, frame);
-
- emit imageCaptured(imageData.id, img);
-
- QMediaMetaData metaData = this->metaData();
- metaData.insert(QMediaMetaData::Date, QDateTime::currentDateTime());
- metaData.insert(QMediaMetaData::Resolution, frame.size());
- imageData.metaData = metaData;
-
- // ensure taginject injects this metaData
- const auto &md = static_cast<const QGstreamerMetaData &>(metaData);
- md.setMetaData(muxer.element());
-
- emit imageMetadataAvailable(imageData.id, metaData);
-
- return true;
-}
-
-void QGstreamerImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QGstreamerMediaCapture *captureSession = static_cast<QGstreamerMediaCapture *>(session);
- if (m_session == captureSession)
- return;
-
- if (m_session) {
- disconnect(m_session, nullptr, this, nullptr);
- m_lastId = 0;
- pendingImages.clear();
- passImage = false;
- cameraActive = false;
- }
-
- m_session = captureSession;
- if (!m_session)
- return;
-
- connect(m_session, &QPlatformMediaCaptureSession::cameraChanged, this, &QGstreamerImageCapture::onCameraChanged);
- onCameraChanged();
-}
-
-void QGstreamerImageCapture::cameraActiveChanged(bool active)
-{
- qCDebug(qLcImageCapture) << "cameraActiveChanged" << cameraActive << active;
- if (cameraActive == active)
- return;
- cameraActive = active;
- qCDebug(qLcImageCapture) << "isReady" << isReadyForCapture();
- emit readyForCaptureChanged(isReadyForCapture());
-}
-
-void QGstreamerImageCapture::onCameraChanged()
-{
- if (m_session->camera()) {
- cameraActiveChanged(m_session->camera()->isActive());
- connect(m_session->camera(), &QPlatformCamera::activeChanged, this, &QGstreamerImageCapture::cameraActiveChanged);
- }
-
-}
-
-gboolean QGstreamerImageCapture::saveImageFilter(GstElement *element,
- GstBuffer *buffer,
- GstPad *pad,
- void *appdata)
-{
- Q_UNUSED(element);
- Q_UNUSED(pad);
- QGstreamerImageCapture *capture = static_cast<QGstreamerImageCapture *>(appdata);
-
- capture->passImage = false;
-
- if (capture->pendingImages.isEmpty()) {
- return true;
- }
-
- auto imageData = capture->pendingImages.dequeue();
- if (imageData.filename.isEmpty()) {
- return true;
- }
-
- qCDebug(qLcImageCapture) << "saving image as" << imageData.filename;
-
- QFile f(imageData.filename);
- if (f.open(QFile::WriteOnly)) {
- 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();
-
- static QMetaMethod savedSignal = QMetaMethod::fromSignal(&QGstreamerImageCapture::imageSaved);
- savedSignal.invoke(capture,
- Qt::QueuedConnection,
- Q_ARG(int, imageData.id),
- Q_ARG(QString, imageData.filename));
- }
-
- return TRUE;
-}
-
-QImageEncoderSettings QGstreamerImageCapture::imageSettings() const
-{
- return m_settings;
-}
-
-void QGstreamerImageCapture::setImageSettings(const QImageEncoderSettings &settings)
-{
- if (m_settings != settings) {
- m_settings = settings;
- // ###
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture_p.h b/src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture_p.h
deleted file mode 100644
index a0f5d1a0b..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamerimagecapture_p.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#ifndef QGSTREAMERIMAGECAPTURECONTROL_H
-#define QGSTREAMERIMAGECAPTURECONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformimagecapture_p.h>
-#include "qgstreamermediacapture_p.h"
-#include "private/qgstreamerbufferprobe_p.h"
-
-#include <qqueue.h>
-
-#include <private/qgst_p.h>
-#include <gst/video/video.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerImageCapture : public QPlatformImageCapture, private QGstreamerBufferProbe
-
-{
- Q_OBJECT
-public:
- QGstreamerImageCapture(QImageCapture *parent);
- virtual ~QGstreamerImageCapture();
-
- bool isReadyForCapture() const override;
- int capture(const QString &fileName) override;
- int captureToBuffer() override;
-
- QImageEncoderSettings imageSettings() const override;
- void setImageSettings(const QImageEncoderSettings &settings) override;
-
- bool probeBuffer(GstBuffer *buffer) override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
- QGstElement gstElement() const { return bin.element(); }
-
-public Q_SLOTS:
- void cameraActiveChanged(bool active);
- void onCameraChanged();
-
-private:
- int doCapture(const QString &fileName);
- static gboolean saveImageFilter(GstElement *element, GstBuffer *buffer, GstPad *pad, void *appdata);
-
- QGstreamerMediaCapture *m_session = nullptr;
- int m_lastId = 0;
- QImageEncoderSettings m_settings;
-
- struct PendingImage {
- int id;
- QString filename;
- QMediaMetaData metaData;
- };
-
- QQueue<PendingImage> pendingImages;
-
- QGstBin bin;
- QGstElement queue;
- QGstElement videoConvert;
- QGstElement encoder;
- QGstElement muxer;
- QGstElement sink;
- QGstPad videoSrcPad;
-
- bool passImage = false;
- bool cameraActive = false;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERCAPTURECORNTROL_H
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp
deleted file mode 100644
index 478eb1c0a..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamermediacapture_p.h"
-#include "qgstreamermediaencoder_p.h"
-#include "qgstreamerimagecapture_p.h"
-#include "qgstreamercamera_p.h"
-#include <private/qgstpipeline_p.h>
-
-#include "private/qgstreameraudioinput_p.h"
-#include "private/qgstreameraudiooutput_p.h"
-#include "private/qgstreamervideooutput_p.h"
-
-#include <qloggingcategory.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(qLcMediaCapture, "qt.multimedia.capture")
-
-
-static void linkTeeToPad(QGstElement tee, QGstPad sink)
-{
- if (tee.isNull() || sink.isNull())
- return;
-
- auto source = tee.getRequestPad("src_%u");
- 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);
-}
-
-
-QGstreamerMediaCapture::QGstreamerMediaCapture()
- : gstPipeline("pipeline")
-{
- gstVideoOutput = new QGstreamerVideoOutput(this);
- gstVideoOutput->setIsPreview();
- gstVideoOutput->setPipeline(gstPipeline);
-
- // Use system clock to drive all elements in the pipeline. Otherwise,
- // the clock is sourced from the elements (e.g. from an audio source).
- // Since the elements are added and removed dynamically the clock would
- // also change causing lost of synchronization in the pipeline.
- gst_pipeline_use_clock(gstPipeline.pipeline(), gst_system_clock_obtain());
-
- // This is the recording pipeline with only live sources, thus the pipeline
- // will be always in the playing state.
- gstPipeline.setState(GST_STATE_PLAYING);
-
- // TODO: remove this debug before final commit
- // Four basic elements of the capture session showing the current position and state
- // All presented position should show similar progress.
- heartbeat.setInterval(1000);
- heartbeat.start();
- QObject::connect(&heartbeat, &QTimer::timeout, [this]() {
- if (!gstPipeline.isNull()) {
- gint64 current = -1;
- gst_element_query_position(gstPipeline.element(),GST_FORMAT_TIME, &current);
- qDebug() << "Pipeline " << current / 1000000 << gstPipeline.state();
-// auto name = QString::number(current).toLocal8Bit().data();
-// gstPipeline.dumpGraph(name);
- }
- if (gstAudioInput && !gstAudioInput->gstElement().isNull()) {
- gint64 current = -1;
- auto element = gstAudioInput->gstElement().element();
- gst_element_query_position(element,GST_FORMAT_TIME, &current);
- qDebug() << "Audio " << current / 1000000 << gstAudioInput->gstElement().state();
- }
- if (gstCamera && !gstCamera->gstElement().isNull()) {
- gint64 current = -1;
- gst_element_query_position(gstCamera->gstElement().element(),GST_FORMAT_TIME, &current);
- qDebug() << "Camera " << current / 1000000 << gstCamera->gstElement().state();
- }
- auto encoder = !m_mediaEncoder ? QGstElement{} : m_mediaEncoder->getEncoder();
- if (!encoder.isNull()) {
- gint64 current = -1;
- gst_element_query_position(encoder.element(),GST_FORMAT_TIME, &current);
- qDebug() << "Encoder " << current / 1000000 << encoder.state();
- }
- });
-
- gstPipeline.dumpGraph("initial");
-}
-
-QGstreamerMediaCapture::~QGstreamerMediaCapture()
-{
- setMediaEncoder(nullptr);
- setImageCapture(nullptr);
- setCamera(nullptr);
- gstPipeline.setStateSync(GST_STATE_NULL);
-}
-
-QPlatformCamera *QGstreamerMediaCapture::camera()
-{
- return gstCamera;
-}
-
-void QGstreamerMediaCapture::setCamera(QPlatformCamera *camera)
-{
- QGstreamerCamera *control = static_cast<QGstreamerCamera *>(camera);
- if (gstCamera == control)
- return;
-
- if (gstCamera) {
- unlinkTeeFromPad(gstVideoTee, encoderVideoSink);
- unlinkTeeFromPad(gstVideoTee, imageCaptureSink);
-
- auto camera = gstCamera->gstElement();
- camera.setStateSync(GST_STATE_NULL);
- gstVideoTee.setStateSync(GST_STATE_NULL);
- gstVideoOutput->gstElement().setStateSync(GST_STATE_NULL);
-
- gstPipeline.remove(camera);
- gstPipeline.remove(gstVideoTee);
- gstPipeline.remove(gstVideoOutput->gstElement());
-
- gstVideoTee = {};
- gstCamera->setCaptureSession(nullptr);
- }
-
- gstCamera = control;
- if (gstCamera) {
- QGstElement camera = gstCamera->gstElement();
- gstVideoTee = QGstElement("tee", "videotee");
- gstVideoTee.set("allow-not-linked", true);
-
- gstPipeline.add(gstVideoOutput->gstElement(), camera, gstVideoTee);
-
- linkTeeToPad(gstVideoTee, encoderVideoSink);
- linkTeeToPad(gstVideoTee, gstVideoOutput->gstElement().staticPad("sink"));
- linkTeeToPad(gstVideoTee, imageCaptureSink);
-
- camera.link(gstVideoTee);
-
- gstVideoOutput->gstElement().setState(GST_STATE_PLAYING);
- gstVideoTee.setState(GST_STATE_PLAYING);
- camera.setState(GST_STATE_PLAYING);
- }
-
- gstPipeline.dumpGraph("camera");
-
- emit cameraChanged();
-}
-
-QPlatformImageCapture *QGstreamerMediaCapture::imageCapture()
-{
- return m_imageCapture;
-}
-
-void QGstreamerMediaCapture::setImageCapture(QPlatformImageCapture *imageCapture)
-{
- QGstreamerImageCapture *control = static_cast<QGstreamerImageCapture *>(imageCapture);
- if (m_imageCapture == control)
- return;
-
- if (m_imageCapture) {
- unlinkTeeFromPad(gstVideoTee, imageCaptureSink);
- m_imageCapture->gstElement().setStateSync(GST_STATE_NULL);
- gstPipeline.remove(m_imageCapture->gstElement());
- imageCaptureSink = {};
- m_imageCapture->setCaptureSession(nullptr);
- }
-
- m_imageCapture = control;
- if (m_imageCapture) {
- imageCaptureSink = m_imageCapture->gstElement().staticPad("sink");
- m_imageCapture->gstElement().setState(GST_STATE_PLAYING);
- gstPipeline.add(m_imageCapture->gstElement());
- linkTeeToPad(gstVideoTee, imageCaptureSink);
- m_imageCapture->setCaptureSession(this);
- }
-
- gstPipeline.dumpGraph("imageCapture");
-
- emit imageCaptureChanged();
-}
-
-void QGstreamerMediaCapture::setMediaEncoder(QPlatformMediaEncoder *encoder)
-{
- QGstreamerMediaEncoder *control = static_cast<QGstreamerMediaEncoder *>(encoder);
- if (m_mediaEncoder == control)
- return;
-
- if (m_mediaEncoder)
- m_mediaEncoder->setCaptureSession(nullptr);
- m_mediaEncoder = control;
- if (m_mediaEncoder)
- m_mediaEncoder->setCaptureSession(this);
-
- emit encoderChanged();
- gstPipeline.dumpGraph("encoder");
-}
-
-QPlatformMediaEncoder *QGstreamerMediaCapture::mediaEncoder()
-{
- return m_mediaEncoder;
-}
-
-void QGstreamerMediaCapture::linkEncoder(QGstPad audioSink, QGstPad videoSink)
-{
- if (!gstVideoTee.isNull() && !videoSink.isNull()) {
- auto caps = gst_pad_get_current_caps(gstVideoTee.sink().pad());
-
- encoderVideoCapsFilter = QGstElement("capsfilter", "encoderVideoCapsFilter");
- encoderVideoCapsFilter.set("caps", QGstMutableCaps(caps));
-
- gstPipeline.add(encoderVideoCapsFilter);
-
- encoderVideoCapsFilter.src().link(videoSink);
- linkTeeToPad(gstVideoTee, encoderVideoCapsFilter.sink());
- encoderVideoCapsFilter.setState(GST_STATE_PLAYING);
- encoderVideoSink = encoderVideoCapsFilter.sink();
- }
-
- if (!gstAudioTee.isNull() && !audioSink.isNull()) {
- auto caps = gst_pad_get_current_caps(gstAudioTee.sink().pad());
-
- encoderAudioCapsFilter = QGstElement("capsfilter", "encoderAudioCapsFilter");
- encoderAudioCapsFilter.set("caps", QGstMutableCaps(caps));
-
- gstPipeline.add(encoderAudioCapsFilter);
-
- encoderAudioCapsFilter.src().link(audioSink);
- linkTeeToPad(gstAudioTee, encoderAudioCapsFilter.sink());
- encoderAudioCapsFilter.setState(GST_STATE_PLAYING);
- encoderAudioSink = encoderAudioCapsFilter.sink();
- }
-}
-
-void QGstreamerMediaCapture::unlinkEncoder()
-{
- if (!encoderVideoCapsFilter.isNull()) {
- encoderVideoCapsFilter.src().unlinkPeer();
- unlinkTeeFromPad(gstVideoTee, encoderVideoCapsFilter.sink());
- encoderVideoCapsFilter.setStateSync(GST_STATE_NULL);
- gstPipeline.remove(encoderVideoCapsFilter);
- encoderVideoCapsFilter = {};
- }
-
- if (!encoderAudioCapsFilter.isNull()) {
- encoderAudioCapsFilter.src().unlinkPeer();
- unlinkTeeFromPad(gstAudioTee, encoderAudioCapsFilter.sink());
- encoderAudioCapsFilter.setStateSync(GST_STATE_NULL);
- gstPipeline.remove(encoderAudioCapsFilter);
- encoderAudioCapsFilter = {};
- }
-
- encoderAudioSink = {};
- encoderVideoSink = {};
-}
-
-void QGstreamerMediaCapture::setAudioInput(QPlatformAudioInput *input)
-{
- if (gstAudioInput == input)
- return;
-
- if (gstAudioInput) {
- unlinkTeeFromPad(gstAudioTee, encoderAudioSink);
-
- if (gstAudioOutput) {
- unlinkTeeFromPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
- gstAudioOutput->gstElement().setStateSync(GST_STATE_NULL);
- gstPipeline.remove(gstAudioOutput->gstElement());
- }
-
- gstAudioInput->gstElement().setStateSync(GST_STATE_NULL);
- gstPipeline.remove(gstAudioInput->gstElement());
- gstAudioTee.setStateSync(GST_STATE_NULL);
- gstPipeline.remove(gstAudioTee);
- gstAudioTee = {};
- }
-
- gstAudioInput = static_cast<QGstreamerAudioInput *>(input);
- if (gstAudioInput) {
- Q_ASSERT(gstAudioTee.isNull());
- gstAudioTee = QGstElement("tee", "audiotee");
- gstAudioTee.set("allow-not-linked", true);
- gstPipeline.add(gstAudioInput->gstElement(), gstAudioTee);
- gstAudioInput->gstElement().link(gstAudioTee);
-
- if (gstAudioOutput) {
- gstPipeline.add(gstAudioOutput->gstElement());
- gstAudioOutput->gstElement().setState(GST_STATE_PLAYING);
- linkTeeToPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
- }
-
- gstAudioTee.setState(GST_STATE_PLAYING);
- gstAudioInput->gstElement().setStateSync(GST_STATE_PLAYING);
-
- linkTeeToPad(gstAudioTee, encoderAudioSink);
- }
-}
-
-void QGstreamerMediaCapture::setVideoPreview(QVideoSink *sink)
-{
- gstVideoOutput->setVideoSink(sink);
-}
-
-void QGstreamerMediaCapture::setAudioOutput(QPlatformAudioOutput *output)
-{
- if (gstAudioOutput == output)
- return;
-
- if (gstAudioOutput && gstAudioInput) {
- // If audio input is set, the output is in the pipeline
- unlinkTeeFromPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
- gstAudioOutput->gstElement().setStateSync(GST_STATE_NULL);
- gstPipeline.remove(gstAudioOutput->gstElement());
- }
-
- gstAudioOutput = static_cast<QGstreamerAudioOutput *>(output);
- if (gstAudioOutput && gstAudioInput) {
- gstPipeline.add(gstAudioOutput->gstElement());
- gstAudioOutput->gstElement().setState(GST_STATE_PLAYING);
- linkTeeToPad(gstAudioTee, gstAudioOutput->gstElement().staticPad("sink"));
- }
-}
-
-QGstreamerVideoSink *QGstreamerMediaCapture::gstreamerVideoSink() const
-{
- return gstVideoOutput ? gstVideoOutput->gstreamerVideoSink() : nullptr;
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h
deleted file mode 100644
index ed75a27d1..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERCAPTURESERVICE_H
-#define QGSTREAMERCAPTURESERVICE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediacapture_p.h>
-#include <private/qplatformmediaintegration_p.h>
-
-#include <private/qgst_p.h>
-#include <private/qgstpipeline_p.h>
-
-#include <qtimer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerCamera;
-class QGstreamerImageCapture;
-class QGstreamerMediaEncoder;
-class QGstreamerAudioInput;
-class QGstreamerAudioOutput;
-class QGstreamerVideoOutput;
-class QGstreamerVideoSink;
-
-class QGstreamerMediaCapture : public QPlatformMediaCaptureSession
-{
- Q_OBJECT
-
-public:
- QGstreamerMediaCapture();
- virtual ~QGstreamerMediaCapture();
-
- QPlatformCamera *camera() override;
- void setCamera(QPlatformCamera *camera) override;
-
- QPlatformImageCapture *imageCapture() override;
- void setImageCapture(QPlatformImageCapture *imageCapture) override;
-
- QPlatformMediaEncoder *mediaEncoder() override;
- void setMediaEncoder(QPlatformMediaEncoder *encoder) override;
-
- void setAudioInput(QPlatformAudioInput *input) override;
- QGstreamerAudioInput *audioInput() { return gstAudioInput; }
-
- void setVideoPreview(QVideoSink *sink) override;
- void setAudioOutput(QPlatformAudioOutput *output) override;
-
- void linkEncoder(QGstPad audioSink, QGstPad videoSink);
- void unlinkEncoder();
-
- QGstPipeline pipeline() const { return gstPipeline; }
-
- QGstreamerVideoSink *gstreamerVideoSink() const;
-
-private:
- friend QGstreamerMediaEncoder;
- // Gst elements
- QGstPipeline gstPipeline;
- QTimer heartbeat;
-
- QGstreamerAudioInput *gstAudioInput = nullptr;
- QGstreamerCamera *gstCamera = nullptr;
-
- QGstElement gstAudioTee;
- QGstElement gstVideoTee;
- QGstElement encoderVideoCapsFilter;
- QGstElement encoderAudioCapsFilter;
-
- QGstPad encoderAudioSink;
- QGstPad encoderVideoSink;
- QGstPad imageCaptureSink;
-
- QGstreamerAudioOutput *gstAudioOutput = nullptr;
- QGstreamerVideoOutput *gstVideoOutput = nullptr;
-
- QGstreamerMediaEncoder *m_mediaEncoder = nullptr;
- QGstreamerImageCapture *m_imageCapture = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERCAPTURESERVICE_H
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder.cpp
deleted file mode 100644
index 434a6ca67..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamermediaencoder_p.h"
-#include "private/qgstreamerintegration_p.h"
-#include "private/qgstreamerformatinfo_p.h"
-#include "private/qgstpipeline_p.h"
-#include "private/qgstreamermessage_p.h"
-#include "private/qplatformcamera_p.h"
-#include "qaudiodevice.h"
-#include "qmediastoragelocation_p.h"
-
-#include <qdebug.h>
-#include <qstandardpaths.h>
-#include <qmimetype.h>
-#include <qloggingcategory.h>
-
-#include <gst/gsttagsetter.h>
-#include <gst/gstversion.h>
-#include <gst/video/video.h>
-#include <gst/pbutils/encoding-profile.h>
-
-Q_LOGGING_CATEGORY(qLcMediaEncoder, "qt.multimedia.encoder")
-
-QGstreamerMediaEncoder::QGstreamerMediaEncoder(QMediaRecorder *parent)
- : QPlatformMediaEncoder(parent),
- audioPauseControl(*this),
- videoPauseControl(*this)
-{
- signalDurationChangedTimer.setInterval(100);
- signalDurationChangedTimer.callOnTimeout([this](){ durationChanged(duration()); });
-}
-
-QGstreamerMediaEncoder::~QGstreamerMediaEncoder()
-{
- if (!gstPipeline.isNull()) {
- finalize();
- gstPipeline.removeMessageFilter(this);
- gstPipeline.setStateSync(GST_STATE_NULL);
- }
-}
-
-bool QGstreamerMediaEncoder::isLocationWritable(const QUrl &) const
-{
- return true;
-}
-
-void QGstreamerMediaEncoder::handleSessionError(QMediaRecorder::Error code, const QString &description)
-{
- error(code, description);
- stop();
-}
-
-bool QGstreamerMediaEncoder::processBusMessage(const QGstreamerMessage &message)
-{
- GstMessage *gm = message.rawMessage();
- if (!gm)
- return false;
-
-// qCDebug(qLcMediaEncoder) << "received event from" << message.source().name() << Qt::hex << message.type();
-// if (message.type() == GST_MESSAGE_STATE_CHANGED) {
-// GstState oldState;
-// GstState newState;
-// GstState pending;
-// gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
-// qCDebug(qLcMediaEncoder) << "received state change from" << message.source().name() << oldState << newState << pending;
-// }
- if (message.type() == GST_MESSAGE_ELEMENT) {
- QGstStructure s = gst_message_get_structure(gm);
- qCDebug(qLcMediaEncoder) << "received element message from" << message.source().name() << s.name();
- if (s.name() == "GstBinForwarded")
- gm = s.getMessage();
- if (!gm)
- return false;
- }
-
- if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_EOS) {
- qCDebug(qLcMediaEncoder) << "received EOS from" << QGstObject(GST_MESSAGE_SRC(gm)).name();
- finalize();
- return false;
- }
-
- if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) {
- GError *err;
- gchar *debug;
- gst_message_parse_error(gm, &err, &debug);
- error(QMediaRecorder::ResourceError, QString::fromUtf8(err->message));
- g_error_free(err);
- g_free(debug);
- finalize();
- }
-
- if (GST_MESSAGE_SRC(gm) == gstEncoder.object()) {
- switch (GST_MESSAGE_TYPE(gm)) {
- case GST_MESSAGE_STATE_CHANGED: {
- GstState oldState;
- GstState newState;
- GstState pending;
- gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
-
- if (newState == GST_STATE_PAUSED && !m_metaData.isEmpty())
- setMetaData(m_metaData);
- break;
- }
- default:
- break;
- }
- }
- return false;
-}
-
-qint64 QGstreamerMediaEncoder::duration() const
-{
- return std::max(audioPauseControl.duration, videoPauseControl.duration);
-}
-
-
-static GstEncodingContainerProfile *createContainerProfile(const QMediaEncoderSettings &settings)
-{
- auto *formatInfo = QGstreamerIntegration::instance()->m_formatsInfo;
-
- QGstMutableCaps caps = formatInfo->formatCaps(settings.fileFormat());
-
- GstEncodingContainerProfile *profile = (GstEncodingContainerProfile *)gst_encoding_container_profile_new(
- "container_profile",
- (gchar *)"custom container profile",
- const_cast<GstCaps *>(caps.get()),
- nullptr); //preset
- return profile;
-}
-
-static GstEncodingProfile *createVideoProfile(const QMediaEncoderSettings &settings)
-{
- auto *formatInfo = QGstreamerIntegration::instance()->m_formatsInfo;
-
- QGstMutableCaps caps = formatInfo->videoCaps(settings.mediaFormat());
- if (caps.isNull())
- return nullptr;
-
- GstEncodingVideoProfile *profile = gst_encoding_video_profile_new(
- const_cast<GstCaps *>(caps.get()),
- nullptr,
- nullptr, //restriction
- 0); //presence
-
- gst_encoding_video_profile_set_pass(profile, 0);
- gst_encoding_video_profile_set_variableframerate(profile, TRUE);
-
- return (GstEncodingProfile *)profile;
-}
-
-static GstEncodingProfile *createAudioProfile(const QMediaEncoderSettings &settings)
-{
- auto *formatInfo = QGstreamerIntegration::instance()->m_formatsInfo;
-
- auto caps = formatInfo->audioCaps(settings.mediaFormat());
- if (caps.isNull())
- return nullptr;
-
- GstEncodingProfile *profile = (GstEncodingProfile *)gst_encoding_audio_profile_new(
- const_cast<GstCaps *>(caps.get()),
- nullptr, //preset
- nullptr, //restriction
- 0); //presence
-
- return profile;
-}
-
-
-static GstEncodingContainerProfile *createEncodingProfile(const QMediaEncoderSettings &settings)
-{
- auto *containerProfile = createContainerProfile(settings);
- if (!containerProfile) {
- qWarning() << "QGstreamerMediaEncoder: failed to create container profile!";
- return nullptr;
- }
-
- GstEncodingProfile *audioProfile = createAudioProfile(settings);
- GstEncodingProfile *videoProfile = nullptr;
- if (settings.videoCodec() != QMediaFormat::VideoCodec::Unspecified)
- videoProfile = createVideoProfile(settings);
-// qDebug() << "audio profile" << (audioProfile ? gst_caps_to_string(gst_encoding_profile_get_format(audioProfile)) : "(null)");
-// qDebug() << "video profile" << (videoProfile ? gst_caps_to_string(gst_encoding_profile_get_format(videoProfile)) : "(null)");
-// qDebug() << "conta profile" << gst_caps_to_string(gst_encoding_profile_get_format((GstEncodingProfile *)containerProfile));
-
- if (videoProfile) {
- if (!gst_encoding_container_profile_add_profile(containerProfile, videoProfile)) {
- qWarning() << "QGstreamerMediaEncoder: failed to add video profile!";
- gst_encoding_profile_unref(videoProfile);
- }
- }
- if (audioProfile) {
- if (!gst_encoding_container_profile_add_profile(containerProfile, audioProfile)) {
- qWarning() << "QGstreamerMediaEncoder: failed to add audio profile!";
- gst_encoding_profile_unref(audioProfile);
- }
- }
-
- return containerProfile;
-}
-
-void QGstreamerMediaEncoder::PauseControl::reset()
-{
- pauseOffsetPts = 0;
- pauseStartPts.reset();
- duration = 0;
- firstBufferPts.reset();
-}
-
-void QGstreamerMediaEncoder::PauseControl::installOn(QGstPad pad)
-{
- pad.addProbe<&QGstreamerMediaEncoder::PauseControl::processBuffer>(this, GST_PAD_PROBE_TYPE_BUFFER);
-}
-
-GstPadProbeReturn QGstreamerMediaEncoder::PauseControl::processBuffer(QGstPad, GstPadProbeInfo *info)
-{
- auto buffer = GST_PAD_PROBE_INFO_BUFFER(info);
- if (!buffer)
- return GST_PAD_PROBE_OK;
-
- buffer = gst_buffer_make_writable(buffer);
-
- if (!buffer)
- return GST_PAD_PROBE_OK;
-
- GST_PAD_PROBE_INFO_DATA(info) = buffer;
-
- if (!GST_BUFFER_PTS_IS_VALID(buffer))
- return GST_PAD_PROBE_OK;
-
- if (!firstBufferPts)
- firstBufferPts = GST_BUFFER_PTS(buffer);
-
- if (encoder.state() == QMediaRecorder::PausedState) {
- if (!pauseStartPts)
- pauseStartPts = GST_BUFFER_PTS(buffer);
-
- return GST_PAD_PROBE_DROP;
- }
-
- if (pauseStartPts) {
- pauseOffsetPts += GST_BUFFER_PTS(buffer) - *pauseStartPts;
- pauseStartPts.reset();
- }
- GST_BUFFER_PTS(buffer) -= pauseOffsetPts;
-
- duration = (GST_BUFFER_PTS(buffer) - *firstBufferPts) / GST_MSECOND;
-
- return GST_PAD_PROBE_OK;
-}
-
-void QGstreamerMediaEncoder::record(QMediaEncoderSettings &settings)
-{
- if (!m_session || state() != QMediaRecorder::StoppedState)
- return;
-
- const auto hasVideo = m_session->camera() && m_session->camera()->isActive();
- const auto hasAudio = m_session->audioInput() != nullptr;
-
- if (!hasVideo && !hasAudio) {
- error(QMediaRecorder::ResourceError, QMediaRecorder::tr("No camera or audio input"));
- return;
- }
-
- const auto audioOnly = settings.videoCodec() == QMediaFormat::VideoCodec::Unspecified;
-
- auto primaryLocation = audioOnly ? QStandardPaths::MusicLocation : QStandardPaths::MoviesLocation;
- auto container = settings.mimeType().preferredSuffix();
- auto location = QMediaStorageLocation::generateFileName(outputLocation().toLocalFile(), primaryLocation, container);
-
- QUrl actualSink = QUrl::fromLocalFile(QDir::currentPath()).resolved(location);
- qCDebug(qLcMediaEncoder) << "recording new video to" << actualSink;
-
- Q_ASSERT(!actualSink.isEmpty());
-
- gstEncoder = QGstElement("encodebin", "encodebin");
- auto *encodingProfile = createEncodingProfile(settings);
- g_object_set (gstEncoder.object(), "profile", encodingProfile, nullptr);
- gst_encoding_profile_unref(encodingProfile);
-
- gstFileSink = QGstElement("filesink", "filesink");
- gstFileSink.set("location", QFile::encodeName(actualSink.toLocalFile()).constData());
- gstFileSink.set("async", false);
-
- QGstPad audioSink = {};
- QGstPad videoSink = {};
-
- audioPauseControl.reset();
- videoPauseControl.reset();
-
- if (hasAudio) {
- audioSink = gstEncoder.getRequestPad("audio_%u");
- if (audioSink.isNull())
- qWarning() << "Unsupported audio codec";
- else
- audioPauseControl.installOn(audioSink);
- }
-
- if (hasVideo) {
- videoSink = gstEncoder.getRequestPad("video_%u");
- if (videoSink.isNull())
- qWarning() << "Unsupported video codec";
- else
- videoPauseControl.installOn(videoSink);
- }
-
- gstPipeline.add(gstEncoder, gstFileSink);
- gstEncoder.link(gstFileSink);
- m_session->linkEncoder(audioSink, videoSink);
-
- gstEncoder.syncStateWithParent();
- gstFileSink.syncStateWithParent();
-
- signalDurationChangedTimer.start();
- gstPipeline.dumpGraph("recording");
-
- stateChanged(QMediaRecorder::RecordingState);
- actualLocationChanged(QUrl::fromLocalFile(location));
-}
-
-void QGstreamerMediaEncoder::pause()
-{
- if (!m_session || state() != QMediaRecorder::RecordingState)
- return;
- signalDurationChangedTimer.stop();
- gstPipeline.dumpGraph("before-pause");
- stateChanged(QMediaRecorder::PausedState);
-}
-
-void QGstreamerMediaEncoder::resume()
-{
- gstPipeline.dumpGraph("before-resume");
- if (!m_session || state() != QMediaRecorder::PausedState)
- return;
- signalDurationChangedTimer.start();
- stateChanged(QMediaRecorder::RecordingState);
-}
-
-void QGstreamerMediaEncoder::stop()
-{
- if (!m_session || state() == QMediaRecorder::StoppedState)
- return;
- qCDebug(qLcMediaEncoder) << "stop";
-
- m_session->unlinkEncoder();
- signalDurationChangedTimer.stop();
-
- //with live sources it's necessary to send EOS even to pipeline
- //before going to STOPPED state
- qCDebug(qLcMediaEncoder) << ">>>>>>>>>>>>> sending EOS";
- gstEncoder.sendEos();
-}
-
-void QGstreamerMediaEncoder::finalize()
-{
- if (!m_session || gstEncoder.isNull())
- return;
-
- qCDebug(qLcMediaEncoder) << "finalize";
-
- gstEncoder.setState(GST_STATE_NULL);
- gstFileSink.setState(GST_STATE_NULL);
- gstPipeline.remove(gstEncoder);
- gstPipeline.remove(gstFileSink);
- gstFileSink = {};
- gstEncoder = {};
- stateChanged(QMediaRecorder::StoppedState);
-}
-
-void QGstreamerMediaEncoder::setMetaData(const QMediaMetaData &metaData)
-{
- if (!m_session)
- return;
- m_metaData = static_cast<const QGstreamerMetaData &>(metaData);
- m_metaData.setMetaData(gstEncoder.bin());
-
-}
-
-QMediaMetaData QGstreamerMediaEncoder::metaData() const
-{
- return m_metaData;
-}
-
-void QGstreamerMediaEncoder::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QGstreamerMediaCapture *captureSession = static_cast<QGstreamerMediaCapture *>(session);
- if (m_session == captureSession)
- return;
-
- if (m_session) {
- finalize();
- gstPipeline.removeMessageFilter(this);
- gstPipeline = {};
- }
-
- m_session = captureSession;
- if (!m_session)
- return;
-
- gstPipeline = captureSession->gstPipeline;
- gstPipeline.set("message-forward", true);
- gstPipeline.installMessageFilter(this);
-}
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder_p.h b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder_p.h
deleted file mode 100644
index 649edbfd9..000000000
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediaencoder_p.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#ifndef QGSTREAMERENCODERCONTROL_H
-#define QGSTREAMERENCODERCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaencoder_p.h>
-#include "qgstreamermediacapture_p.h"
-#include "private/qgstreamermetadata_p.h"
-
-#include <QtCore/qurl.h>
-#include <QtCore/qdir.h>
-#include <qelapsedtimer.h>
-#include <qtimer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QMediaMetaData;
-class QGstreamerMessage;
-
-class QGstreamerMediaEncoder : public QPlatformMediaEncoder, QGstreamerBusMessageFilter
-{
-public:
- QGstreamerMediaEncoder(QMediaRecorder *parent);
- virtual ~QGstreamerMediaEncoder();
-
- bool isLocationWritable(const QUrl &sink) const override;
-
- qint64 duration() const override;
-
- void record(QMediaEncoderSettings &settings) override;
- void pause() override;
- void resume() override;
- void stop() override;
-
- void setMetaData(const QMediaMetaData &) override;
- QMediaMetaData metaData() const override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
- QGstElement getEncoder() { return gstEncoder; }
-private:
- bool processBusMessage(const QGstreamerMessage& message) override;
-
-private:
- struct PauseControl {
- PauseControl(QPlatformMediaEncoder &encoder) : encoder(encoder) {}
-
- GstPadProbeReturn processBuffer(QGstPad pad, GstPadProbeInfo *info);
- void installOn(QGstPad pad);
- void reset();
-
- QPlatformMediaEncoder &encoder;
- GstClockTime pauseOffsetPts = 0;
- std::optional<GstClockTime> pauseStartPts;
- std::optional<GstClockTime> firstBufferPts;
- qint64 duration = 0;
- };
-
- PauseControl audioPauseControl;
- PauseControl videoPauseControl;
-
- void handleSessionError(QMediaRecorder::Error code, const QString &description);
- void finalize();
-
- QGstreamerMediaCapture *m_session = nullptr;
- QGstreamerMetaData m_metaData;
- QTimer signalDurationChangedTimer;
-
- QGstPipeline gstPipeline;
- QGstBin gstEncoder;
- QGstElement gstFileSink;
-};
-
-QT_END_NAMESPACE
-
-#endif // QGSTREAMERENCODERCONTROL_H
diff --git a/src/multimedia/platform/gstreamer/qgstreamerformatinfo.cpp b/src/multimedia/platform/gstreamer/qgstreamerformatinfo.cpp
deleted file mode 100644
index 1bf17ac89..000000000
--- a/src/multimedia/platform/gstreamer/qgstreamerformatinfo.cpp
+++ /dev/null
@@ -1,459 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamerformatinfo_p.h"
-
-#include "private/qgstutils_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QMediaFormat::AudioCodec QGstreamerFormatInfo::audioCodecForCaps(QGstStructure structure)
-{
- const char *name = structure.name().data();
-
- if (!name || strncmp(name, "audio/", 6))
- return QMediaFormat::AudioCodec::Unspecified;
- name += 6;
- if (!strcmp(name, "mpeg")) {
- auto version = structure["mpegversion"].toInt();
- if (version == 1) {
- auto layer = structure["layer"];
- if (!layer.isNull())
- return QMediaFormat::AudioCodec::MP3;
- }
- if (version == 4)
- return QMediaFormat::AudioCodec::AAC;
- } else if (!strcmp(name, "x-ac3")) {
- return QMediaFormat::AudioCodec::AC3;
- } else if (!strcmp(name, "x-eac3")) {
- return QMediaFormat::AudioCodec::EAC3;
- } else if (!strcmp(name, "x-flac")) {
- return QMediaFormat::AudioCodec::FLAC;
- } else if (!strcmp(name, "x-alac")) {
- return QMediaFormat::AudioCodec::ALAC;
- } else if (!strcmp(name, "x-true-hd")) {
- return QMediaFormat::AudioCodec::DolbyTrueHD;
- } else if (!strcmp(name, "x-vorbis")) {
- return QMediaFormat::AudioCodec::Vorbis;
- } else if (!strcmp(name, "x-opus")) {
- return QMediaFormat::AudioCodec::Opus;
- } else if (!strcmp(name, "x-wav")) {
- return QMediaFormat::AudioCodec::Wave;
- } else if (!strcmp(name, "x-wma")) {
- return QMediaFormat::AudioCodec::WMA;
- }
- return QMediaFormat::AudioCodec::Unspecified;
-}
-
-QMediaFormat::VideoCodec QGstreamerFormatInfo::videoCodecForCaps(QGstStructure structure)
-{
- const char *name = structure.name().data();
-
- if (!name || strncmp(name, "video/", 6))
- return QMediaFormat::VideoCodec::Unspecified;
- name += 6;
-
- if (!strcmp(name, "mpeg")) {
- auto version = structure["mpegversion"].toInt();
- if (version == 1)
- return QMediaFormat::VideoCodec::MPEG1;
- else if (version == 2)
- return QMediaFormat::VideoCodec::MPEG2;
- else if (version == 4)
- return QMediaFormat::VideoCodec::MPEG4;
- } else if (!strcmp(name, "x-h264")) {
- return QMediaFormat::VideoCodec::H264;
-#if GST_CHECK_VERSION(1, 17, 0) // x265enc seems to be broken on 1.16 at least
- } else if (!strcmp(name, "x-h265")) {
- return QMediaFormat::VideoCodec::H265;
-#endif
- } else if (!strcmp(name, "x-vp8")) {
- return QMediaFormat::VideoCodec::VP8;
- } else if (!strcmp(name, "x-vp9")) {
- return QMediaFormat::VideoCodec::VP9;
- } else if (!strcmp(name, "x-av1")) {
- return QMediaFormat::VideoCodec::AV1;
- } else if (!strcmp(name, "x-theora")) {
- return QMediaFormat::VideoCodec::Theora;
- } else if (!strcmp(name, "x-jpeg")) {
- return QMediaFormat::VideoCodec::MotionJPEG;
- } else if (!strcmp(name, "x-wmv")) {
- return QMediaFormat::VideoCodec::WMV;
- }
- return QMediaFormat::VideoCodec::Unspecified;
-}
-
-QMediaFormat::FileFormat QGstreamerFormatInfo::fileFormatForCaps(QGstStructure structure)
-{
- const char *name = structure.name().data();
-
- if (!strcmp(name, "video/x-ms-asf")) {
- return QMediaFormat::FileFormat::WMV;
- } else if (!strcmp(name, "video/x-msvideo")) {
- return QMediaFormat::FileFormat::AVI;
- } else if (!strcmp(name, "video/x-matroska")) {
- return QMediaFormat::FileFormat::Matroska;
- } else if (!strcmp(name, "video/quicktime")) {
- auto variant = structure["variant"].toString();
- if (!variant)
- return QMediaFormat::FileFormat::QuickTime;
- else if (!strcmp(variant, "iso"))
- return QMediaFormat::FileFormat::MPEG4;
- } else if (!strcmp(name, "video/ogg")) {
- return QMediaFormat::FileFormat::Ogg;
- } else if (!strcmp(name, "video/webm")) {
- return QMediaFormat::FileFormat::WebM;
- } else if (!strcmp(name, "audio/x-m4a")) {
- return QMediaFormat::FileFormat::Mpeg4Audio;
- } else if (!strcmp(name, "audio/x-wav")) {
- return QMediaFormat::FileFormat::Wave;
- } else if (!strcmp(name, "audio/mpeg")) {
- auto mpegversion = structure["mpegversion"].toInt();
- if (mpegversion == 1) {
- auto layer = structure["layer"];
- if (!layer.isNull())
- return QMediaFormat::FileFormat::MP3;
- }
- }
- return QMediaFormat::UnspecifiedFormat;
-}
-
-
-QImageCapture::FileFormat QGstreamerFormatInfo::imageFormatForCaps(QGstStructure structure)
-{
- const char *name = structure.name().data();
-
- if (!strcmp(name, "image/jpeg")) {
- return QImageCapture::JPEG;
- } else if (!strcmp(name, "image/png")) {
- return QImageCapture::PNG;
- } else if (!strcmp(name, "image/webp")) {
- return QImageCapture::WebP;
- } else if (!strcmp(name, "image/webp")) {
- return QImageCapture::WebP;
- } else if (!strcmp(name, "image/tiff")) {
- return QImageCapture::Tiff;
- }
- return QImageCapture::UnspecifiedFormat;
-}
-
-static QPair<QList<QMediaFormat::AudioCodec>, QList<QMediaFormat::VideoCodec>> getCodecsList(bool decode)
-{
- QList<QMediaFormat::AudioCodec> audio;
- QList<QMediaFormat::VideoCodec> video;
-
- GstPadDirection padDirection = decode ? GST_PAD_SINK : GST_PAD_SRC;
-
- GList *elementList = gst_element_factory_list_get_elements(decode ? GST_ELEMENT_FACTORY_TYPE_DECODER : GST_ELEMENT_FACTORY_TYPE_ENCODER,
- GST_RANK_MARGINAL);
-
- GList *element = elementList;
- while (element) {
- GstElementFactory *factory = (GstElementFactory *)element->data;
- element = element->next;
-
- const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
- while (padTemplates) {
- GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
- padTemplates = padTemplates->next;
-
- if (padTemplate->direction == padDirection) {
- QGstMutableCaps caps = gst_static_caps_get(&padTemplate->static_caps);
-
- for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
- auto a = QGstreamerFormatInfo::audioCodecForCaps(structure);
- if (a != QMediaFormat::AudioCodec::Unspecified && !audio.contains(a))
- audio.append(a);
- auto v = QGstreamerFormatInfo::videoCodecForCaps(structure);
- if (v != QMediaFormat::VideoCodec::Unspecified && !video.contains(v))
- video.append(v);
- }
- }
- }
- }
- gst_plugin_feature_list_free(elementList);
- return {audio, video};
-}
-
-
-QList<QGstreamerFormatInfo::CodecMap> QGstreamerFormatInfo::getMuxerList(bool demuxer,
- QList<QMediaFormat::AudioCodec> supportedAudioCodecs,
- QList<QMediaFormat::VideoCodec> supportedVideoCodecs)
-{
- QList<QGstreamerFormatInfo::CodecMap> muxers;
-
- GstPadDirection padDirection = demuxer ? GST_PAD_SINK : GST_PAD_SRC;
-
- GList *elementList = gst_element_factory_list_get_elements(demuxer ? GST_ELEMENT_FACTORY_TYPE_DEMUXER : GST_ELEMENT_FACTORY_TYPE_MUXER,
- GST_RANK_MARGINAL);
- GList *element = elementList;
- while (element) {
- GstElementFactory *factory = (GstElementFactory *)element->data;
- element = element->next;
-
- QList<QMediaFormat::FileFormat> fileFormats;
-
- const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
- while (padTemplates) {
- GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
- padTemplates = padTemplates->next;
-
- if (padTemplate->direction == padDirection) {
- QGstMutableCaps caps = gst_static_caps_get(&padTemplate->static_caps);
-
- for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
- auto fmt = fileFormatForCaps(structure);
- if (fmt != QMediaFormat::UnspecifiedFormat)
- fileFormats.append(fmt);
- }
- }
- }
- if (fileFormats.isEmpty())
- continue;
-
- QList<QMediaFormat::AudioCodec> audioCodecs;
- QList<QMediaFormat::VideoCodec> videoCodecs;
-
- padTemplates = gst_element_factory_get_static_pad_templates(factory);
- while (padTemplates) {
- GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
- padTemplates = padTemplates->next;
-
- // check the other side for supported inputs/outputs
- if (padTemplate->direction != padDirection) {
- QGstMutableCaps caps = gst_static_caps_get(&padTemplate->static_caps);
-
- bool acceptsRawAudio = false;
- for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
- if (structure.name() == "audio/x-raw")
- acceptsRawAudio = true;
- auto audio = audioCodecForCaps(structure);
- if (audio != QMediaFormat::AudioCodec::Unspecified && supportedAudioCodecs.contains(audio))
- audioCodecs.append(audio);
- auto video = videoCodecForCaps(structure);
- if (video != QMediaFormat::VideoCodec::Unspecified && supportedVideoCodecs.contains(video))
- videoCodecs.append(video);
- }
- if (acceptsRawAudio && fileFormats.size() == 1) {
- switch (fileFormats.at(0)) {
- case QMediaFormat::Mpeg4Audio:
- default:
- break;
- case QMediaFormat::MP3:
- audioCodecs.append(QMediaFormat::AudioCodec::MP3);
- break;
- case QMediaFormat::FLAC:
- audioCodecs.append(QMediaFormat::AudioCodec::FLAC);
- break;
- case QMediaFormat::Wave:
- audioCodecs.append(QMediaFormat::AudioCodec::Wave);
- break;
- }
- }
- }
- }
- if (!audioCodecs.isEmpty() || !videoCodecs.isEmpty()) {
- for (auto f : qAsConst(fileFormats)) {
- muxers.append({f, audioCodecs, videoCodecs});
- if (f == QMediaFormat::MPEG4 && !fileFormats.contains(QMediaFormat::Mpeg4Audio)) {
- muxers.append({QMediaFormat::Mpeg4Audio, audioCodecs, {}});
- if (audioCodecs.contains(QMediaFormat::AudioCodec::AAC))
- muxers.append({QMediaFormat::AAC, { QMediaFormat::AudioCodec::AAC }, {}});
- } else if (f == QMediaFormat::WMV && !fileFormats.contains(QMediaFormat::WMA)) {
- muxers.append({QMediaFormat::WMA, audioCodecs, {}});
- }
- }
- }
- }
- gst_plugin_feature_list_free(elementList);
- return muxers;
-}
-
-static QList<QImageCapture::FileFormat> getImageFormatList()
-{
- QSet<QImageCapture::FileFormat> formats;
-
- GList *elementList = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_ENCODER,
- GST_RANK_MARGINAL);
-
- GList *element = elementList;
- while (element) {
- GstElementFactory *factory = (GstElementFactory *)element->data;
- element = element->next;
-
- const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
- while (padTemplates) {
- GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
- padTemplates = padTemplates->next;
-
- if (padTemplate->direction == GST_PAD_SRC) {
- QGstMutableCaps caps = gst_static_caps_get(&padTemplate->static_caps);
-
- for (int i = 0; i < caps.size(); i++) {
- QGstStructure structure = caps.at(i);
- auto f = QGstreamerFormatInfo::imageFormatForCaps(structure);
- if (f != QImageCapture::UnspecifiedFormat) {
-// qDebug() << structure.toString() << f;
- formats.insert(f);
- }
- }
- }
- }
- }
- gst_plugin_feature_list_free(elementList);
- return formats.values();
-}
-
-#if 0
-static void dumpAudioCodecs(const QList<QMediaFormat::AudioCodec> &codecList)
-{
- qDebug() << "Audio codecs:";
- for (const auto &c : codecList)
- qDebug() << " " << QMediaFormat::audioCodecName(c);
-}
-
-static void dumpVideoCodecs(const QList<QMediaFormat::VideoCodec> &codecList)
-{
- qDebug() << "Video codecs:";
- for (const auto &c : codecList)
- qDebug() << " " << QMediaFormat::videoCodecName(c);
-}
-
-static void dumpMuxers(const QList<QPlatformMediaFormatInfo::CodecMap> &muxerList)
-{
- for (const auto &m : muxerList) {
- qDebug() << " " << QMediaFormat::fileFormatName(m.format);
- qDebug() << " Audio";
- for (const auto &a : m.audio)
- qDebug() << " " << QMediaFormat::audioCodecName(a);
- qDebug() << " Video";
- for (const auto &v : m.video)
- qDebug() << " " << QMediaFormat::videoCodecName(v);
- }
-
-}
-#endif
-
-QGstreamerFormatInfo::QGstreamerFormatInfo()
-{
- auto codecs = getCodecsList(/*decode = */ true);
- decoders = getMuxerList(true, codecs.first, codecs.second);
-
- codecs = getCodecsList(/*decode = */ false);
- encoders = getMuxerList(/* demuxer = */false, codecs.first, codecs.second);
-// dumpAudioCodecs(codecs.first);
-// dumpVideoCodecs(codecs.second);
-// dumpMuxers(encoders);
-
- imageFormats = getImageFormatList();
-}
-
-QGstreamerFormatInfo::~QGstreamerFormatInfo() = default;
-
-QGstMutableCaps QGstreamerFormatInfo::formatCaps(const QMediaFormat &f) const
-{
- auto format = f.fileFormat();
- Q_ASSERT(format != QMediaFormat::UnspecifiedFormat);
-
- const char *capsForFormat[QMediaFormat::LastFileFormat + 1] = {
- "video/x-ms-asf", // WMV
- "video/x-msvideo", // AVI
- "video/x-matroska", // Matroska
- "video/quicktime, variant=(string)iso", // MPEG4
- "video/ogg", // Ogg
- "video/quicktime", // QuickTime
- "video/webm", // WebM
- "video/quicktime, variant=(string)iso", // Mpeg4Audio is the same is mp4...
- "video/quicktime, variant=(string)iso", // AAC is also an MP4 container
- "video/x-ms-asf", // WMA, same as WMV
- "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
- "audio/x-flac", // FLAC
- "audio/x-wav" // Wave
- };
- return gst_caps_from_string(capsForFormat[format]);
-}
-
-QGstMutableCaps QGstreamerFormatInfo::audioCaps(const QMediaFormat &f) const
-{
- auto codec = f.audioCodec();
- if (codec == QMediaFormat::AudioCodec::Unspecified)
- return nullptr;
-
- const char *capsForCodec[(int)QMediaFormat::AudioCodec::LastAudioCodec + 1] = {
- "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
- "audio/mpeg, mpegversion=(int)4", // AAC
- "audio/x-ac3", // AC3
- "audio/x-eac3", // EAC3
- "audio/x-flac", // FLAC
- "audio/x-true-hd", // DolbyTrueHD
- "audio/x-opus", // Opus
- "audio/x-vorbis", // Vorbis
- "audio/x-raw", // WAVE
- "audio/x-wma", // WMA
- "audio/x-alac", // ALAC
- };
- return gst_caps_from_string(capsForCodec[(int)codec]);
-}
-
-QGstMutableCaps QGstreamerFormatInfo::videoCaps(const QMediaFormat &f) const
-{
- auto codec = f.videoCodec();
- if (codec == QMediaFormat::VideoCodec::Unspecified)
- return nullptr;
-
- const char *capsForCodec[(int)QMediaFormat::VideoCodec::LastVideoCodec + 1] = {
- "video/mpeg, mpegversion=(int)1", // MPEG1,
- "video/mpeg, mpegversion=(int)2", // MPEG2,
- "video/mpeg, mpegversion=(int)4", // MPEG4,
- "video/x-h264", // H264,
- "video/x-h265", // H265,
- "video/x-vp8", // VP8,
- "video/x-vp9", // VP9,
- "video/x-av1", // AV1,
- "video/x-theora", // Theora,
- "audio/x-wmv", // WMV
- "video/x-jpeg", // MotionJPEG,
- };
- return gst_caps_from_string(capsForCodec[(int)codec]);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/qgstreamerformatinfo_p.h b/src/multimedia/platform/gstreamer/qgstreamerformatinfo_p.h
deleted file mode 100644
index f8de964e4..000000000
--- a/src/multimedia/platform/gstreamer/qgstreamerformatinfo_p.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERFORMATINFO_H
-#define QGSTREAMERFORMATINFO_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaformatinfo_p.h>
-#include <qhash.h>
-#include <qlist.h>
-#include <private/qgstutils_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerFormatInfo : public QPlatformMediaFormatInfo
-{
-public:
- QGstreamerFormatInfo();
- ~QGstreamerFormatInfo();
-
- QGstMutableCaps formatCaps(const QMediaFormat &f) const;
- QGstMutableCaps audioCaps(const QMediaFormat &f) const;
- QGstMutableCaps 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);
-
- QList<CodecMap> getMuxerList(bool demuxer, QList<QMediaFormat::AudioCodec> audioCodecs, QList<QMediaFormat::VideoCodec> videoCodecs);
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/qgstreamerintegration.cpp b/src/multimedia/platform/gstreamer/qgstreamerintegration.cpp
deleted file mode 100644
index 6f28fe42d..000000000
--- a/src/multimedia/platform/gstreamer/qgstreamerintegration.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamerintegration_p.h"
-#include "qgstreamermediadevices_p.h"
-#include "private/qgstreamermediaplayer_p.h"
-#include "private/qgstreamermediacapture_p.h"
-#include "private/qgstreameraudiodecoder_p.h"
-#include "private/qgstreamercamera_p.h"
-#include "private/qgstreamermediaencoder_p.h"
-#include "private/qgstreamerimagecapture_p.h"
-#include "private/qgstreamerformatinfo_p.h"
-#include "private/qgstreamervideosink_p.h"
-#include "private/qgstreameraudioinput_p.h"
-#include "private/qgstreameraudiooutput_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QGstreamerIntegration::QGstreamerIntegration()
-{
- gst_init(nullptr, nullptr);
- m_devices = new QGstreamerMediaDevices();
- m_formatsInfo = new QGstreamerFormatInfo();
-}
-
-QGstreamerIntegration::~QGstreamerIntegration()
-{
- delete m_devices;
- delete m_formatsInfo;
-}
-
-QPlatformMediaDevices *QGstreamerIntegration::devices()
-{
- return m_devices;
-}
-
-QPlatformMediaFormatInfo *QGstreamerIntegration::formatInfo()
-{
- return m_formatsInfo;
-}
-
-QPlatformAudioDecoder *QGstreamerIntegration::createAudioDecoder(QAudioDecoder *decoder)
-{
- return new QGstreamerAudioDecoder(decoder);
-}
-
-QPlatformMediaCaptureSession *QGstreamerIntegration::createCaptureSession()
-{
- return new QGstreamerMediaCapture();
-}
-
-QPlatformMediaPlayer *QGstreamerIntegration::createPlayer(QMediaPlayer *player)
-{
- return new QGstreamerMediaPlayer(player);
-}
-
-QPlatformCamera *QGstreamerIntegration::createCamera(QCamera *camera)
-{
- return new QGstreamerCamera(camera);
-}
-
-QPlatformMediaEncoder *QGstreamerIntegration::createEncoder(QMediaRecorder *encoder)
-{
- return new QGstreamerMediaEncoder(encoder);
-}
-
-QPlatformImageCapture *QGstreamerIntegration::createImageCapture(QImageCapture *imageCapture)
-{
- return new QGstreamerImageCapture(imageCapture);
-}
-
-QPlatformVideoSink *QGstreamerIntegration::createVideoSink(QVideoSink *sink)
-{
- return new QGstreamerVideoSink(sink);
-}
-
-QPlatformAudioInput *QGstreamerIntegration::createAudioInput(QAudioInput *q)
-{
- return new QGstreamerAudioInput(q);
-}
-
-QPlatformAudioOutput *QGstreamerIntegration::createAudioOutput(QAudioOutput *q)
-{
- return new QGstreamerAudioOutput(q);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/qgstreamerintegration_p.h b/src/multimedia/platform/gstreamer/qgstreamerintegration_p.h
deleted file mode 100644
index 14167e750..000000000
--- a/src/multimedia/platform/gstreamer/qgstreamerintegration_p.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERINTEGRATION_H
-#define QGSTREAMERINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerMediaDevices;
-class QGstreamerPlayerInterface;
-class QGstreamerFormatInfo;
-
-class QGstreamerIntegration : public QPlatformMediaIntegration
-{
-public:
- QGstreamerIntegration();
- ~QGstreamerIntegration();
-
- static QGstreamerIntegration *instance() { return static_cast<QGstreamerIntegration *>(QPlatformMediaIntegration::instance()); }
- QPlatformMediaDevices *devices() override;
- QPlatformMediaFormatInfo *formatInfo() override;
-
- QPlatformAudioDecoder *createAudioDecoder(QAudioDecoder *decoder) override;
- QPlatformMediaCaptureSession *createCaptureSession() override;
- QPlatformMediaPlayer *createPlayer(QMediaPlayer *player) override;
- QPlatformCamera *createCamera(QCamera *) override;
- QPlatformMediaEncoder *createEncoder(QMediaRecorder *) override;
- QPlatformImageCapture *createImageCapture(QImageCapture *) override;
-
- QPlatformVideoSink *createVideoSink(QVideoSink *sink) override;
-
- QPlatformAudioInput *createAudioInput(QAudioInput *) override;
- QPlatformAudioOutput *createAudioOutput(QAudioOutput *) override;
-
- QGstreamerMediaDevices *m_devices = nullptr;
- QGstreamerFormatInfo *m_formatsInfo = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/qgstreamermediadevices.cpp b/src/multimedia/platform/gstreamer/qgstreamermediadevices.cpp
deleted file mode 100644
index f66329f5e..000000000
--- a/src/multimedia/platform/gstreamer/qgstreamermediadevices.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstreamermediadevices_p.h"
-#include "qmediadevices.h"
-#include "qcameradevice_p.h"
-
-#include "private/qgstreameraudiosource_p.h"
-#include "private/qgstreameraudiosink_p.h"
-#include "private/qgstreameraudiodevice_p.h"
-#include "private/qgstutils_p.h"
-
-QT_BEGIN_NAMESPACE
-
-static gboolean deviceMonitor(GstBus *, GstMessage *message, gpointer m)
-{
- QGstreamerMediaDevices *manager = static_cast<QGstreamerMediaDevices *>(m);
- GstDevice *device = nullptr;
-
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_DEVICE_ADDED:
- gst_message_parse_device_added(message, &device);
- manager->addDevice(device);
- break;
- case GST_MESSAGE_DEVICE_REMOVED:
- gst_message_parse_device_removed(message, &device);
- manager->removeDevice(device);
- break;
- default:
- break;
- }
- if (device)
- gst_object_unref (device);
-
- return G_SOURCE_CONTINUE;
-}
-
-QGstreamerMediaDevices::QGstreamerMediaDevices()
- : QPlatformMediaDevices()
-{
- GstDeviceMonitor *monitor;
- GstBus *bus;
-
- monitor = gst_device_monitor_new();
-
- gst_device_monitor_add_filter (monitor, "Video/Source", nullptr);
- gst_device_monitor_add_filter (monitor, "Audio/Source", nullptr);
- gst_device_monitor_add_filter (monitor, "Audio/Sink", nullptr);
-
- bus = gst_device_monitor_get_bus(monitor);
- gst_bus_add_watch(bus, deviceMonitor, this);
- gst_object_unref(bus);
-
- gst_device_monitor_start(monitor);
-
- auto devices = gst_device_monitor_get_devices(monitor);
-
- while (devices) {
- GstDevice *device = static_cast<GstDevice *>(devices->data);
- addDevice(device);
- gst_object_unref(device);
- devices = g_list_delete_link(devices, devices);
- }
-}
-
-static QList<QAudioDevice> devicesFromSet(const QSet<GstDevice *> &deviceSet, QAudioDevice::Mode mode)
-{
- QList<QAudioDevice> devices;
- for (auto *d : deviceSet) {
- auto *properties = gst_device_get_properties(d);
- if (properties) {
- auto *klass = gst_structure_get_string(properties, "device.class");
- if (qstrcmp(klass, "monitor")) {
- auto *name = gst_structure_get_string(properties, "sysfs.path");
- gboolean def;
- auto *info = new QGStreamerAudioDeviceInfo(d, name, mode);
- if (gst_structure_get_boolean(properties, "is-default", &def) && def)
- devices.prepend(info->create());
- else
- devices.append(info->create());
- }
-
- gst_structure_free(properties);
- }
- }
- return devices;
-};
-
-QList<QAudioDevice> QGstreamerMediaDevices::audioInputs() const
-{
- return devicesFromSet(m_audioSources, QAudioDevice::Input);
-}
-
-QList<QAudioDevice> QGstreamerMediaDevices::audioOutputs() const
-{
- return devicesFromSet(m_audioSinks, QAudioDevice::Output);
-}
-
-QList<QCameraDevice> QGstreamerMediaDevices::videoInputs() const
-{
- QList<QCameraDevice> devices;
-
- for (auto *d : qAsConst(m_videoSources)) {
- QGstStructure properties = gst_device_get_properties(d);
- if (!properties.isNull()) {
- QCameraDevicePrivate *info = new QCameraDevicePrivate;
- auto *desc = gst_device_get_display_name(d);
- info->description = QString::fromUtf8(desc);
- g_free(desc);
-
- info->id = properties["device.path"].toString();
- auto def = properties["is-default"].toBool();
- info->isDefault = def && *def;
- if (def)
- devices.prepend(info->create());
- else
- devices.append(info->create());
- properties.free();
- QGstCaps caps = gst_device_get_caps(d);
- if (!caps.isNull()) {
- QList<QCameraFormat> formats;
- QSet<QSize> photoResolutions;
-
- int size = caps.size();
- for (int i = 0; i < size; ++i) {
- auto cap = caps.at(i);
-
- QSize resolution = cap.resolution();
- if (!resolution.isValid())
- continue;
-
- auto pixelFormat = cap.pixelFormat();
- auto frameRate = cap.frameRateRange();
-
- auto *f = new QCameraFormatPrivate{
- QSharedData(),
- pixelFormat,
- resolution,
- frameRate.min,
- frameRate.max
- };
- formats << f->create();
- photoResolutions.insert(resolution);
- }
- info->videoFormats = formats;
- // ### sort resolutions?
- info->photoResolutions = photoResolutions.values();
- }
- }
- }
- return devices;
-}
-
-QPlatformAudioSource *QGstreamerMediaDevices::createAudioSource(const QAudioDevice &deviceInfo)
-{
- return new QGStreamerAudioSource(deviceInfo);
-}
-
-QPlatformAudioSink *QGstreamerMediaDevices::createAudioSink(const QAudioDevice &deviceInfo)
-{
- return new QGStreamerAudioSink(deviceInfo);
-}
-
-void QGstreamerMediaDevices::addDevice(GstDevice *device)
-{
- gchar *type = gst_device_get_device_class(device);
-// qDebug() << "adding device:" << device << type << gst_device_get_display_name(device) << gst_structure_to_string(gst_device_get_properties(device));
- gst_object_ref(device);
- if (!strcmp(type, "Video/Source")) {
- m_videoSources.insert(device);
- videoInputsChanged();
- } else if (!strcmp(type, "Audio/Source")) {
- m_audioSources.insert(device);
- audioInputsChanged();
- } else if (!strcmp(type, "Audio/Sink")) {
- m_audioSinks.insert(device);
- audioOutputsChanged();
- } else {
- gst_object_unref(device);
- }
- g_free(type);
-}
-
-void QGstreamerMediaDevices::removeDevice(GstDevice *device)
-{
-// qDebug() << "removing device:" << device << gst_device_get_display_name(device);
- if (m_videoSources.remove(device)) {
- videoInputsChanged();
- } else if (m_audioSources.remove(device)) {
- audioInputsChanged();
- } else if (m_audioSinks.remove(device)) {
- audioOutputsChanged();
- }
-
- gst_object_unref(device);
-}
-
-static GstDevice *getDevice(const QSet<GstDevice *> &devices, const char *key, const QByteArray &id)
-{
- GstDevice *gstDevice = nullptr;
- for (auto *d : devices) {
- QGstStructure properties = gst_device_get_properties(d);
- if (!properties.isNull()) {
- auto *name = properties[key].toString();
- if (id == name) {
- gstDevice = d;
- }
- }
- properties.free();
- if (gstDevice)
- break;
- }
- return gstDevice;
-
-}
-
-GstDevice *QGstreamerMediaDevices::audioDevice(const QByteArray &id, QAudioDevice::Mode mode) const
-{
- const auto devices = (mode == QAudioDevice::Output) ? m_audioSinks : m_audioSources;
-
- return getDevice(devices, "sysfs.path", id);
-}
-
-GstDevice *QGstreamerMediaDevices::videoDevice(const QByteArray &id) const
-{
- return getDevice(m_videoSources, "device.path", id);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/qgstreamermediadevices_p.h b/src/multimedia/platform/gstreamer/qgstreamermediadevices_p.h
deleted file mode 100644
index e3f34433f..000000000
--- a/src/multimedia/platform/gstreamer/qgstreamermediadevices_p.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTREAMERMEDIADEVICES_H
-#define QGSTREAMERMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <gst/gst.h>
-#include <qset.h>
-#include <qaudiodevice.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstreamerMediaDevices : public QPlatformMediaDevices
-{
-public:
- QGstreamerMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) override;
-
- void addDevice(GstDevice *);
- void removeDevice(GstDevice *);
-
- GstDevice *audioDevice(const QByteArray &id, QAudioDevice::Mode mode) const;
- GstDevice *videoDevice(const QByteArray &id) const;
-
-private:
- QSet<GstDevice *> m_videoSources;
- QSet<GstDevice *> m_audioSources;
- QSet<GstDevice *> m_audioSinks;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/pulseaudio/qaudioengine_pulse.cpp b/src/multimedia/platform/pulseaudio/qaudioengine_pulse.cpp
deleted file mode 100644
index 53ffffe53..000000000
--- a/src/multimedia/platform/pulseaudio/qaudioengine_pulse.cpp
+++ /dev/null
@@ -1,479 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qdebug.h>
-
-#include <qaudiodevice.h>
-#include <QTimer>
-#include "qaudioengine_pulse_p.h"
-#include "qpulseaudiodevice_p.h"
-#include "qpulsehelpers_p.h"
-#include <sys/types.h>
-#include <unistd.h>
-
-QT_BEGIN_NAMESPACE
-
-static void serverInfoCallback(pa_context *context, const pa_server_info *info, void *userdata)
-{
- if (!info) {
- qWarning() << QString::fromLatin1("Failed to get server information: %s").arg(QString::fromUtf8(pa_strerror(pa_context_errno(context))));
- return;
- }
-
-#ifdef DEBUG_PULSE
- char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
-
- pa_sample_spec_snprint(ss, sizeof(ss), &info->sample_spec);
- pa_channel_map_snprint(cm, sizeof(cm), &info->channel_map);
-
- qDebug() << QString("User name: %1\n"
- "Host Name: %2\n"
- "Server Name: %3\n"
- "Server Version: %4\n"
- "Default Sample Specification: %5\n"
- "Default Channel Map: %6\n"
- "Default Sink: %7\n"
- "Default Source: %8\n").arg(
- info->user_name,
- info->host_name,
- info->server_name,
- info->server_version,
- ss,
- cm,
- info->default_sink_name,
- info->default_source_name);
-#endif
-
- QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
- pulseEngine->m_serverLock.lockForWrite();
- pulseEngine->m_defaultSink = info->default_sink_name;
- pulseEngine->m_defaultSource = info->default_source_name;
- // ### ensure the QAudioDevices are updated if default changes and emit changed signal in the device manager
- pulseEngine->m_serverLock.unlock();
-
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
-}
-
-static void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int isLast, void *userdata)
-{
- QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
-
- if (isLast < 0) {
- qWarning() << QString::fromLatin1("Failed to get sink information: %s").arg(QString::fromUtf8(pa_strerror(pa_context_errno(context))));
- return;
- }
-
- if (isLast) {
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
- return;
- }
-
- Q_ASSERT(info);
-
-#ifdef DEBUG_PULSE
- QMap<pa_sink_state, QString> stateMap;
- stateMap[PA_SINK_INVALID_STATE] = "n/a";
- stateMap[PA_SINK_RUNNING] = "RUNNING";
- stateMap[PA_SINK_IDLE] = "IDLE";
- stateMap[PA_SINK_SUSPENDED] = "SUSPENDED";
-
- qDebug() << QString("Sink #%1\n"
- "\tState: %2\n"
- "\tName: %3\n"
- "\tDescription: %4\n"
- ).arg(QString::number(info->index),
- stateMap.value(info->state),
- info->name,
- info->description);
-#endif
-
- QWriteLocker locker(&pulseEngine->m_sinkLock);
- bool isDefault = pulseEngine->m_defaultSink == info->name;
- auto *dinfo = new QPulseAudioDeviceInfo(info->name, info->description, isDefault, QAudioDevice::Output);
- pulseEngine->m_sinks.insert(info->index, dinfo->create());
-}
-
-static void sourceInfoCallback(pa_context *context, const pa_source_info *info, int isLast, void *userdata)
-{
- Q_UNUSED(context);
- QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
-
- if (isLast) {
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
- return;
- }
-
- Q_ASSERT(info);
-
-#ifdef DEBUG_PULSE
- QMap<pa_source_state, QString> stateMap;
- stateMap[PA_SOURCE_INVALID_STATE] = "n/a";
- stateMap[PA_SOURCE_RUNNING] = "RUNNING";
- stateMap[PA_SOURCE_IDLE] = "IDLE";
- stateMap[PA_SOURCE_SUSPENDED] = "SUSPENDED";
-
- qDebug() << QString("Source #%1\n"
- "\tState: %2\n"
- "\tName: %3\n"
- "\tDescription: %4\n"
- ).arg(QString::number(info->index),
- stateMap.value(info->state),
- info->name,
- info->description);
-#endif
-
- QWriteLocker locker(&pulseEngine->m_sourceLock);
- // skip monitor channels
- if (info->monitor_of_sink != PA_INVALID_INDEX)
- return;
- bool isDefault = pulseEngine->m_defaultSink == info->name;
- auto *dinfo = new QPulseAudioDeviceInfo(info->name, info->description, isDefault, QAudioDevice::Input);
- pulseEngine->m_sources.insert(info->index, dinfo->create());
-}
-
-static void event_cb(pa_context* context, pa_subscription_event_type_t t, uint32_t index, void* userdata)
-{
- QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
-
- int type = t & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
- int facility = t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
-
- switch (type) {
- case PA_SUBSCRIPTION_EVENT_NEW:
- case PA_SUBSCRIPTION_EVENT_CHANGE:
- switch (facility) {
- case PA_SUBSCRIPTION_EVENT_SERVER: {
- pa_operation *op = pa_context_get_server_info(context, serverInfoCallback, userdata);
- if (op)
- pa_operation_unref(op);
- else
- qWarning("PulseAudioService: failed to get server info");
- break;
- }
- case PA_SUBSCRIPTION_EVENT_SINK: {
- pa_operation *op = pa_context_get_sink_info_by_index(context, index, sinkInfoCallback, userdata);
- if (op)
- pa_operation_unref(op);
- else
- qWarning("PulseAudioService: failed to get sink info");
- break;
- }
- case PA_SUBSCRIPTION_EVENT_SOURCE: {
- pa_operation *op = pa_context_get_source_info_by_index(context, index, sourceInfoCallback, userdata);
- if (op)
- pa_operation_unref(op);
- else
- qWarning("PulseAudioService: failed to get source info");
- break;
- }
- default:
- break;
- }
- break;
- case PA_SUBSCRIPTION_EVENT_REMOVE:
- switch (facility) {
- case PA_SUBSCRIPTION_EVENT_SINK:
- pulseEngine->m_sinkLock.lockForWrite();
- pulseEngine->m_sinks.remove(index);
- pulseEngine->m_sinkLock.unlock();
- break;
- case PA_SUBSCRIPTION_EVENT_SOURCE:
- pulseEngine->m_sourceLock.lockForWrite();
- pulseEngine->m_sources.remove(index);
- pulseEngine->m_sourceLock.unlock();
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-}
-
-static void contextStateCallbackInit(pa_context *context, void *userdata)
-{
- Q_UNUSED(context);
-#ifdef DEBUG_PULSE
- qDebug() << QPulseAudioInternal::stateToQString(pa_context_get_state(context));
-#endif
- QPulseAudioEngine *pulseEngine = reinterpret_cast<QPulseAudioEngine*>(userdata);
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
-}
-
-static void contextStateCallback(pa_context *c, void *userdata)
-{
- QPulseAudioEngine *self = reinterpret_cast<QPulseAudioEngine*>(userdata);
- pa_context_state_t state = pa_context_get_state(c);
-
-#ifdef DEBUG_PULSE
- qDebug() << QPulseAudioInternal::stateToQString(state);
-#endif
-
- if (state == PA_CONTEXT_FAILED)
- QMetaObject::invokeMethod(self, "onContextFailed", Qt::QueuedConnection);
-}
-
-Q_GLOBAL_STATIC(QPulseAudioEngine, pulseEngine);
-
-QPulseAudioEngine::QPulseAudioEngine(QObject *parent)
- : QObject(parent)
- , m_mainLoopApi(nullptr)
- , m_context(nullptr)
- , m_prepared(false)
-{
- prepare();
-}
-
-QPulseAudioEngine::~QPulseAudioEngine()
-{
- if (m_prepared)
- release();
-}
-
-void QPulseAudioEngine::prepare()
-{
- bool keepGoing = true;
- bool ok = true;
-
- m_mainLoop = pa_threaded_mainloop_new();
- if (m_mainLoop == nullptr) {
- qWarning("PulseAudioService: unable to create pulseaudio mainloop");
- return;
- }
-
- if (pa_threaded_mainloop_start(m_mainLoop) != 0) {
- qWarning("PulseAudioService: unable to start pulseaudio mainloop");
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- return;
- }
-
- m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop);
-
- lock();
-
- m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtPulseAudio:%1")).arg(::getpid()).toLatin1().constData());
-
- if (m_context == nullptr) {
- qWarning("PulseAudioService: Unable to create new pulseaudio context");
- pa_threaded_mainloop_unlock(m_mainLoop);
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- onContextFailed();
- return;
- }
-
- pa_context_set_state_callback(m_context, contextStateCallbackInit, this);
-
- if (pa_context_connect(m_context, nullptr, (pa_context_flags_t)0, nullptr) < 0) {
- qWarning("PulseAudioService: pa_context_connect() failed");
- pa_context_unref(m_context);
- pa_threaded_mainloop_unlock(m_mainLoop);
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- m_context = nullptr;
- return;
- }
-
- pa_threaded_mainloop_wait(m_mainLoop);
-
- while (keepGoing) {
- switch (pa_context_get_state(m_context)) {
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- break;
-
- case PA_CONTEXT_READY:
-#ifdef DEBUG_PULSE
- qDebug("Connection established.");
-#endif
- keepGoing = false;
- break;
-
- case PA_CONTEXT_TERMINATED:
- qCritical("PulseAudioService: Context terminated.");
- keepGoing = false;
- ok = false;
- break;
-
- case PA_CONTEXT_FAILED:
- default:
- qCritical() << QString::fromLatin1("PulseAudioService: Connection failure: %1")
- .arg(QString::fromUtf8(pa_strerror(pa_context_errno(m_context))));
- keepGoing = false;
- ok = false;
- }
-
- if (keepGoing)
- pa_threaded_mainloop_wait(m_mainLoop);
- }
-
- if (ok) {
- pa_context_set_state_callback(m_context, contextStateCallback, this);
-
- pa_context_set_subscribe_callback(m_context, event_cb, this);
- pa_operation *op = pa_context_subscribe(m_context,
- pa_subscription_mask_t(PA_SUBSCRIPTION_MASK_SINK |
- PA_SUBSCRIPTION_MASK_SOURCE |
- PA_SUBSCRIPTION_MASK_SERVER),
- nullptr, nullptr);
- if (op)
- pa_operation_unref(op);
- else
- qWarning("PulseAudioService: failed to subscribe to context notifications");
- } else {
- pa_context_unref(m_context);
- m_context = nullptr;
- }
-
- unlock();
-
- if (ok) {
- updateDevices();
- m_prepared = true;
- } else {
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- onContextFailed();
- }
-}
-
-void QPulseAudioEngine::release()
-{
- if (!m_prepared)
- return;
-
- if (m_context) {
- pa_context_disconnect(m_context);
- pa_context_unref(m_context);
- m_context = nullptr;
- }
-
- if (m_mainLoop) {
- pa_threaded_mainloop_stop(m_mainLoop);
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- }
-
- m_prepared = false;
-}
-
-void QPulseAudioEngine::updateDevices()
-{
- lock();
-
- // Get default input and output devices
- pa_operation *operation = pa_context_get_server_info(m_context, serverInfoCallback, this);
- if (operation) {
- while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(m_mainLoop);
- pa_operation_unref(operation);
- } else {
- qWarning("PulseAudioService: failed to get server info");
- }
-
- // Get output devices
- operation = pa_context_get_sink_info_list(m_context, sinkInfoCallback, this);
- if (operation) {
- while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(m_mainLoop);
- pa_operation_unref(operation);
- } else {
- qWarning("PulseAudioService: failed to get sink info");
- }
-
- // Get input devices
- operation = pa_context_get_source_info_list(m_context, sourceInfoCallback, this);
- if (operation) {
- while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(m_mainLoop);
- pa_operation_unref(operation);
- } else {
- qWarning("PulseAudioService: failed to get source info");
- }
-
- unlock();
-}
-
-void QPulseAudioEngine::onContextFailed()
-{
- // Give a chance to the connected slots to still use the Pulse main loop before releasing it.
- emit contextFailed();
-
- release();
-
- // Try to reconnect later
- QTimer::singleShot(3000, this, SLOT(prepare()));
-}
-
-QPulseAudioEngine *QPulseAudioEngine::instance()
-{
- return pulseEngine();
-}
-
-QList<QAudioDevice> QPulseAudioEngine::availableDevices(QAudioDevice::Mode mode) const
-{
- QList<QAudioDevice> devices;
- QByteArray defaultDevice;
-
- m_serverLock.lockForRead();
-
- if (mode == QAudioDevice::Output) {
- QReadLocker locker(&m_sinkLock);
- devices = m_sinks.values();
- defaultDevice = m_defaultSink;
- } else {
- QReadLocker locker(&m_sourceLock);
- devices = m_sources.values();
- defaultDevice = m_defaultSource;
- }
-
- m_serverLock.unlock();
-
- return devices;
-}
-
-QByteArray QPulseAudioEngine::defaultDevice(QAudioDevice::Mode mode) const
-{
- return (mode == QAudioDevice::Output) ? m_defaultSink : m_defaultSource;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiodevice.cpp b/src/multimedia/platform/pulseaudio/qpulseaudiodevice.cpp
deleted file mode 100644
index df161ab18..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiodevice.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qpulseaudiodevice_p.h"
-#include "qaudioengine_pulse_p.h"
-#include "qpulsehelpers_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QPulseAudioDeviceInfo::QPulseAudioDeviceInfo(const char *device, const char *desc, bool isDef, QAudioDevice::Mode mode)
- : QAudioDevicePrivate(device, mode)
-{
- description = QString::fromUtf8(desc);
- isDefault = isDef;
-
- minimumChannelCount = 1;
- maximumChannelCount = PA_CHANNELS_MAX;
- minimumSampleRate = 1;
- maximumSampleRate = PA_RATE_MAX;
-
- constexpr bool isBigEndian = QSysInfo::ByteOrder == QSysInfo::BigEndian;
-
- const struct {
- pa_sample_format pa_fmt;
- QAudioFormat::SampleFormat qt_fmt;
- } formatMap[] = {
- { PA_SAMPLE_U8, QAudioFormat::UInt8 },
- { isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE, QAudioFormat::Int16 },
- { isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE, QAudioFormat::Int32 },
- { isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE, QAudioFormat::Float },
- };
-
- pa_sample_spec spec;
- spec.channels = 1;
- spec.rate = 48000;
-
- for (const auto &f : formatMap) {
- spec.format = f.pa_fmt;
- if (pa_sample_spec_valid(&spec) != 0)
- supportedSampleFormats.append(f.qt_fmt);
- }
-
- preferredFormat.setChannelCount(2);
- preferredFormat.setSampleRate(48000);
- QAudioFormat::SampleFormat f = QAudioFormat::Int16;
- if (!supportedSampleFormats.contains(f))
- f = supportedSampleFormats.value(0, QAudioFormat::Unknown);
- preferredFormat.setSampleFormat(f);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiodevice_p.h b/src/multimedia/platform/pulseaudio/qpulseaudiodevice_p.h
deleted file mode 100644
index 111134614..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiodevice_p.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QAUDIODEVICEINFOPULSE_H
-#define QAUDIODEVICEINFOPULSE_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/qbytearray.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qlist.h>
-
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiosystem_p.h>
-#include <private/qaudiodevice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QPulseAudioDeviceInfo : public QAudioDevicePrivate
-{
-public:
- QPulseAudioDeviceInfo(const char *device, const char *description, bool isDefault, QAudioDevice::Mode mode);
- ~QPulseAudioDeviceInfo() {}
-};
-
-QT_END_NAMESPACE
-
-#endif
-
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiointegration.cpp b/src/multimedia/platform/pulseaudio/qpulseaudiointegration.cpp
deleted file mode 100644
index f68f2934a..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiointegration.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qpulseaudiointegration_p.h"
-#include "qpulseaudiomediadevices_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QPulseAudioIntegration::QPulseAudioIntegration()
-{
- pulseEngine = new QPulseAudioEngine;
-}
-
-QPulseAudioIntegration::~QPulseAudioIntegration()
-{
- delete m_devices;
-}
-
-QPlatformMediaDevices *QPulseAudioIntegration::devices()
-{
- if (!m_devices)
- m_devices = new QPulseAudioMediaDevices(pulseEngine);
- return m_devices;
-}
-
-QPlatformMediaFormatInfo *QPulseAudioIntegration::formatInfo()
-{
- Q_ASSERT(!"In need of implementation"); // TODO
- return nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiointegration_p.h b/src/multimedia/platform/pulseaudio/qpulseaudiointegration_p.h
deleted file mode 100644
index eb83e6856..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiointegration_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QPULSEAUDIOINTEGRATION_H
-#define QPULSEAUDIOINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-#include <private/qaudioengine_pulse_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QPulseAudioMediaDevices;
-
-class QPulseAudioIntegration : public QPlatformMediaIntegration
-{
-public:
- QPulseAudioIntegration();
- ~QPulseAudioIntegration();
-
- QPlatformMediaDevices *devices() override;
- QPlatformMediaFormatInfo *formatInfo() override;
-
- QPulseAudioMediaDevices *m_devices = nullptr;
- QPulseAudioEngine *pulseEngine = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiomediadevices.cpp b/src/multimedia/platform/pulseaudio/qpulseaudiomediadevices.cpp
deleted file mode 100644
index 4c3c561b4..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiomediadevices.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qpulseaudiomediadevices_p.h"
-#include "qmediadevices.h"
-#include "qcameradevice_p.h"
-
-#include "private/qpulseaudiosource_p.h"
-#include "private/qpulseaudiosink_p.h"
-#include "private/qpulseaudiodevice_p.h"
-#include "private/qaudioengine_pulse_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QPulseAudioMediaDevices::QPulseAudioMediaDevices(QPulseAudioEngine *engine)
- : QPlatformMediaDevices(),
- pulseEngine(engine)
-{
-}
-
-QList<QAudioDevice> QPulseAudioMediaDevices::audioInputs() const
-{
- return pulseEngine->availableDevices(QAudioDevice::Input);
-}
-
-QList<QAudioDevice> QPulseAudioMediaDevices::audioOutputs() const
-{
- return pulseEngine->availableDevices(QAudioDevice::Output);
-}
-
-QList<QCameraDevice> QPulseAudioMediaDevices::videoInputs() const
-{
- return {};
-}
-
-QPlatformAudioSource *QPulseAudioMediaDevices::createAudioSource(const QAudioDevice &deviceInfo)
-{
- return new QPulseAudioSource(deviceInfo.id());
-}
-
-QPlatformAudioSink *QPulseAudioMediaDevices::createAudioSink(const QAudioDevice &deviceInfo)
-{
- return new QPulseAudioSink(deviceInfo.id());
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiomediadevices_p.h b/src/multimedia/platform/pulseaudio/qpulseaudiomediadevices_p.h
deleted file mode 100644
index 4cb28056f..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiomediadevices_p.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QPULSEAUDIOMEDIADEVICES_H
-#define QPULSEAUDIOMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <qset.h>
-#include <qaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-class QPulseAudioEngine;
-
-class QPulseAudioMediaDevices : public QPlatformMediaDevices
-{
-public:
- QPulseAudioMediaDevices(QPulseAudioEngine *engine);
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) override;
-
-private:
- QPulseAudioEngine *pulseEngine;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiosink.cpp b/src/multimedia/platform/pulseaudio/qpulseaudiosink.cpp
deleted file mode 100644
index 87779e5a7..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiosink.cpp
+++ /dev/null
@@ -1,709 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <private/qaudiohelpers_p.h>
-
-#include "qpulseaudiosink_p.h"
-#include "qpulseaudiodevice_p.h"
-#include "qaudioengine_pulse_p.h"
-#include "qpulsehelpers_p.h"
-#include <sys/types.h>
-#include <unistd.h>
-
-QT_BEGIN_NAMESPACE
-
-const int PeriodTimeMs = 20;
-const int LowLatencyPeriodTimeMs = 10;
-const int LowLatencyBufferSizeMs = 40;
-
-#define LOW_LATENCY_CATEGORY_NAME "game"
-
-static void outputStreamWriteCallback(pa_stream *stream, size_t length, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(length);
- Q_UNUSED(userdata);
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
-}
-
-static void outputStreamStateCallback(pa_stream *stream, void *userdata)
-{
- Q_UNUSED(userdata);
- pa_stream_state_t state = pa_stream_get_state(stream);
-#ifdef DEBUG_PULSE
- qDebug() << "Stream state: " << QPulseAudioInternal::stateToQString(state);
-#endif
- switch (state) {
- case PA_STREAM_CREATING:
- case PA_STREAM_READY:
- case PA_STREAM_TERMINATED:
- break;
-
- case PA_STREAM_FAILED:
- default:
- qWarning() << QString::fromLatin1("Stream error: %1").arg(QString::fromUtf8(pa_strerror(pa_context_errno(pa_stream_get_context(stream)))));
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
- break;
- }
-}
-
-static void outputStreamUnderflowCallback(pa_stream *stream, void *userdata)
-{
- Q_UNUSED(stream);
- ((QPulseAudioSink*)userdata)->streamUnderflowCallback();
-}
-
-static void outputStreamOverflowCallback(pa_stream *stream, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(userdata);
- qWarning() << "Got a buffer overflow!";
-}
-
-static void outputStreamLatencyCallback(pa_stream *stream, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(userdata);
-
-#ifdef DEBUG_PULSE
- const pa_timing_info *info = pa_stream_get_timing_info(stream);
-
- qDebug() << "Write index corrupt: " << info->write_index_corrupt;
- qDebug() << "Write index: " << info->write_index;
- qDebug() << "Read index corrupt: " << info->read_index_corrupt;
- qDebug() << "Read index: " << info->read_index;
- qDebug() << "Sink usec: " << info->sink_usec;
- qDebug() << "Configured sink usec: " << info->configured_sink_usec;
-#endif
-}
-
-static void outputStreamSuccessCallback(pa_stream *stream, int success, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(success);
- Q_UNUSED(userdata);
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
-}
-
-static void outputStreamDrainComplete(pa_stream *stream, int success, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(success);
- Q_UNUSED(userdata);
-
-#ifdef DEBUG_PULSE
- qDebug() << "Draining completed successfully: " << (bool)success;
-#endif
-}
-
-static void streamAdjustPrebufferCallback(pa_stream *stream, int success, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(success);
- Q_UNUSED(userdata);
-
-#ifdef DEBUG_PULSE
- qDebug() << "Adjust prebuffer completed successfully: " << (bool)success;
-#endif
-}
-
-
-QPulseAudioSink::QPulseAudioSink(const QByteArray &device)
- : m_device(device)
- , m_errorState(QAudio::NoError)
- , m_deviceState(QAudio::StoppedState)
- , m_pullMode(true)
- , m_opened(false)
- , m_audioSource(nullptr)
- , m_periodTime(0)
- , m_stream(nullptr)
- , m_periodSize(0)
- , m_bufferSize(0)
- , m_maxBufferSize(0)
- , m_totalTimeValue(0)
- , m_tickTimer(new QTimer(this))
- , m_audioBuffer(nullptr)
- , m_resuming(false)
- , m_volume(1.0)
-{
- connect(m_tickTimer, SIGNAL(timeout()), SLOT(userFeed()));
-}
-
-QPulseAudioSink::~QPulseAudioSink()
-{
- close();
- disconnect(m_tickTimer, SIGNAL(timeout()));
- QCoreApplication::processEvents();
-}
-
-void QPulseAudioSink::setError(QAudio::Error error)
-{
- if (m_errorState == error)
- return;
-
- m_errorState = error;
- emit errorChanged(error);
-}
-
-QAudio::Error QPulseAudioSink::error() const
-{
- return m_errorState;
-}
-
-void QPulseAudioSink::setState(QAudio::State state)
-{
- if (m_deviceState == state)
- return;
-
- m_deviceState = state;
- emit stateChanged(state);
-}
-
-QAudio::State QPulseAudioSink::state() const
-{
- return m_deviceState;
-}
-
-void QPulseAudioSink::streamUnderflowCallback()
-{
- if (m_deviceState != QAudio::IdleState && !m_resuming) {
- setError(QAudio::UnderrunError);
- setState(QAudio::IdleState);
- }
-}
-
-void QPulseAudioSink::start(QIODevice *device)
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- // Handle change of mode
- if (m_audioSource && !m_pullMode) {
- delete m_audioSource;
- }
- m_audioSource = nullptr;
-
- close();
-
- m_pullMode = true;
- m_audioSource = device;
-
- if (!open()) {
- m_audioSource = nullptr;
- return;
- }
-
- setState(QAudio::ActiveState);
-}
-
-QIODevice *QPulseAudioSink::start()
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- // Handle change of mode
- if (m_audioSource && !m_pullMode) {
- delete m_audioSource;
- }
- m_audioSource = nullptr;
-
- close();
-
- m_pullMode = false;
-
- if (!open())
- return nullptr;
-
- m_audioSource = new PulseOutputPrivate(this);
- m_audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
-
- setState(QAudio::IdleState);
-
- return m_audioSource;
-}
-
-bool QPulseAudioSink::open()
-{
- if (m_opened)
- return true;
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
-
- if (!pulseEngine->context() || pa_context_get_state(pulseEngine->context()) != PA_CONTEXT_READY) {
- setError(QAudio::FatalError);
- setState(QAudio::StoppedState);
- emit stateChanged(m_deviceState);
- return false;
- }
-
- pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format);
-
- if (!pa_sample_spec_valid(&spec)) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- emit stateChanged(m_deviceState);
- return false;
- }
-
- m_spec = spec;
- m_totalTimeValue = 0;
-
- if (m_streamName.isNull())
- m_streamName = QString(QLatin1String("QtmPulseStream-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8();
-
-#ifdef DEBUG_PULSE
- qDebug() << "Format: " << QPulseAudioInternal::sampleFormatToQString(spec.format);
- qDebug() << "Rate: " << spec.rate;
- qDebug() << "Channels: " << spec.channels;
- qDebug() << "Frame size: " << pa_frame_size(&spec);
-#endif
-
- pulseEngine->lock();
-
-
- pa_proplist *propList = pa_proplist_new();
-#if 0
- qint64 bytesPerSecond = m_format.sampleRate() * m_format.bytesPerFrame();
- static const char *mediaRoleFromAudioRole[] = {
- nullptr, // UnknownRole
- "music", // MusicRole
- "video", // VideoRole
- "phone", // VoiceCommunicationRole
- "event", // AlarmRole
- "event", // NotificationRole
- "phone", // RingtoneRole
- "a11y", // AccessibilityRole
- nullptr, // SonificationRole
- "game" // GameRole
- };
-
- const char *r = mediaRoleFromAudioRole[m_role];
- if (r)
- pa_proplist_sets(propList, PA_PROP_MEDIA_ROLE, r);
-#endif
-
- static const auto mapName = qEnvironmentVariable("QT_PA_CHANNEL_MAP");
- pa_channel_map_def_t mapDef = PA_CHANNEL_MAP_DEFAULT;
- if (mapName == QLatin1String("ALSA"))
- mapDef = PA_CHANNEL_MAP_ALSA;
- else if (mapName == QLatin1String("AUX"))
- mapDef = PA_CHANNEL_MAP_AUX;
- else if (mapName == QLatin1String("WAVEEX"))
- mapDef = PA_CHANNEL_MAP_WAVEEX;
- else if (mapName == QLatin1String("OSS"))
- mapDef = PA_CHANNEL_MAP_OSS;
- else if (!mapName.isEmpty())
- qWarning() << "Unknown pulse audio channel mapping definition:" << mapName;
-
- pa_channel_map m;
- auto channelMap = pa_channel_map_init_extend(&m, m_spec.channels, mapDef);
- if (!channelMap)
- qWarning() << "QAudioSink: pa_channel_map_init_extend() Could not initialize channel map";
-
- m_stream = pa_stream_new_with_proplist(pulseEngine->context(), m_streamName.constData(), &m_spec, channelMap, propList);
- if (!m_stream) {
- qWarning() << "QAudioSink: pa_stream_new_with_proplist() failed!";
- pulseEngine->unlock();
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- emit stateChanged(m_deviceState);
- return false;
- }
-
- pa_proplist_free(propList);
-
- pa_stream_set_state_callback(m_stream, outputStreamStateCallback, this);
- pa_stream_set_write_callback(m_stream, outputStreamWriteCallback, this);
-
- pa_stream_set_underflow_callback(m_stream, outputStreamUnderflowCallback, this);
- pa_stream_set_overflow_callback(m_stream, outputStreamOverflowCallback, this);
- pa_stream_set_latency_update_callback(m_stream, outputStreamLatencyCallback, this);
-
-// if (m_bufferSize <= 0 && m_role == QAudio::GameRoleRole)
-// m_bufferSize = bytesPerSecond * LowLatencyBufferSizeMs / qint64(1000);
-
- pa_buffer_attr requestedBuffer;
- requestedBuffer.fragsize = (uint32_t)-1;
- requestedBuffer.maxlength = (uint32_t)-1;
- requestedBuffer.minreq = (uint32_t)-1;
- requestedBuffer.prebuf = (uint32_t)-1;
- requestedBuffer.tlength = m_bufferSize;
-
- if (pa_stream_connect_playback(m_stream, m_device.data(), (m_bufferSize > 0) ? &requestedBuffer : nullptr, (pa_stream_flags_t)0, nullptr, nullptr) < 0) {
- qWarning() << "pa_stream_connect_playback() failed!";
- pa_stream_unref(m_stream);
- m_stream = nullptr;
- pulseEngine->unlock();
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- emit stateChanged(m_deviceState);
- return false;
- }
-
- while (pa_stream_get_state(m_stream) != PA_STREAM_READY)
- pa_threaded_mainloop_wait(pulseEngine->mainloop());
-
- const pa_buffer_attr *buffer = pa_stream_get_buffer_attr(m_stream);
- m_periodTime = /*(m_role == QAudio::GameRole) ? LowLatencyPeriodTimeMs :*/ PeriodTimeMs;
- m_periodSize = pa_usec_to_bytes(m_periodTime*1000, &m_spec);
- m_bufferSize = buffer->tlength;
- m_maxBufferSize = buffer->maxlength;
- m_audioBuffer = new char[m_maxBufferSize];
-
- const qint64 streamSize = m_audioSource ? m_audioSource->size() : 0;
- if (m_pullMode && streamSize > 0 && static_cast<qint64>(buffer->prebuf) > streamSize) {
- pa_buffer_attr newBufferAttr;
- newBufferAttr = *buffer;
- newBufferAttr.prebuf = streamSize;
- pa_operation *o = pa_stream_set_buffer_attr(m_stream, &newBufferAttr, streamAdjustPrebufferCallback, nullptr);
- if (o)
- pa_operation_unref(o);
- }
-
-#ifdef DEBUG_PULSE
- qDebug() << "Buffering info:";
- qDebug() << "\tMax length: " << buffer->maxlength;
- qDebug() << "\tTarget length: " << buffer->tlength;
- qDebug() << "\tPre-buffering: " << buffer->prebuf;
- qDebug() << "\tMinimum request: " << buffer->minreq;
- qDebug() << "\tFragment size: " << buffer->fragsize;
-#endif
-
- pulseEngine->unlock();
-
- connect(pulseEngine, &QPulseAudioEngine::contextFailed, this, &QPulseAudioSink::onPulseContextFailed);
-
- m_opened = true;
-
- m_tickTimer->start(m_periodTime);
-
- m_elapsedTimeOffset = 0;
-
- return true;
-}
-
-void QPulseAudioSink::close()
-{
- if (!m_opened)
- return;
-
- m_tickTimer->stop();
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
-
- if (m_stream) {
- pulseEngine->lock();
-
- pa_stream_set_state_callback(m_stream, nullptr, nullptr);
- pa_stream_set_write_callback(m_stream, nullptr, nullptr);
- pa_stream_set_underflow_callback(m_stream, nullptr, nullptr);
- pa_stream_set_overflow_callback(m_stream, nullptr, nullptr);
- pa_stream_set_latency_update_callback(m_stream, nullptr, nullptr);
-
- pa_operation *o = pa_stream_drain(m_stream, outputStreamDrainComplete, nullptr);
- if (o)
- pa_operation_unref(o);
-
- pa_stream_disconnect(m_stream);
- pa_stream_unref(m_stream);
- m_stream = nullptr;
-
- pulseEngine->unlock();
- }
-
- disconnect(pulseEngine, &QPulseAudioEngine::contextFailed, this, &QPulseAudioSink::onPulseContextFailed);
-
- if (!m_pullMode && m_audioSource) {
- delete m_audioSource;
- m_audioSource = nullptr;
- }
- m_opened = false;
- if (m_audioBuffer) {
- delete[] m_audioBuffer;
- m_audioBuffer = nullptr;
- }
-}
-
-void QPulseAudioSink::userFeed()
-{
- if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
- return;
-
- m_resuming = false;
-
- if (m_pullMode) {
- int writableSize = bytesFree();
- int chunks = writableSize / m_periodSize;
- if (chunks == 0)
- return;
-
- int input = m_periodSize; // always request 1 chunk of data from user
- if (input > m_maxBufferSize)
- input = m_maxBufferSize;
-
- int audioBytesPulled = m_audioSource->read(m_audioBuffer, input);
- Q_ASSERT(audioBytesPulled <= input);
- if (m_audioBuffer && audioBytesPulled > 0) {
- if (audioBytesPulled > input) {
- qWarning() << "QPulseAudioSink::userFeed() - Invalid audio data size provided from user:"
- << audioBytesPulled << "should be less than" << input;
- audioBytesPulled = input;
- }
- qint64 bytesWritten = write(m_audioBuffer, audioBytesPulled);
- Q_ASSERT(bytesWritten == audioBytesPulled); //unfinished write should not happen since the data provided is less than writableSize
- Q_UNUSED(bytesWritten);
-
- if (chunks > 1) {
- // PulseAudio needs more data. Ask for it immediately.
- QMetaObject::invokeMethod(this, "userFeed", Qt::QueuedConnection);
- }
- }
- }
-
- if (m_deviceState != QAudio::ActiveState)
- return;
-}
-
-qint64 QPulseAudioSink::write(const char *data, qint64 len)
-{
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
-
- pulseEngine->lock();
-
- len = qMin(len, static_cast<qint64>(pa_stream_writable_size(m_stream)));
-
- if (m_volume < 1.0f) {
- // Don't use PulseAudio volume, as it might affect all other streams of the same category
- // or even affect the system volume if flat volumes are enabled
- void *dest = nullptr;
- size_t nbytes = len;
- if (pa_stream_begin_write(m_stream, &dest, &nbytes) < 0) {
- qWarning("QAudioSink(pulseaudio): pa_stream_begin_write, error = %s",
- pa_strerror(pa_context_errno(pulseEngine->context())));
- setError(QAudio::IOError);
- return 0;
- }
-
- len = int(nbytes);
- QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, dest, len);
- data = reinterpret_cast<char *>(dest);
- }
-
- if (pa_stream_write(m_stream, data, len, nullptr, 0, PA_SEEK_RELATIVE) < 0) {
- qWarning("QAudioSink(pulseaudio): pa_stream_write, error = %s",
- pa_strerror(pa_context_errno(pulseEngine->context())));
- setError(QAudio::IOError);
- return 0;
- }
-
- pulseEngine->unlock();
- m_totalTimeValue += len;
-
- setError(QAudio::NoError);
- setState(QAudio::ActiveState);
-
- return len;
-}
-
-void QPulseAudioSink::stop()
-{
- if (m_deviceState == QAudio::StoppedState)
- return;
-
- close();
-
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
-}
-
-qsizetype QPulseAudioSink::bytesFree() const
-{
- if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState)
- return 0;
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pulseEngine->lock();
- int writableSize = pa_stream_writable_size(m_stream);
- pulseEngine->unlock();
- return writableSize;
-}
-
-void QPulseAudioSink::setBufferSize(qsizetype value)
-{
- m_bufferSize = value;
-}
-
-qsizetype QPulseAudioSink::bufferSize() const
-{
- return m_bufferSize;
-}
-
-qint64 QPulseAudioSink::processedUSecs() const
-{
- qint64 result = qint64(1000000) * m_totalTimeValue / m_format.bytesPerFrame() / m_format.sampleRate();
-
- return result;
-}
-
-void QPulseAudioSink::resume()
-{
- if (m_deviceState == QAudio::SuspendedState) {
- m_resuming = true;
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
-
- pulseEngine->lock();
-
- pa_operation *operation = pa_stream_cork(m_stream, 0, outputStreamSuccessCallback, nullptr);
- pulseEngine->wait(operation);
- pa_operation_unref(operation);
-
- operation = pa_stream_trigger(m_stream, outputStreamSuccessCallback, nullptr);
- pulseEngine->wait(operation);
- pa_operation_unref(operation);
-
- pulseEngine->unlock();
-
- m_tickTimer->start(m_periodTime);
-
- setState(m_pullMode ? QAudio::ActiveState : QAudio::IdleState);
- setError(QAudio::NoError);
- }
-}
-
-void QPulseAudioSink::setFormat(const QAudioFormat &format)
-{
- m_format = format;
-}
-
-QAudioFormat QPulseAudioSink::format() const
-{
- return m_format;
-}
-
-void QPulseAudioSink::suspend()
-{
- if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::IdleState) {
- setError(QAudio::NoError);
- setState(QAudio::SuspendedState);
-
- m_tickTimer->stop();
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_operation *operation;
-
- pulseEngine->lock();
-
- operation = pa_stream_cork(m_stream, 1, outputStreamSuccessCallback, nullptr);
- pulseEngine->wait(operation);
- pa_operation_unref(operation);
-
- pulseEngine->unlock();
- }
-}
-
-void QPulseAudioSink::reset()
-{
- stop();
-}
-
-PulseOutputPrivate::PulseOutputPrivate(QPulseAudioSink *audio)
-{
- m_audioDevice = qobject_cast<QPulseAudioSink*>(audio);
-}
-
-qint64 PulseOutputPrivate::readData(char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- return 0;
-}
-
-qint64 PulseOutputPrivate::writeData(const char *data, qint64 len)
-{
- int retry = 0;
- qint64 written = 0;
-
- if ((m_audioDevice->m_deviceState == QAudio::ActiveState
- || m_audioDevice->m_deviceState == QAudio::IdleState)) {
- while(written < len) {
- int chunk = m_audioDevice->write(data+written, (len-written));
- if (chunk <= 0)
- retry++;
- written+=chunk;
- if (retry > 10)
- return written;
- }
- }
-
- return written;
-}
-
-void QPulseAudioSink::setVolume(qreal vol)
-{
- if (qFuzzyCompare(m_volume, vol))
- return;
-
- m_volume = qBound(qreal(0), vol, qreal(1));
-}
-
-qreal QPulseAudioSink::volume() const
-{
- return m_volume;
-}
-
-void QPulseAudioSink::onPulseContextFailed()
-{
- close();
-
- setError(QAudio::FatalError);
- setState(QAudio::StoppedState);
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qpulseaudiosink_p.cpp"
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiosink_p.h b/src/multimedia/platform/pulseaudio/qpulseaudiosink_p.h
deleted file mode 100644
index 9397c507a..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiosink_p.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QAUDIOOUTPUTPULSE_H
-#define QAUDIOOUTPUTPULSE_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 "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiosystem_p.h>
-
-#include <pulse/pulseaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-class QPulseAudioSink : public QPlatformAudioSink
-{
- friend class PulseOutputPrivate;
- Q_OBJECT
-
-public:
- QPulseAudioSink(const QByteArray &device);
- ~QPulseAudioSink();
-
- 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;
-
-public:
- void streamUnderflowCallback();
-
-private:
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
- bool open();
- void close();
- qint64 write(const char *data, qint64 len);
-
-private Q_SLOTS:
- void userFeed();
- void onPulseContextFailed();
-
-private:
- QByteArray m_device;
- QByteArray m_streamName;
- QAudioFormat m_format;
- QAudio::Error m_errorState;
- QAudio::State m_deviceState;
- bool m_pullMode;
- bool m_opened;
- QIODevice *m_audioSource;
- QTimer m_periodTimer;
- int m_periodTime;
- pa_stream *m_stream;
- int m_periodSize;
- int m_bufferSize;
- int m_maxBufferSize;
- qint64 m_totalTimeValue;
- QTimer *m_tickTimer;
- char *m_audioBuffer;
- qint64 m_elapsedTimeOffset;
- bool m_resuming;
-
- qreal m_volume;
- pa_sample_spec m_spec;
-};
-
-class PulseOutputPrivate : public QIODevice
-{
- friend class QPulseAudioSink;
- Q_OBJECT
-
-public:
- PulseOutputPrivate(QPulseAudioSink *audio);
- virtual ~PulseOutputPrivate() {}
-
-protected:
- qint64 readData(char *data, qint64 len) override;
- qint64 writeData(const char *data, qint64 len) override;
-
-private:
- QPulseAudioSink *m_audioDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiosource.cpp b/src/multimedia/platform/pulseaudio/qpulseaudiosource.cpp
deleted file mode 100644
index a7a0d4702..000000000
--- a/src/multimedia/platform/pulseaudio/qpulseaudiosource.cpp
+++ /dev/null
@@ -1,645 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <private/qaudiohelpers_p.h>
-
-#include "qpulseaudiosource_p.h"
-#include "qaudioengine_pulse_p.h"
-#include "qpulseaudiodevice_p.h"
-#include "qpulsehelpers_p.h"
-#include <sys/types.h>
-#include <unistd.h>
-
-QT_BEGIN_NAMESPACE
-
-const int PeriodTimeMs = 50;
-
-static void inputStreamReadCallback(pa_stream *stream, size_t length, void *userdata)
-{
- Q_UNUSED(userdata);
- Q_UNUSED(length);
- Q_UNUSED(stream);
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
-}
-
-static void inputStreamStateCallback(pa_stream *stream, void *userdata)
-{
- Q_UNUSED(userdata);
- pa_stream_state_t state = pa_stream_get_state(stream);
-#ifdef DEBUG_PULSE
- qDebug() << "Stream state: " << QPulseAudioInternal::stateToQString(state);
-#endif
- switch (state) {
- case PA_STREAM_CREATING:
- break;
- case PA_STREAM_READY: {
-#ifdef DEBUG_PULSE
- QPulseAudioSource *audioInput = static_cast<QPulseAudioSource*>(userdata);
- const pa_buffer_attr *buffer_attr = pa_stream_get_buffer_attr(stream);
- qDebug() << "*** maxlength: " << buffer_attr->maxlength;
- qDebug() << "*** prebuf: " << buffer_attr->prebuf;
- qDebug() << "*** fragsize: " << buffer_attr->fragsize;
- qDebug() << "*** minreq: " << buffer_attr->minreq;
- qDebug() << "*** tlength: " << buffer_attr->tlength;
-
- pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(audioInput->format());
- qDebug() << "*** bytes_to_usec: " << pa_bytes_to_usec(buffer_attr->fragsize, &spec);
-#endif
- }
- break;
- case PA_STREAM_TERMINATED:
- break;
- case PA_STREAM_FAILED:
- default:
- qWarning() << QString::fromLatin1("Stream error: %1").arg(QString::fromUtf8(pa_strerror(pa_context_errno(pa_stream_get_context(stream)))));
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
- break;
- }
-}
-
-static void inputStreamUnderflowCallback(pa_stream *stream, void *userdata)
-{
- Q_UNUSED(userdata);
- Q_UNUSED(stream);
- qWarning() << "Got a buffer underflow!";
-}
-
-static void inputStreamOverflowCallback(pa_stream *stream, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(userdata);
- qWarning() << "Got a buffer overflow!";
-}
-
-static void inputStreamSuccessCallback(pa_stream *stream, int success, void *userdata)
-{
- Q_UNUSED(stream);
- Q_UNUSED(userdata);
- Q_UNUSED(success);
-
- //if (!success)
- //TODO: Is cork success? i->operation_success = success;
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
-}
-
-QPulseAudioSource::QPulseAudioSource(const QByteArray &device)
- : m_totalTimeValue(0)
- , m_audioSource(nullptr)
- , m_errorState(QAudio::NoError)
- , m_deviceState(QAudio::StoppedState)
- , m_volume(qreal(1.0f))
- , m_pullMode(true)
- , m_opened(false)
- , m_bytesAvailable(0)
- , m_bufferSize(0)
- , m_periodSize(0)
- , m_periodTime(PeriodTimeMs)
- , m_stream(nullptr)
- , m_device(device)
-{
- m_timer = new QTimer(this);
- connect(m_timer, SIGNAL(timeout()), SLOT(userFeed()));
-}
-
-QPulseAudioSource::~QPulseAudioSource()
-{
- close();
- disconnect(m_timer, SIGNAL(timeout()));
- QCoreApplication::processEvents();
- delete m_timer;
-}
-
-void QPulseAudioSource::setError(QAudio::Error error)
-{
- if (m_errorState == error)
- return;
-
- m_errorState = error;
- emit errorChanged(error);
-}
-
-QAudio::Error QPulseAudioSource::error() const
-{
- return m_errorState;
-}
-
-void QPulseAudioSource::setState(QAudio::State state)
-{
- if (m_deviceState == state)
- return;
-
- m_deviceState = state;
- emit stateChanged(state);
-}
-
-QAudio::State QPulseAudioSource::state() const
-{
- return m_deviceState;
-}
-
-void QPulseAudioSource::setFormat(const QAudioFormat &format)
-{
- if (m_deviceState == QAudio::StoppedState)
- m_format = format;
-}
-
-QAudioFormat QPulseAudioSource::format() const
-{
- return m_format;
-}
-
-void QPulseAudioSource::start(QIODevice *device)
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- if (!m_pullMode && m_audioSource) {
- delete m_audioSource;
- m_audioSource = nullptr;
- }
-
- close();
-
- if (!open())
- return;
-
- m_pullMode = true;
- m_audioSource = device;
-
- setState(QAudio::ActiveState);
-}
-
-QIODevice *QPulseAudioSource::start()
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- if (!m_pullMode && m_audioSource) {
- delete m_audioSource;
- m_audioSource = nullptr;
- }
-
- close();
-
- if (!open())
- return nullptr;
-
- m_pullMode = false;
- m_audioSource = new PulseInputPrivate(this);
- m_audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
-
- setState(QAudio::IdleState);
-
- return m_audioSource;
-}
-
-void QPulseAudioSource::stop()
-{
- if (m_deviceState == QAudio::StoppedState)
- return;
-
- close();
-
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
-}
-
-bool QPulseAudioSource::open()
-{
- if (m_opened)
- return true;
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
-
- if (!pulseEngine->context() || pa_context_get_state(pulseEngine->context()) != PA_CONTEXT_READY) {
- setError(QAudio::FatalError);
- setState(QAudio::StoppedState);
- return false;
- }
-
- pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format);
-
- if (!pa_sample_spec_valid(&spec)) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
- m_spec = spec;
-
-#ifdef DEBUG_PULSE
-// QTime now(QTime::currentTime());
-// qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
-#endif
-
- if (m_streamName.isNull())
- m_streamName = QString(QLatin1String("QtmPulseStream-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8();
-
-#ifdef DEBUG_PULSE
- qDebug() << "Format: " << QPulseAudioInternal::sampleFormatToQString(spec.format);
- qDebug() << "Rate: " << spec.rate;
- qDebug() << "Channels: " << spec.channels;
- qDebug() << "Frame size: " << pa_frame_size(&spec);
-#endif
-
- pulseEngine->lock();
- pa_channel_map channel_map;
-
- pa_channel_map_init_extend(&channel_map, spec.channels, PA_CHANNEL_MAP_DEFAULT);
-
- if (!pa_channel_map_compatible(&channel_map, &spec))
- qWarning() << "Channel map doesn't match sample specification!";
-
- m_stream = pa_stream_new(pulseEngine->context(), m_streamName.constData(), &spec, &channel_map);
-
- pa_stream_set_state_callback(m_stream, inputStreamStateCallback, this);
- pa_stream_set_read_callback(m_stream, inputStreamReadCallback, this);
-
- pa_stream_set_underflow_callback(m_stream, inputStreamUnderflowCallback, this);
- pa_stream_set_overflow_callback(m_stream, inputStreamOverflowCallback, this);
-
- m_periodSize = pa_usec_to_bytes(PeriodTimeMs*1000, &spec);
-
- int flags = 0;
- pa_buffer_attr buffer_attr;
- buffer_attr.maxlength = (uint32_t) -1;
- buffer_attr.prebuf = (uint32_t) -1;
- buffer_attr.tlength = (uint32_t) -1;
- buffer_attr.minreq = (uint32_t) -1;
- flags |= PA_STREAM_ADJUST_LATENCY;
-
- if (m_bufferSize > 0)
- buffer_attr.fragsize = (uint32_t) m_bufferSize;
- else
- buffer_attr.fragsize = (uint32_t) m_periodSize;
-
- if (pa_stream_connect_record(m_stream, m_device.data(), &buffer_attr, (pa_stream_flags_t)flags) < 0) {
- qWarning() << "pa_stream_connect_record() failed!";
- pa_stream_unref(m_stream);
- m_stream = nullptr;
- pulseEngine->unlock();
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
- while (pa_stream_get_state(m_stream) != PA_STREAM_READY)
- pa_threaded_mainloop_wait(pulseEngine->mainloop());
-
- const pa_buffer_attr *actualBufferAttr = pa_stream_get_buffer_attr(m_stream);
- m_periodSize = actualBufferAttr->fragsize;
- m_periodTime = pa_bytes_to_usec(m_periodSize, &spec) / 1000;
- if (actualBufferAttr->tlength != (uint32_t)-1)
- m_bufferSize = actualBufferAttr->tlength;
-
- pulseEngine->unlock();
-
- connect(pulseEngine, &QPulseAudioEngine::contextFailed, this, &QPulseAudioSource::onPulseContextFailed);
-
- m_opened = true;
- m_timer->start(m_periodTime);
-
- m_elapsedTimeOffset = 0;
- m_totalTimeValue = 0;
-
- return true;
-}
-
-void QPulseAudioSource::close()
-{
- if (!m_opened)
- return;
-
- m_timer->stop();
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
-
- if (m_stream) {
- pulseEngine->lock();
-
- pa_stream_set_state_callback(m_stream, nullptr, nullptr);
- pa_stream_set_read_callback(m_stream, nullptr, nullptr);
- pa_stream_set_underflow_callback(m_stream, nullptr, nullptr);
- pa_stream_set_overflow_callback(m_stream, nullptr, nullptr);
-
- pa_stream_disconnect(m_stream);
- pa_stream_unref(m_stream);
- m_stream = nullptr;
-
- pulseEngine->unlock();
- }
-
- disconnect(pulseEngine, &QPulseAudioEngine::contextFailed, this, &QPulseAudioSource::onPulseContextFailed);
-
- if (!m_pullMode && m_audioSource) {
- delete m_audioSource;
- m_audioSource = nullptr;
- }
- m_opened = false;
-}
-
-int QPulseAudioSource::checkBytesReady()
-{
- if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState) {
- m_bytesAvailable = 0;
- } else {
- m_bytesAvailable = pa_stream_readable_size(m_stream);
- }
-
- return m_bytesAvailable;
-}
-
-qsizetype QPulseAudioSource::bytesReady() const
-{
- return qMax(m_bytesAvailable, 0);
-}
-
-qint64 QPulseAudioSource::read(char *data, qint64 len)
-{
- m_bytesAvailable = checkBytesReady();
-
- setError(QAudio::NoError);
- setState(QAudio::ActiveState);
-
- int readBytes = 0;
-
- if (!m_pullMode && !m_tempBuffer.isEmpty()) {
- readBytes = qMin(static_cast<int>(len), m_tempBuffer.size());
- memcpy(data, m_tempBuffer.constData(), readBytes);
- m_totalTimeValue += readBytes;
-
- if (readBytes < m_tempBuffer.size()) {
- m_tempBuffer.remove(0, readBytes);
- return readBytes;
- }
-
- m_tempBuffer.clear();
- }
-
- while (pa_stream_readable_size(m_stream) > 0) {
- size_t readLength = 0;
-
-#ifdef DEBUG_PULSE
- qDebug() << "QPulseAudioSource::read -- " << pa_stream_readable_size(m_stream) << " bytes available from pulse audio";
-#endif
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pulseEngine->lock();
-
- const void *audioBuffer;
-
- // Second and third parameters (audioBuffer and length) to pa_stream_peek are output parameters,
- // the audioBuffer pointer is set to point to the actual pulse audio data,
- // and the length is set to the length of this data.
- if (pa_stream_peek(m_stream, &audioBuffer, &readLength) < 0) {
- qWarning() << QString::fromLatin1("pa_stream_peek() failed: %1")
- .arg(QString::fromUtf8(pa_strerror(pa_context_errno(pa_stream_get_context(m_stream)))));
- pulseEngine->unlock();
- return 0;
- }
-
- qint64 actualLength = 0;
- if (m_pullMode) {
- QByteArray adjusted(readLength, Qt::Uninitialized);
- applyVolume(audioBuffer, adjusted.data(), readLength);
- actualLength = m_audioSource->write(adjusted);
-
- if (actualLength < qint64(readLength)) {
- pulseEngine->unlock();
-
- setError(QAudio::UnderrunError);
- setState(QAudio::IdleState);
-
- return actualLength;
- }
- } else {
- actualLength = qMin(static_cast<int>(len - readBytes), static_cast<int>(readLength));
- applyVolume(audioBuffer, data + readBytes, actualLength);
- }
-
-#ifdef DEBUG_PULSE
- qDebug() << "QPulseAudioSource::read -- wrote " << actualLength << " to client";
-#endif
-
- if (actualLength < qint64(readLength)) {
-#ifdef DEBUG_PULSE
- qDebug() << "QPulseAudioSource::read -- appending " << readLength - actualLength << " bytes of data to temp buffer";
-#endif
- int diff = readLength - actualLength;
- int oldSize = m_tempBuffer.size();
- m_tempBuffer.resize(m_tempBuffer.size() + diff);
- applyVolume(static_cast<const char *>(audioBuffer) + actualLength, m_tempBuffer.data() + oldSize, diff);
- QMetaObject::invokeMethod(this, "userFeed", Qt::QueuedConnection);
- }
-
- m_totalTimeValue += actualLength;
- readBytes += actualLength;
-
- pa_stream_drop(m_stream);
- pulseEngine->unlock();
-
- if (!m_pullMode && readBytes >= len)
- break;
- }
-
-#ifdef DEBUG_PULSE
- qDebug() << "QPulseAudioSource::read -- returning after reading " << readBytes << " bytes";
-#endif
-
- return readBytes;
-}
-
-void QPulseAudioSource::applyVolume(const void *src, void *dest, int len)
-{
- if (m_volume < 1.f)
- QAudioHelperInternal::qMultiplySamples(m_volume, m_format, src, dest, len);
- else
- memcpy(dest, src, len);
-}
-
-void QPulseAudioSource::resume()
-{
- if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) {
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_operation *operation;
-
- pulseEngine->lock();
-
- operation = pa_stream_cork(m_stream, 0, inputStreamSuccessCallback, nullptr);
- pulseEngine->wait(operation);
- pa_operation_unref(operation);
-
- pulseEngine->unlock();
-
- m_timer->start(m_periodTime);
-
- setState(QAudio::ActiveState);
- setError(QAudio::NoError);
- }
-}
-
-void QPulseAudioSource::setVolume(qreal vol)
-{
- if (qFuzzyCompare(m_volume, vol))
- return;
-
- m_volume = qBound(qreal(0), vol, qreal(1));
-}
-
-qreal QPulseAudioSource::volume() const
-{
- return m_volume;
-}
-
-void QPulseAudioSource::setBufferSize(qsizetype value)
-{
- m_bufferSize = value;
-}
-
-qsizetype QPulseAudioSource::bufferSize() const
-{
- return m_bufferSize;
-}
-
-qint64 QPulseAudioSource::processedUSecs() const
-{
- pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format);
- qint64 result = pa_bytes_to_usec(m_totalTimeValue, &spec);
-
- return result;
-}
-
-void QPulseAudioSource::suspend()
-{
- if (m_deviceState == QAudio::ActiveState) {
- setError(QAudio::NoError);
- setState(QAudio::SuspendedState);
-
- m_timer->stop();
-
- QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
- pa_operation *operation;
-
- pulseEngine->lock();
-
- operation = pa_stream_cork(m_stream, 1, inputStreamSuccessCallback, nullptr);
- pulseEngine->wait(operation);
- pa_operation_unref(operation);
-
- pulseEngine->unlock();
- }
-}
-
-void QPulseAudioSource::userFeed()
-{
- if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
- return;
-#ifdef DEBUG_PULSE
-// QTime now(QTime::currentTime());
-// qDebug()<< now.second() << "s " << now.msec() << "ms :userFeed() IN";
-#endif
- deviceReady();
-}
-
-bool QPulseAudioSource::deviceReady()
-{
- if (m_pullMode) {
- // reads some audio data and writes it to QIODevice
- read(nullptr,0);
- } else {
- // emits readyRead() so user will call read() on QIODevice to get some audio data
- if (m_audioSource != nullptr) {
- PulseInputPrivate *a = qobject_cast<PulseInputPrivate*>(m_audioSource);
- a->trigger();
- }
- }
- m_bytesAvailable = checkBytesReady();
-
- if (m_deviceState != QAudio::ActiveState)
- return true;
-
- return true;
-}
-
-void QPulseAudioSource::reset()
-{
- stop();
- m_bytesAvailable = 0;
-}
-
-void QPulseAudioSource::onPulseContextFailed()
-{
- close();
-
- setError(QAudio::FatalError);
- setState(QAudio::StoppedState);
-}
-
-PulseInputPrivate::PulseInputPrivate(QPulseAudioSource *audio)
-{
- m_audioDevice = qobject_cast<QPulseAudioSource*>(audio);
-}
-
-qint64 PulseInputPrivate::readData(char *data, qint64 len)
-{
- return m_audioDevice->read(data, len);
-}
-
-qint64 PulseInputPrivate::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
- return 0;
-}
-
-void PulseInputPrivate::trigger()
-{
- emit readyRead();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qpulseaudiosource_p.cpp"
diff --git a/src/multimedia/platform/pulseaudio/qpulsehelpers.cpp b/src/multimedia/platform/pulseaudio/qpulsehelpers.cpp
deleted file mode 100644
index c3ca6f8c9..000000000
--- a/src/multimedia/platform/pulseaudio/qpulsehelpers.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qpulsehelpers_p.h"
-
-QT_BEGIN_NAMESPACE
-
-namespace QPulseAudioInternal
-{
-pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
-{
- pa_sample_spec spec;
-
- spec.rate = format.sampleRate();
- spec.channels = format.channelCount();
- spec.format = PA_SAMPLE_INVALID;
- const bool isBigEndian = QSysInfo::ByteOrder == QSysInfo::BigEndian;
-
- if (format.sampleFormat() == QAudioFormat::UInt8) {
- spec.format = PA_SAMPLE_U8;
- } else if (format.sampleFormat() == QAudioFormat::Int16) {
- spec.format = isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
- } else if (format.sampleFormat() == QAudioFormat::Int32) {
- spec.format = isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
- } else if (format.sampleFormat() == QAudioFormat::Float) {
- spec.format = isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
- }
-
- return spec;
-}
-
-#ifdef DEBUG_PULSE
-QString stateToQString(pa_stream_state_t state)
-{
- switch (state)
- {
- case PA_STREAM_UNCONNECTED: return "Unconnected";
- case PA_STREAM_CREATING: return "Creating";
- case PA_STREAM_READY: return "Ready";
- case PA_STREAM_FAILED: return "Failed";
- case PA_STREAM_TERMINATED: return "Terminated";
- }
-
- return QString("Unknown state: %0").arg(state);
-}
-
-QString sampleFormatToQString(pa_sample_format format)
-{
- switch (format)
- {
- case PA_SAMPLE_U8: return "Unsigned 8 Bit PCM.";
- case PA_SAMPLE_ALAW: return "8 Bit a-Law ";
- case PA_SAMPLE_ULAW: return "8 Bit mu-Law";
- case PA_SAMPLE_S16LE: return "Signed 16 Bit PCM, little endian (PC).";
- case PA_SAMPLE_S16BE: return "Signed 16 Bit PCM, big endian.";
- case PA_SAMPLE_FLOAT32LE: return "32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0";
- case PA_SAMPLE_FLOAT32BE: return "32 Bit IEEE floating point, big endian, range -1.0 to 1.0";
- case PA_SAMPLE_S32LE: return "Signed 32 Bit PCM, little endian (PC).";
- case PA_SAMPLE_S32BE: return "Signed 32 Bit PCM, big endian.";
- case PA_SAMPLE_S24LE: return "Signed 24 Bit PCM packed, little endian (PC).";
- case PA_SAMPLE_S24BE: return "Signed 24 Bit PCM packed, big endian.";
- case PA_SAMPLE_S24_32LE: return "Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC).";
- case PA_SAMPLE_S24_32BE: return "Signed 24 Bit PCM in LSB of 32 Bit words, big endian.";
- case PA_SAMPLE_MAX: return "Upper limit of valid sample types.";
- case PA_SAMPLE_INVALID: return "Invalid sample format";
- }
-
- return QString("Invalid value: %0").arg(format);
-}
-
-QString stateToQString(pa_context_state_t state)
-{
- switch (state)
- {
- case PA_CONTEXT_UNCONNECTED: return "Unconnected";
- case PA_CONTEXT_CONNECTING: return "Connecting";
- case PA_CONTEXT_AUTHORIZING: return "Authorizing";
- case PA_CONTEXT_SETTING_NAME: return "Setting Name";
- case PA_CONTEXT_READY: return "Ready";
- case PA_CONTEXT_FAILED: return "Failed";
- case PA_CONTEXT_TERMINATED: return "Terminated";
- }
-
- return QString("Unknown state: %0").arg(state);
-}
-#endif
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/pulseaudio/qpulsehelpers_p.h b/src/multimedia/platform/pulseaudio/qpulsehelpers_p.h
deleted file mode 100644
index 5663e73ed..000000000
--- a/src/multimedia/platform/pulseaudio/qpulsehelpers_p.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QPULSEHELPER_H
-#define QPULSEHELPER_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 "qaudiodevice.h"
-#include <qaudioformat.h>
-#include <pulse/pulseaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QPulseAudioInternal
-{
-pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format);
-QString stateToQString(pa_stream_state_t state);
-QString stateToQString(pa_context_state_t state);
-QString sampleFormatToQString(pa_sample_format format);
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/audio/qnxaudioutils.cpp b/src/multimedia/platform/qnx/audio/qnxaudioutils.cpp
deleted file mode 100644
index 7aa31e408..000000000
--- a/src/multimedia/platform/qnx/audio/qnxaudioutils.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qnxaudioutils_p.h"
-
-QT_BEGIN_NAMESPACE
-
-snd_pcm_channel_params_t QnxAudioUtils::formatToChannelParams(const QAudioFormat &format, QAudioDevice::Mode mode, int fragmentSize)
-{
- snd_pcm_channel_params_t params;
- memset(&params, 0, sizeof(params));
- params.channel = (mode == QAudioDevice::Output) ? SND_PCM_CHANNEL_PLAYBACK : SND_PCM_CHANNEL_CAPTURE;
- params.mode = SND_PCM_MODE_BLOCK;
- params.start_mode = SND_PCM_START_DATA;
- params.stop_mode = SND_PCM_STOP_ROLLOVER;
- params.buf.block.frag_size = fragmentSize;
- params.buf.block.frags_min = 1;
- params.buf.block.frags_max = 1;
- strcpy(params.sw_mixer_subchn_name, "QAudio Channel");
-
- params.format.interleave = 1;
- params.format.rate = format.sampleRate();
- params.format.voices = format.channelCount();
-
- switch (format.sampleSize()) {
- case 8:
- switch (format.sampleType()) {
- case QAudioFormat::SignedInt:
- params.format.format = SND_PCM_SFMT_S8;
- break;
- case QAudioFormat::UnSignedInt:
- params.format.format = SND_PCM_SFMT_U8;
- break;
- default:
- break;
- }
- break;
-
- case 16:
- switch (format.sampleType()) {
- case QAudioFormat::SignedInt:
- if (format.byteOrder() == QAudioFormat::LittleEndian) {
- params.format.format = SND_PCM_SFMT_S16_LE;
- } else {
- params.format.format = SND_PCM_SFMT_S16_BE;
- }
- break;
- case QAudioFormat::UnSignedInt:
- if (format.byteOrder() == QAudioFormat::LittleEndian) {
- params.format.format = SND_PCM_SFMT_U16_LE;
- } else {
- params.format.format = SND_PCM_SFMT_U16_BE;
- }
- break;
- default:
- break;
- }
- break;
-
- case 32:
- switch (format.sampleType()) {
- case QAudioFormat::SignedInt:
- if (format.byteOrder() == QAudioFormat::LittleEndian) {
- params.format.format = SND_PCM_SFMT_S32_LE;
- } else {
- params.format.format = SND_PCM_SFMT_S32_BE;
- }
- break;
- case QAudioFormat::UnSignedInt:
- if (format.byteOrder() == QAudioFormat::LittleEndian) {
- params.format.format = SND_PCM_SFMT_U32_LE;
- } else {
- params.format.format = SND_PCM_SFMT_U32_BE;
- }
- break;
- case QAudioFormat::Float:
- if (format.byteOrder() == QAudioFormat::LittleEndian) {
- params.format.format = SND_PCM_SFMT_FLOAT_LE;
- } else {
- params.format.format = SND_PCM_SFMT_FLOAT_BE;
- }
- break;
- default:
- break;
- }
- break;
- }
-
- return params;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/audio/qnxaudioutils_p.h b/src/multimedia/platform/qnx/audio/qnxaudioutils_p.h
deleted file mode 100644
index d8e454de2..000000000
--- a/src/multimedia/platform/qnx/audio/qnxaudioutils_p.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNXAUDIOUTILS_H
-#define QNXAUDIOUTILS_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 "qaudiosystem_p.h"
-#include <sys/asoundlib.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QnxAudioUtils
-{
- snd_pcm_channel_params_t formatToChannelParams(const QAudioFormat &format, QAudioDevice::Mode mode, int fragmentSize);
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/audio/qqnxaudiodevice.cpp b/src/multimedia/platform/qnx/audio/qqnxaudiodevice.cpp
deleted file mode 100644
index ff7d23192..000000000
--- a/src/multimedia/platform/qnx/audio/qqnxaudiodevice.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqnxaudiodevice_p.h"
-
-#include "qnxaudioutils_p.h"
-
-#include <sys/asoundlib.h>
-
-QT_BEGIN_NAMESPACE
-
-QnxAudioDeviceInfo::QnxAudioDeviceInfo(const QByteArray &deviceName, QAudioDevice::Mode mode)
- : QAudioDevicePrivate(deviceName, mode)
-{
-}
-
-QnxAudioDeviceInfo::~QnxAudioDeviceInfo()
-{
-}
-
-QAudioFormat QnxAudioDeviceInfo::preferredFormat() const
-{
- QAudioFormat format;
- format.setSampleRate(44100);
- format.setByteOrder(QAudioFormat::LittleEndian);
- format.setSampleType(QAudioFormat::SignedInt);
- format.setSampleSize(16);
- format.setChannelCount(2);
- if(mode == QAudioDevice::Input && !isFormatSupported(format))
- format.setChannelCount(1);
- return format;
-}
-
-bool QnxAudioDeviceInfo::isFormatSupported(const QAudioFormat &format) const
-{
- const int pcmMode = (mode == QAudioDevice::Output) ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE;
- snd_pcm_t *handle;
-
- int card = 0;
- int device = 0;
- if (snd_pcm_open_preferred(&handle, &card, &device, pcmMode) < 0)
- return false;
-
- snd_pcm_channel_info_t info;
- memset (&info, 0, sizeof(info));
- info.channel = (mode == QAudioDevice::Output) ? SND_PCM_CHANNEL_PLAYBACK : SND_PCM_CHANNEL_CAPTURE;
-
- if (snd_pcm_plugin_info(handle, &info) < 0) {
- qWarning("QAudioDevice: couldn't get channel info");
- snd_pcm_close(handle);
- return false;
- }
-
- snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(format, mode, info.max_fragment_size);
- const int errorCode = snd_pcm_plugin_params(handle, &params);
- snd_pcm_close(handle);
-
- return errorCode == 0;
-}
-
-QList<int> QnxAudioDeviceInfo::supportedSampleRates() const
-{
- return QList<int>() << 8000 << 11025 << 22050 << 44100 << 48000;
-}
-
-QList<int> QnxAudioDeviceInfo::supportedChannelCounts() const
-{
- return QList<int>() << 1 << 2;
-}
-
-QList<int> QnxAudioDeviceInfo::supportedSampleSizes() const
-{
- return QList<int>() << 8 << 16 << 32;
-}
-
-QList<QAudioFormat::Endian> QnxAudioDeviceInfo::supportedByteOrders() const
-{
- return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian;
-}
-
-QList<QAudioFormat::SampleType> QnxAudioDeviceInfo::supportedSampleTypes() const
-{
- return QList<QAudioFormat::SampleType>() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/audio/qqnxaudiodevice_p.h b/src/multimedia/platform/qnx/audio/qqnxaudiodevice_p.h
deleted file mode 100644
index 96e65759a..000000000
--- a/src/multimedia/platform/qnx/audio/qqnxaudiodevice_p.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNXAUDIODEVICEINFO_H
-#define QNXAUDIODEVICEINFO_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 "qaudiosystem_p.h"
-#include <private/qaudiodevice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QnxAudioDeviceInfo : public QAudioDevicePrivate
-{
-public:
- QnxAudioDeviceInfo(const QByteArray &deviceName, QAudioDevice::Mode mode);
- ~QnxAudioDeviceInfo();
-
- QAudioFormat preferredFormat() const override;
- bool isFormatSupported(const QAudioFormat &format) const override;
- QString description() const override { return QString::fromUtf8(id()); }
- QList<int> supportedSampleRates() const override;
- QList<int> supportedChannelCounts() const override;
- QList<int> supportedSampleSizes() const override;
- QList<QAudioFormat::Endian> supportedByteOrders() const override;
- QList<QAudioFormat::SampleType> supportedSampleTypes() const override;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/audio/qqnxaudiosink_p.h b/src/multimedia/platform/qnx/audio/qqnxaudiosink_p.h
deleted file mode 100644
index 2ce38315a..000000000
--- a/src/multimedia/platform/qnx/audio/qqnxaudiosink_p.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNXAUDIOOUTPUT_H
-#define QNXAUDIOOUTPUT_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 "qaudiosystem_p.h"
-
-#include <QElapsedTimer>
-#include <QTimer>
-#include <QIODevice>
-#include <QSocketNotifier>
-
-#include <sys/asoundlib.h>
-#include <sys/neutrino.h>
-
-QT_BEGIN_NAMESPACE
-
-class QnxPushIODevice;
-
-class QQnxAudioSink : public QPlatformAudioSink
-{
- Q_OBJECT
-
-public:
- QQnxAudioSink();
- ~QQnxAudioSink();
-
- void start(QIODevice *source) override;
- QIODevice *start() override;
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- qsizetype bytesFree() const override;
- void setBufferSize(qsizetype) override {}
- qsizetype bufferSize() const override { return 0; }
- 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 slots:
- void pullData();
-
-private:
- bool open();
- void close();
- void setError(QAudio::Error error);
- void setState(QAudio::State state);
-
- void addPcmEventFilter();
- void createPcmNotifiers();
- void destroyPcmNotifiers();
- void setTypeName(snd_pcm_channel_params_t *params);
-
- void suspendInternal(QAudio::State suspendState);
- void resumeInternal();
-
- friend class QnxPushIODevice;
- qint64 write(const char *data, qint64 len);
-
- QIODevice *m_source;
- bool m_pushSource;
- QTimer m_timer;
-
- QAudio::Error m_error;
- QAudio::State m_state;
- QAudioFormat m_format;
- qreal m_volume;
- int m_periodSize;
-
- snd_pcm_t *m_pcmHandle;
- qint64 m_bytesWritten;
-
-#if _NTO_VERSION >= 700
- QSocketNotifier *m_pcmNotifier;
-
-private slots:
- void pcmNotifierActivated(int socket);
-#endif
-};
-
-class QnxPushIODevice : public QIODevice
-{
- Q_OBJECT
-public:
- explicit QnxPushIODevice(QQnxAudioSink *output);
- ~QnxPushIODevice();
-
- qint64 readData(char *data, qint64 len);
- qint64 writeData(const char *data, qint64 len);
-
-private:
- QQnxAudioSink *m_output;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/audio/qqnxaudiosource_p.h b/src/multimedia/platform/qnx/audio/qqnxaudiosource_p.h
deleted file mode 100644
index 3432f7544..000000000
--- a/src/multimedia/platform/qnx/audio/qqnxaudiosource_p.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNXAUDIOINPUT_H
-#define QNXAUDIOINPUT_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 "qaudiosystem_p.h"
-
-#include <QSocketNotifier>
-#include <QIODevice>
-#include <QElapsedTimer>
-#include <QTimer>
-
-#include <sys/asoundlib.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQnxAudioSource : public QPlatformAudioSource
-{
- Q_OBJECT
-
-public:
- QQnxAudioSource();
- ~QQnxAudioSource();
-
- void start(QIODevice*) override;
- QIODevice* start() override;
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- qsizetype bytesReady() const override;
- void setBufferSize(qsizetype ) override;
- qsizetype bufferSize() const override;
- qint64 processedUSecs() const override;
- QAudio::Error error() const override;
- QAudio::State state() const override;
- void setFormat(const QAudioFormat&) override;
- QAudioFormat format() const override;
- void setVolume(qreal) override;
- qreal volume() const override;
-
-private slots:
- void userFeed();
- bool deviceReady();
-
-private:
- friend class InputPrivate;
-
- bool open();
- void close();
- qint64 read(char *data, qint64 len);
- void setError(QAudio::Error error);
- void setState(QAudio::State state);
-
- QAudioFormat m_format;
-
- QIODevice *m_audioSource;
- snd_pcm_t *m_pcmHandle;
- QSocketNotifier *m_pcmNotifier;
-
- QAudio::Error m_error;
- QAudio::State m_state;
-
- qint64 m_bytesRead;
- qint64 m_elapsedTimeOffset;
- qint64 m_totalTimeValue;
-
- qreal m_volume;
-
- int m_bytesAvailable;
- int m_bufferSize;
- int m_periodSize;
-
- bool m_pullMode;
-};
-
-class InputPrivate : public QIODevice
-{
- Q_OBJECT
-public:
- InputPrivate(QQnxAudioSource *audio);
-
- qint64 readData(char *data, qint64 len) override;
- qint64 writeData(const char *data, qint64 len) override;
-
- void trigger();
-
-private:
- QQnxAudioSource *m_audioDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol.cpp b/src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol.cpp
deleted file mode 100644
index 2c0529bc4..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameraaudioencodersettingscontrol_p.h"
-
-#include "bbcamerasession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-BbCameraAudioEncoderSettingsControl::BbCameraAudioEncoderSettingsControl(BbCameraSession *session, QObject *parent)
- : QAudioEncoderSettingsControl(parent)
- , m_session(session)
-{
-}
-
-QStringList BbCameraAudioEncoderSettingsControl::supportedAudioCodecs() const
-{
- return QStringList() << QLatin1String("none") << QLatin1String("aac") << QLatin1String("raw");
-}
-
-QString BbCameraAudioEncoderSettingsControl::codecDescription(const QString &codecName) const
-{
- if (codecName == QLatin1String("none"))
- return tr("No compression");
- else if (codecName == QLatin1String("aac"))
- return tr("AAC compression");
- else if (codecName == QLatin1String("raw"))
- return tr("PCM uncompressed");
-
- return QString();
-}
-
-QList<int> BbCameraAudioEncoderSettingsControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const
-{
- Q_UNUSED(settings);
- Q_UNUSED(continuous);
-
- // no API provided by BB10 yet
- return QList<int>();
-}
-
-QAudioEncoderSettings BbCameraAudioEncoderSettingsControl::audioSettings() const
-{
- return m_session->audioSettings();
-}
-
-void BbCameraAudioEncoderSettingsControl::setAudioSettings(const QAudioEncoderSettings &settings)
-{
- m_session->setAudioSettings(settings);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol_p.h b/src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol_p.h
deleted file mode 100644
index cdc384537..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraaudioencodersettingscontrol_p.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAAUDIOENCODERSETTINGSCONTROL_H
-#define BBCAMERAAUDIOENCODERSETTINGSCONTROL_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 <qaudioencodersettingscontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraAudioEncoderSettingsControl : public QAudioEncoderSettingsControl
-{
- Q_OBJECT
-public:
- explicit BbCameraAudioEncoderSettingsControl(BbCameraSession *session, QObject *parent = 0);
-
- QStringList supportedAudioCodecs() const override;
- QString codecDescription(const QString &codecName) const override;
- QList<int> supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous = 0) const override;
- QAudioEncoderSettings audioSettings() const override;
- void setAudioSettings(const QAudioEncoderSettings &settings) override;
-
-private:
- BbCameraSession *m_session;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameracontrol.cpp b/src/multimedia/platform/qnx/camera/bbcameracontrol.cpp
deleted file mode 100644
index 335b7c584..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameracontrol.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameracontrol_p.h"
-
-#include "bbcamerasession_p.h"
-#include <qcameradevice.h>
-
-QT_BEGIN_NAMESPACE
-
-BbCameraControl::BbCameraControl(BbCameraSession *session, QObject *parent)
- : QPlatformCamera(parent)
- , m_session(session)
-{
- connect(m_session, SIGNAL(statusChanged(QCamera::Status)), this, SIGNAL(statusChanged(QCamera::Status)));
- connect(m_session, SIGNAL(stateChanged(QCamera::State)), this, SIGNAL(stateChanged(QCamera::State)));
- connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString)));
- connect(m_session, SIGNAL(captureModeChanged(QCamera::CaptureModes)), this, SIGNAL(captureModeChanged(QCamera::CaptureModes)));
-
- connect(m_session, SIGNAL(cameraOpened()), SLOT(cameraOpened()));
-}
-
-QCamera::State BbCameraControl::state() const
-{
- return m_session->state();
-}
-
-void BbCameraControl::setState(QCamera::State state)
-{
- m_session->setState(state);
-}
-
-QCamera::CaptureModes BbCameraControl::captureMode() const
-{
- return m_session->captureMode();
-}
-
-void BbCameraControl::setCaptureMode(QCamera::CaptureModes mode)
-{
- m_session->setCaptureMode(mode);
-}
-
-QCamera::Status BbCameraControl::status() const
-{
- return m_session->status();
-}
-
-void BbCameraControl::setCamera(const QCameraDevice &camera)
-{
- m_session->setDevice(camera.id());
-}
-
-bool BbCameraControl::isCaptureModeSupported(QCamera::CaptureModes mode) const
-{
- return m_session->isCaptureModeSupported(mode);
-}
-
-void BbCameraControl::cameraOpened()
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameracontrol_p.h b/src/multimedia/platform/qnx/camera/bbcameracontrol_p.h
deleted file mode 100644
index 4990f6517..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameracontrol_p.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERACONTROL_H
-#define BBCAMERACONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformcamera_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraControl : public QPlatformCamera
-{
- Q_OBJECT
-public:
- explicit BbCameraControl(BbCameraSession *session, QObject *parent = 0);
-
- QCamera::State state() const override;
- void setState(QCamera::State state) override;
-
- QCamera::Status status() const override;
-
- void setCamera(const QCameraDevice &camera) override;
-
- QCamera::CaptureModes captureMode() const override;
- void setCaptureMode(QCamera::CaptureModes) override;
- bool isCaptureModeSupported(QCamera::CaptureModes mode) const override;
-
- enum LocksApplyMode
- {
- IndependentMode,
- FocusExposureBoundMode,
- AllBoundMode,
- FocusOnlyMode
- };
-
-private Q_SLOTS:
- void cameraOpened();
-
-private:
- BbCameraSession *m_session;
-
-private:
- BbCameraSession *m_session;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameraexposurecontrol.cpp b/src/multimedia/platform/qnx/camera/bbcameraexposurecontrol.cpp
deleted file mode 100644
index 81ab2ba7f..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraexposurecontrol.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameraexposurecontrol_p.h"
-
-#include "bbcamerasession_p.h"
-
-#include <QDebug>
-
-QT_BEGIN_NAMESPACE
-
-BbCameraExposureControl::BbCameraExposureControl(BbCameraSession *session, QObject *parent)
- : QPlatformCameraExposure(parent)
- , m_session(session)
- , m_requestedExposureMode(QCamera::ExposureAuto)
-{
- connect(m_session, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(statusChanged(QCamera::Status)));
-}
-
-bool BbCameraExposureControl::isParameterSupported(ExposureParameter parameter) const
-{
- switch (parameter) {
- case QPlatformCameraExposure::ISO:
- return false;
- case QPlatformCameraExposure::ShutterSpeed:
- return false;
- case QPlatformCameraExposure::ExposureCompensation:
- return false;
- case QPlatformCameraExposure::FlashPower:
- return false;
- case QPlatformCameraExposure::FlashCompensation:
- return false;
- case QPlatformCameraExposure::TorchPower:
- return false;
- case QPlatformCameraExposure::ExposureMode:
- return true;
- case QPlatformCameraExposure::MeteringMode:
- return false;
- default:
- return false;
- }
-}
-
-QVariantList BbCameraExposureControl::supportedParameterRange(ExposureParameter parameter, bool *continuous) const
-{
- if (parameter != QPlatformCameraExposure::ExposureMode) // no other parameter supported by BB10 API at the moment
- return QVariantList();
-
- if (m_session->status() != QCamera::ActiveStatus) // we can query supported exposure modes only with active viewfinder
- return QVariantList();
-
- if (continuous)
- *continuous = false;
-
- int supported = 0;
- camera_scenemode_t modes[20];
- const camera_error_t result = camera_get_scene_modes(m_session->handle(), 20, &supported, modes);
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve supported scene modes:" << result;
- return QVariantList();
- }
-
- QVariantList exposureModes;
- for (int i = 0; i < supported; ++i) {
- switch (modes[i]) {
- case CAMERA_SCENE_AUTO:
- exposureModes << QVariant::fromValue(QCamera::ExposureAuto);
- break;
- case CAMERA_SCENE_SPORTS:
- exposureModes << QVariant::fromValue(QCamera::ExposureSports);
- break;
- case CAMERA_SCENE_CLOSEUP:
- exposureModes << QVariant::fromValue(QCamera::ExposurePortrait);
- break;
- case CAMERA_SCENE_ACTION:
- exposureModes << QVariant::fromValue(QCamera::ExposureSports);
- break;
- case CAMERA_SCENE_BEACHANDSNOW:
- exposureModes << QVariant::fromValue(QCamera::ExposureBeach) << QVariant::fromValue(QCamera::ExposureSnow);
- break;
- case CAMERA_SCENE_NIGHT:
- exposureModes << QVariant::fromValue(QCamera::ExposureNight);
- break;
- default: break;
- }
- }
-
- return exposureModes;
-}
-
-QVariant BbCameraExposureControl::requestedValue(ExposureParameter parameter) const
-{
- if (parameter != QPlatformCameraExposure::ExposureMode) // no other parameter supported by BB10 API at the moment
- return QVariant();
-
- return QVariant::fromValue(m_requestedExposureMode);
-}
-
-QVariant BbCameraExposureControl::actualValue(ExposureParameter parameter) const
-{
- if (parameter != QPlatformCameraExposure::ExposureMode) // no other parameter supported by BB10 API at the moment
- return QVariantList();
-
- if (m_session->status() != QCamera::ActiveStatus) // we can query actual scene modes only with active viewfinder
- return QVariantList();
-
- camera_scenemode_t sceneMode = CAMERA_SCENE_DEFAULT;
- const camera_error_t result = camera_get_scene_mode(m_session->handle(), &sceneMode);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve scene mode:" << result;
- return QVariant();
- }
-
- switch (sceneMode) {
- case CAMERA_SCENE_AUTO:
- return QVariant::fromValue(QCamera::ExposureAuto);
- case CAMERA_SCENE_SPORTS:
- return QVariant::fromValue(QCamera::ExposureSports);
- case CAMERA_SCENE_CLOSEUP:
- return QVariant::fromValue(QCamera::ExposurePortrait);
- case CAMERA_SCENE_ACTION:
- return QVariant::fromValue(QCamera::ExposureSports);
- case CAMERA_SCENE_BEACHANDSNOW:
- return (m_requestedExposureMode == QCamera::ExposureBeach ? QVariant::fromValue(QCamera::ExposureBeach)
- : QVariant::fromValue(QCamera::ExposureSnow));
- case CAMERA_SCENE_NIGHT:
- return QVariant::fromValue(QCamera::ExposureNight);
- default:
- break;
- }
-
- return QVariant();
-}
-
-bool BbCameraExposureControl::setValue(ExposureParameter parameter, const QVariant& value)
-{
- if (parameter != QPlatformCameraExposure::ExposureMode) // no other parameter supported by BB10 API at the moment
- return false;
-
- if (m_session->status() != QCamera::ActiveStatus) // we can set actual scene modes only with active viewfinder
- return false;
-
- camera_scenemode_t sceneMode = CAMERA_SCENE_DEFAULT;
-
- if (value.isValid()) {
- m_requestedExposureMode = value.value<QCamera::ExposureMode>();
- emit requestedValueChanged(QPlatformCameraExposure::ExposureMode);
-
- switch (m_requestedExposureMode) {
- case QCamera::ExposureAuto:
- sceneMode = CAMERA_SCENE_AUTO;
- break;
- case QCamera::ExposureSports:
- sceneMode = CAMERA_SCENE_SPORTS;
- break;
- case QCamera::ExposurePortrait:
- sceneMode = CAMERA_SCENE_CLOSEUP;
- break;
- case QCamera::ExposureBeach:
- sceneMode = CAMERA_SCENE_BEACHANDSNOW;
- break;
- case QCamera::ExposureSnow:
- sceneMode = CAMERA_SCENE_BEACHANDSNOW;
- break;
- case QCamera::ExposureNight:
- sceneMode = CAMERA_SCENE_NIGHT;
- break;
- default:
- sceneMode = CAMERA_SCENE_DEFAULT;
- break;
- }
- }
-
- const camera_error_t result = camera_set_scene_mode(m_session->handle(), sceneMode);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to set scene mode:" << result;
- return false;
- }
-
- emit actualValueChanged(QPlatformCameraExposure::ExposureMode);
-
- return true;
-}
-
-void BbCameraExposureControl::statusChanged(QCamera::Status status)
-{
- if (status == QCamera::ActiveStatus || status == QCamera::LoadedStatus)
- emit parameterRangeChanged(QPlatformCameraExposure::ExposureMode);
-}
-
-QCamera::FlashModes BbCameraExposureControl::flashMode() const
-{
- return m_flashMode;
-}
-
-void BbCameraExposureControl::setFlashMode(QCamera::FlashModes mode)
-{
- if (m_flashMode == mode)
- return;
-
- if (m_session->status() != QCamera::ActiveStatus) // can only be changed when viewfinder is active
- return;
-
-// if (m_flashMode == QCamera::FlashVideoLight) {
-// const camera_error_t result = camera_config_videolight(m_session->handle(), CAMERA_VIDEOLIGHT_OFF);
-// if (result != CAMERA_EOK)
-// qWarning() << "Unable to switch off video light:" << result;
-// }
-
- m_flashMode = mode;
-
-// if (m_flashMode == QCamera::FlashVideoLight) {
-// const camera_error_t result = camera_config_videolight(m_session->handle(), CAMERA_VIDEOLIGHT_ON);
-// if (result != CAMERA_EOK)
-// qWarning() << "Unable to switch on video light:" << result;
-// } else
- {
- camera_flashmode_t flashMode = CAMERA_FLASH_AUTO;
-
- if (m_flashMode == QCamera::FlashAuto)
- flashMode = CAMERA_FLASH_AUTO;
- else if (mode == QCamera::FlashOff)
- flashMode = CAMERA_FLASH_OFF;
- else if (mode == QCamera::FlashOn)
- flashMode = CAMERA_FLASH_ON;
-
- const camera_error_t result = camera_config_flash(m_session->handle(), flashMode);
- if (result != CAMERA_EOK)
- qWarning() << "Unable to configure flash:" << result;
- }
-}
-
-bool BbCameraExposureControl::isFlashModeSupported(QCamera::FlashModes mode) const
-{
- // ### Videolight maps to QCamera::TorchOn.
-// bool supportsVideoLight = false;
-// if (m_session->handle() != CAMERA_HANDLE_INVALID) {
-// supportsVideoLight = camera_has_feature(m_session->handle(), CAMERA_FEATURE_VIDEOLIGHT);
-// }
-
- // ### is this correct?
- return true;
-}
-
-bool BbCameraExposureControl::isFlashReady() const
-{
- //TODO: check for flash charge-level here?!?
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameraexposurecontrol_p.h b/src/multimedia/platform/qnx/camera/bbcameraexposurecontrol_p.h
deleted file mode 100644
index 60ffcd0f0..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraexposurecontrol_p.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAEXPOSURECONTROL_H
-#define BBCAMERAEXPOSURECONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformcameraexposure_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraExposureControl : public QPlatformCameraExposure
-{
- Q_OBJECT
-public:
- explicit BbCameraExposureControl(BbCameraSession *session, QObject *parent = 0);
-
- bool isParameterSupported(ExposureParameter parameter) const override;
- QVariantList supportedParameterRange(ExposureParameter parameter, bool *continuous) const override;
-
- QVariant requestedValue(ExposureParameter parameter) const override;
- QVariant actualValue(ExposureParameter parameter) const override;
- bool setValue(ExposureParameter parameter, const QVariant& value) override;
-
- QCamera::FlashMode flashMode() const override;
- void setFlashMode(QCamera::FlashMode mode) override;
- bool isFlashModeSupported(QCamera::FlashMode mode) const override;
- bool isFlashReady() const override;
-
-private Q_SLOTS:
- void statusChanged(QCamera::Status status);
-
-private:
- BbCameraSession *m_session;
- QCamera::ExposureMode m_requestedExposureMode;
-
- QCamera::FlashMode m_flashMode = QCamera::FlashAuto;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcamerafocuscontrol.cpp b/src/multimedia/platform/qnx/camera/bbcamerafocuscontrol.cpp
deleted file mode 100644
index 20d2d540a..000000000
--- a/src/multimedia/platform/qnx/camera/bbcamerafocuscontrol.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcamerafocuscontrol_p.h"
-
-#include "bbcamerasession_p.h"
-
-#include <QDebug>
-
-QT_BEGIN_NAMESPACE
-
-BbCameraFocusControl::BbCameraFocusControl(BbCameraSession *session, QObject *parent)
- : QPlatformCameraFocus(parent)
- , m_session(session)
- , m_focusMode(QCamera::FocusModeAuto)
- , m_customFocusPoint(QPointF(0, 0))
-{
- connect(m_session, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(statusChanged(QCamera::Status)));
-}
-
-QCamera::FocusMode BbCameraFocusControl::focusMode() const
-{
- camera_focusmode_t focusMode = CAMERA_FOCUSMODE_OFF;
-
- const camera_error_t result = camera_get_focus_mode(m_session->handle(), &focusMode);
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve focus mode from camera:" << result;
- return QCamera::FocusModeAuto;
- }
-
- switch (focusMode) {
- case CAMERA_FOCUSMODE_EDOF:
- return QCamera::FocusModeHyperfocal;
- case CAMERA_FOCUSMODE_MANUAL:
- return QCamera::FocusModeManual;
- case CAMERA_FOCUSMODE_CONTINUOUS_MACRO: // fall through
- case CAMERA_FOCUSMODE_MACRO:
- return QCamera::FocusModeAutoNear;
- case CAMERA_FOCUSMODE_AUTO: // fall through
- case CAMERA_FOCUSMODE_CONTINUOUS_AUTO:
- return QCamera::FocusModeAuto;
- case CAMERA_FOCUSMODE_OFF:
- default:
- return QCamera::FocusModeAuto;
- }
-}
-
-void BbCameraFocusControl::setFocusMode(QCamera::FocusMode mode)
-{
- if (m_focusMode == mode)
- return;
-
- camera_focusmode_t focusMode = CAMERA_FOCUSMODE_OFF;
-
- switch (mode) {
- case QCamera::FocusModeHyperfocal:
- case QCamera::FocusModeInfinity: // not 100%, but close
- focusMode = CAMERA_FOCUSMODE_EDOF;
- break;
- case QCamera::FocusModeManual:
- focusMode = CAMERA_FOCUSMODE_MANUAL;
- break;
- case QCamera::FocusModeAutoNear:
- focusMode = CAMERA_FOCUSMODE_MACRO;
- break;
- case QCamera::FocusModeAuto:
- case QCamera::FocusModeAutoFar:
- focusMode = CAMERA_FOCUSMODE_CONTINUOUS_AUTO;
- break;
- }
-
- const camera_error_t result = camera_set_focus_mode(m_session->handle(), focusMode);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to set focus mode:" << result;
- return;
- }
-
- m_focusMode = mode;
- emit focusModeChanged(m_focusMode);
-}
-
-bool BbCameraFocusControl::isFocusModeSupported(QCamera::FocusMode mode) const
-{
- if (m_session->state() == QCamera::UnloadedState)
- return false;
-
- if (mode == QCamera::FocusModeHyperfocal)
- return false; //TODO how to check?
- else if (mode == QCamera::FocusModeManual)
- return camera_has_feature(m_session->handle(), CAMERA_FEATURE_MANUALFOCUS);
- else if (mode == QCamera::FocusModeAuto)
- return camera_has_feature(m_session->handle(), CAMERA_FEATURE_AUTOFOCUS);
- else if (mode == QCamera::FocusModeAutoNear)
- return camera_has_feature(m_session->handle(), CAMERA_FEATURE_MACROFOCUS);
-
- return false;
-}
-
-QPointF BbCameraFocusControl::focusPoint() const
-{
- return m_customFocusPoint;
-}
-
-void BbCameraFocusControl::setCustomFocusPoint(const QPointF &point)
-{
- if (m_customFocusPoint == point)
- return;
-
- m_customFocusPoint = point;
- emit customFocusPointChanged(m_customFocusPoint);
-
- updateCustomFocusRegion();
-}
-
-void BbCameraFocusControl::updateCustomFocusRegion()
-{
- // get the size of the viewfinder
- int viewfinderWidth = 0;
- int viewfinderHeight = 0;
-
- if (!retrieveViewfinderSize(&viewfinderWidth, &viewfinderHeight))
- return;
-
- // define a 40x40 pixel focus region around the custom focus point
- camera_region_t focusRegion;
- focusRegion.left = qMax(0, static_cast<int>(m_customFocusPoint.x() * viewfinderWidth) - 20);
- focusRegion.top = qMax(0, static_cast<int>(m_customFocusPoint.y() * viewfinderHeight) - 20);
- focusRegion.width = 40;
- focusRegion.height = 40;
-
- camera_error_t result = camera_set_focus_regions(m_session->handle(), 1, &focusRegion);
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to set focus region:" << result;
- return;
- }
-
- // re-set focus mode to apply focus region changes
- camera_focusmode_t focusMode = CAMERA_FOCUSMODE_OFF;
- result = camera_get_focus_mode(m_session->handle(), &focusMode);
- camera_set_focus_mode(m_session->handle(), focusMode);
-}
-
-bool BbCameraFocusControl::retrieveViewfinderSize(int *width, int *height)
-{
- if (!width || !height)
- return false;
-
- camera_error_t result = CAMERA_EOK;
- if (m_session->captureMode() & QCamera::CaptureStillImage)
- result = camera_get_photovf_property(m_session->handle(),
- CAMERA_IMGPROP_WIDTH, width,
- CAMERA_IMGPROP_HEIGHT, height);
- else if (m_session->captureMode() & QCamera::CaptureVideo)
- result = camera_get_videovf_property(m_session->handle(),
- CAMERA_IMGPROP_WIDTH, width,
- CAMERA_IMGPROP_HEIGHT, height);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve viewfinder size:" << result;
- return false;
- }
-
- return true;
-}
-
-
-qreal BbCameraFocusControl::maximumOpticalZoom() const
-{
- //TODO: optical zoom support not available in BB10 API yet
- return 1.0;
-}
-
-qreal BbCameraFocusControl::maximumDigitalZoom() const
-{
- return m_maximumZoomFactor;
-}
-
-qreal BbCameraFocusControl::requestedOpticalZoom() const
-{
- //TODO: optical zoom support not available in BB10 API yet
- return 1.0;
-}
-
-qreal BbCameraFocusControl::requestedDigitalZoom() const
-{
- return currentDigitalZoom();
-}
-
-qreal BbCameraFocusControl::currentOpticalZoom() const
-{
- //TODO: optical zoom support not available in BB10 API yet
- return 1.0;
-}
-
-qreal BbCameraFocusControl::currentDigitalZoom() const
-{
- if (m_session->status() != QCamera::ActiveStatus)
- return 1.0;
-
- unsigned int zoomFactor = 0;
- camera_error_t result = CAMERA_EOK;
-
- if (m_session->captureMode() & QCamera::CaptureStillImage)
- result = camera_get_photovf_property(m_session->handle(), CAMERA_IMGPROP_ZOOMFACTOR, &zoomFactor);
- else if (m_session->captureMode() & QCamera::CaptureVideo)
- result = camera_get_videovf_property(m_session->handle(), CAMERA_IMGPROP_ZOOMFACTOR, &zoomFactor);
-
- if (result != CAMERA_EOK)
- return 1.0;
-
- return zoomFactor;
-}
-
-void BbCameraFocusControl::zoomTo(qreal optical, qreal digital)
-{
- Q_UNUSED(optical);
-
- if (m_session->status() != QCamera::ActiveStatus)
- return;
-
- const qreal actualZoom = qBound(m_minimumZoomFactor, digital, m_maximumZoomFactor);
-
- const camera_error_t result = camera_set_zoom(m_session->handle(), actualZoom, false);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to change zoom factor:" << result;
- return;
- }
-
- if (m_requestedZoomFactor != digital) {
- m_requestedZoomFactor = digital;
- emit requestedDigitalZoomChanged(m_requestedZoomFactor);
- }
-
- emit currentDigitalZoomChanged(actualZoom);
-}
-
-void BbCameraFocusControl::statusChanged(QCamera::Status status)
-{
- if (status == QCamera::ActiveStatus) {
- // retrieve information about zoom limits
- unsigned int maximumZoomLimit = 0;
- unsigned int minimumZoomLimit = 0;
- bool smoothZoom = false;
-
- const camera_error_t result = camera_get_zoom_limits(m_session->handle(), &maximumZoomLimit, &minimumZoomLimit, &smoothZoom);
- if (result == CAMERA_EOK) {
- const qreal oldMaximumZoomFactor = m_maximumZoomFactor;
- m_maximumZoomFactor = maximumZoomLimit;
-
- if (oldMaximumZoomFactor != m_maximumZoomFactor)
- emit maximumDigitalZoomChanged(m_maximumZoomFactor);
-
- m_minimumZoomFactor = minimumZoomLimit;
- m_supportsSmoothZoom = smoothZoom;
- } else {
- m_maximumZoomFactor = 1.0;
- m_minimumZoomFactor = 1.0;
- m_supportsSmoothZoom = false;
- }
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcamerafocuscontrol_p.h b/src/multimedia/platform/qnx/camera/bbcamerafocuscontrol_p.h
deleted file mode 100644
index 895701283..000000000
--- a/src/multimedia/platform/qnx/camera/bbcamerafocuscontrol_p.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAFOCUSCONTROL_H
-#define BBCAMERAFOCUSCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformcamerafocus_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraFocusControl : public QPlatformCameraFocus
-{
- Q_OBJECT
-public:
- explicit BbCameraFocusControl(BbCameraSession *session, QObject *parent = 0);
-
- QCamera::FocusMode focusMode() const override;
- void setFocusMode(QCamera::FocusMode mode) override;
- bool isFocusModeSupported(QCamera::FocusMode mode) const override;
- QPointF focusPoint() const override;
- void setCustomFocusPoint(const QPointF &point) override;
-
- qreal maximumOpticalZoom() const override;
- qreal maximumDigitalZoom() const override;
- qreal requestedOpticalZoom() const override;
- qreal requestedDigitalZoom() const override;
- qreal currentOpticalZoom() const override;
- qreal currentDigitalZoom() const override;
- void zoomTo(qreal optical, qreal digital) override;
-
-private Q_SLOTS:
- void statusChanged(QCamera::Status status);
-
-private:
- void updateCustomFocusRegion();
- bool retrieveViewfinderSize(int *width, int *height);
-
- BbCameraSession *m_session;
-
- QCamera::FocusMode m_focusMode;
- QPointF m_customFocusPoint;
-
- qreal m_minimumZoomFactor;
- qreal m_maximumZoomFactor;
- bool m_supportsSmoothZoom;
- qreal m_requestedZoomFactor;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol.cpp b/src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol.cpp
deleted file mode 100644
index 5a78e1ee0..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameraimagecapturecontrol_p.h"
-
-#include "bbcamerasession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-BbCameraImageCaptureControl::BbCameraImageCaptureControl(BbCameraSession *session, QObject *parent)
- : QPlatformImageCapture(parent)
- , m_session(session)
-{
- connect(m_session, SIGNAL(readyForCaptureChanged(bool)), this, SIGNAL(readyForCaptureChanged(bool)));
- connect(m_session, SIGNAL(imageExposed(int)), this, SIGNAL(imageExposed(int)));
- connect(m_session, SIGNAL(imageCaptured(int,QImage)), this, SIGNAL(imageCaptured(int,QImage)));
- connect(m_session, SIGNAL(imageMetadataAvailable(int,QString,QVariant)), this, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
- connect(m_session, SIGNAL(imageAvailable(int,QVideoFrame)), this, SIGNAL(imageAvailable(int,QVideoFrame)));
- connect(m_session, SIGNAL(imageSaved(int,QString)), this, SIGNAL(imageSaved(int,QString)));
- connect(m_session, SIGNAL(imageCaptureError(int,int,QString)), this, SIGNAL(error(int,int,QString)));
-}
-
-bool BbCameraImageCaptureControl::isReadyForCapture() const
-{
- return m_session->isReadyForCapture();
-}
-
-int BbCameraImageCaptureControl::capture(const QString &fileName)
-{
- return m_session->capture(fileName);
-}
-
-int BbCameraImageCaptureControl::captureToBuffer()
-{
- // ### implement me
- return -1;
-}
-
-void BbCameraImageCaptureControl::cancelCapture()
-{
- m_session->cancelCapture();
-}
-
-QImageEncoderSettings BbCameraImageCaptureControl::imageSettings() const
-{
- return m_session->imageSettings();
-}
-
-void BbCameraImageCaptureControl::setImageSettings(const QImageEncoderSettings &settings)
-{
- m_session->setImageSettings(settings);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol_p.h b/src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol_p.h
deleted file mode 100644
index 62ba19c97..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraimagecapturecontrol_p.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAIMAGECAPTURECONTROL_H
-#define BBCAMERAIMAGECAPTURECONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformimagecapture_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraImageCaptureControl : public QPlatformImageCapture
-{
- Q_OBJECT
-public:
- explicit BbCameraImageCaptureControl(BbCameraSession *session, QObject *parent = 0);
-
- bool isReadyForCapture() const override;
-
- int capture(const QString &fileName) override;
- int captureToBuffer() override;
- void cancelCapture() override;
-
- QImageEncoderSettings imageSettings() const override;
- void setImageSettings(const QImageEncoderSettings &settings) override;
-
-private:
- BbCameraSession *m_session;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol.cpp b/src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol.cpp
deleted file mode 100644
index 08e468eea..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameraimageprocessingcontrol_p.h"
-
-#include "bbcamerasession_p.h"
-
-#include <QDebug>
-
-QT_BEGIN_NAMESPACE
-
-BbCameraImageProcessingControl::BbCameraImageProcessingControl(BbCameraSession *session, QObject *parent)
- : QPlatformCameraImageProcessing(parent)
- , m_session(session)
-{
-}
-
-bool BbCameraImageProcessingControl::isParameterSupported(ProcessingParameter parameter) const
-{
- return (parameter == QPlatformCameraImageProcessing::WhiteBalancePreset);
-}
-
-bool BbCameraImageProcessingControl::isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const
-{
- if (parameter != QPlatformCameraImageProcessing::WhiteBalancePreset)
- return false;
-
- if (m_session->handle() == CAMERA_HANDLE_INVALID)
- return false;
-
- int supported = 0;
- camera_whitebalancemode_t modes[20];
- const camera_error_t result = camera_get_whitebalance_modes(m_session->handle(), 20, &supported, modes);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve supported whitebalance modes:" << result;
- return false;
- }
-
- QSet<QCamera::WhiteBalanceMode> supportedModes;
- for (int i = 0; i < supported; ++i) {
- switch (modes[i]) {
- case CAMERA_WHITEBALANCEMODE_AUTO:
- supportedModes.insert(QCamera::WhiteBalanceAuto);
- break;
- case CAMERA_WHITEBALANCEMODE_MANUAL:
- supportedModes.insert(QCamera::WhiteBalanceManual);
- break;
- default:
- break;
- }
- }
-
- return supportedModes.contains(value.value<QCamera::WhiteBalanceMode>());
-}
-
-void BbCameraImageProcessingControl::setParameter(ProcessingParameter parameter, const QVariant &value)
-{
- if (parameter != QPlatformCameraImageProcessing::WhiteBalancePreset)
- return;
-
- if (m_session->handle() == CAMERA_HANDLE_INVALID)
- return;
-
- camera_whitebalancemode_t mode = CAMERA_WHITEBALANCEMODE_DEFAULT;
- switch (value.value<QCamera::WhiteBalanceMode>()) {
- case QCamera::WhiteBalanceAuto:
- mode = CAMERA_WHITEBALANCEMODE_AUTO;
- break;
- case QCamera::WhiteBalanceManual:
- mode = CAMERA_WHITEBALANCEMODE_MANUAL;
- break;
- default:
- break;
- }
-
- const camera_error_t result = camera_set_whitebalance_mode(m_session->handle(), mode);
-
- if (result != CAMERA_EOK)
- qWarning() << "Unable to set whitebalance mode:" << result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol_p.h b/src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol_p.h
deleted file mode 100644
index 6a0af4a85..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraimageprocessingcontrol_p.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAIMAGEPROCESSINGCONTROL_H
-#define BBCAMERAIMAGEPROCESSINGCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformcameraimageprocessing_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraImageProcessingControl : public QPlatformCameraImageProcessing
-{
- Q_OBJECT
-public:
- explicit BbCameraImageProcessingControl(BbCameraSession *session, QObject *parent = 0);
-
- bool isParameterSupported(ProcessingParameter) const override;
- bool isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const override;
- void setParameter(ProcessingParameter parameter, const QVariant &value) override;
-
-private:
- BbCameraSession *m_session;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol.cpp b/src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol.cpp
deleted file mode 100644
index a90ae33be..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameramediarecordercontrol_p.h"
-
-#include "bbcamerasession_p.h"
-
-#include <QDebug>
-#include <QUrl>
-
-#include <audio/audio_manager_device.h>
-#include <audio/audio_manager_volume.h>
-
-QT_BEGIN_NAMESPACE
-
-static audio_manager_device_t currentAudioInputDevice()
-{
- audio_manager_device_t device = AUDIO_DEVICE_HEADSET;
-
- const int result = audio_manager_get_default_input_device(&device);
- if (result != EOK) {
- qWarning() << "Unable to retrieve default audio input device:" << result;
- return AUDIO_DEVICE_HEADSET;
- }
-
- return device;
-}
-
-BbCameraMediaRecorderControl::BbCameraMediaRecorderControl(BbCameraSession *session, QObject *parent)
- : QPlatformMediaEncoder(parent)
- , m_session(session)
-{
- connect(m_session, SIGNAL(videoStateChanged(QMediaRecorder::RecorderState)), this, SIGNAL(stateChanged(QMediaRecorder::RecorderState)));
- connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64)));
- connect(m_session, SIGNAL(actualLocationChanged(QUrl)), this, SIGNAL(actualLocationChanged(QUrl)));
- connect(m_session, SIGNAL(videoError(int,QString)), this, SIGNAL(error(int,QString)));
-}
-
-bool BbCameraMediaRecorderControl::isLocationWritable(const QUrl &location) const
-{
- return true;
-}
-
-QMediaRecorder::RecorderState BbCameraMediaRecorderControl::state() const
-{
- return m_session->videoState();
-}
-
-qint64 BbCameraMediaRecorderControl::duration() const
-{
- return m_session->duration();
-}
-
-bool BbCameraMediaRecorderControl::isMuted() const
-{
- bool muted = false;
-
- const int result = audio_manager_get_input_mute(currentAudioInputDevice(), &muted);
- if (result != EOK) {
- emit const_cast<BbCameraMediaRecorderControl*>(this)->error(QMediaRecorder::ResourceError, tr("Unable to retrieve mute status"));
- return false;
- }
-
- return muted;
-}
-
-qreal BbCameraMediaRecorderControl::volume() const
-{
- double level = 0.0;
-
- const int result = audio_manager_get_input_level(currentAudioInputDevice(), &level);
- if (result != EOK) {
- emit const_cast<BbCameraMediaRecorderControl*>(this)->error(QMediaRecorder::ResourceError, tr("Unable to retrieve audio input volume"));
- return 0.0;
- }
-
- return (level / 100);
-}
-
-void BbCameraMediaRecorderControl::record(QMediaEncoderSettings &)
-{
- if (m_session) {
- m_session->applyVideoSettings();
- m_session->startVideoRecording(outputLocation());
- }
-}
-
-void BbCameraMediaRecorderControl::stop()
-{
- if (m_session)
- m_session->stopVideoRecording();
-}
-
-void BbCameraMediaRecorderControl::setMuted(bool muted)
-{
- const int result = audio_manager_set_input_mute(currentAudioInputDevice(), muted);
- if (result != EOK) {
- emit error(QMediaRecorder::ResourceError, tr("Unable to set mute status"));
- } else {
- emit mutedChanged(muted);
- }
-}
-
-void BbCameraMediaRecorderControl::setVolume(qreal volume)
-{
- const int result = audio_manager_set_input_level(currentAudioInputDevice(), (volume * 100));
- if (result != EOK) {
- emit error(QMediaRecorder::ResourceError, tr("Unable to set audio input volume"));
- } else {
- emit volumeChanged(volume);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol_p.h b/src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol_p.h
deleted file mode 100644
index 5ea453a0b..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameramediarecordercontrol_p.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAMEDIARECORDERCONTROL_H
-#define BBCAMERAMEDIARECORDERCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaencoder_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraMediaRecorderControl : public QPlatformMediaEncoder
-{
- Q_OBJECT
-public:
- explicit BbCameraMediaRecorderControl(BbCameraSession *session, QObject *parent = 0);
-
- QMediaRecorder::RecorderState state() const override;
- bool isLocationWritable(const QUrl &location) const override;
- qint64 duration() const override;
- bool isMuted() const override;
- qreal volume() const override;
- void record(QMediaEncoderSettings &settings) override;
- void stop() override;
-
-
-public Q_SLOTS:
- void setMuted(bool muted) override;
- void setVolume(qreal volume) override;
-
-private:
- BbCameraSession *m_session;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameraorientationhandler.cpp b/src/multimedia/platform/qnx/camera/bbcameraorientationhandler.cpp
deleted file mode 100644
index d600f3db0..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraorientationhandler.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameraorientationhandler.h"
-
-#include <QAbstractEventDispatcher>
-#include <QGuiApplication>
-#include <QScreen>
-#include <QDebug>
-
-#include <bps/orientation.h>
-
-QT_BEGIN_NAMESPACE
-
-BbCameraOrientationHandler::BbCameraOrientationHandler(QObject *parent)
- : QObject(parent)
- , m_orientation(0)
-{
- QCoreApplication::eventDispatcher()->installNativeEventFilter(this);
- int result = orientation_request_events(0);
- if (result == BPS_FAILURE)
- qWarning() << "Unable to register for orientation change events";
-
- orientation_direction_t direction = ORIENTATION_FACE_UP;
- int angle = 0;
-
- result = orientation_get(&direction, &angle);
- if (result == BPS_FAILURE) {
- qWarning() << "Unable to retrieve initial orientation";
- } else {
- m_orientation = angle;
- }
-}
-
-BbCameraOrientationHandler::~BbCameraOrientationHandler()
-{
- const int result = orientation_stop_events(0);
- if (result == BPS_FAILURE)
- qWarning() << "Unable to unregister for orientation change events";
-
- QCoreApplication::eventDispatcher()->removeNativeEventFilter(this);
-}
-
-bool BbCameraOrientationHandler::nativeEventFilter(const QByteArray&, void *message, qintptr *)
-{
- bps_event_t* const event = static_cast<bps_event_t*>(message);
- if (!event || bps_event_get_domain(event) != orientation_get_domain())
- return false;
-
- const int angle = orientation_event_get_angle(event);
- if (angle != m_orientation) {
- if (angle == 180) // The screen does not rotate at 180 degrees
- return false;
-
- m_orientation = angle;
- emit orientationChanged(m_orientation);
- }
-
- return false; // do not drop the event
-}
-
-int BbCameraOrientationHandler::viewfinderOrientation() const
-{
- // On a keyboard device we do not rotate the screen at all
- if (qGuiApp->primaryScreen()->nativeOrientation()
- != qGuiApp->primaryScreen()->primaryOrientation()) {
- return m_orientation;
- }
-
- return 0;
-}
-
-int BbCameraOrientationHandler::orientation() const
-{
- return m_orientation;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameraorientationhandler_p.h b/src/multimedia/platform/qnx/camera/bbcameraorientationhandler_p.h
deleted file mode 100644
index ace5118ef..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraorientationhandler_p.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAORIENTATIONHANDLER_H
-#define BBCAMERAORIENTATIONHANDLER_H
-
-#include <QAbstractNativeEventFilter>
-#include <QObject>
-
-//
-// 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 BbCameraOrientationHandler : public QObject, public QAbstractNativeEventFilter
-{
- Q_OBJECT
-public:
- explicit BbCameraOrientationHandler(QObject *parent = 0);
- ~BbCameraOrientationHandler();
-
- bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override;
-
- int orientation() const;
-
- int viewfinderOrientation() const;
-
-Q_SIGNALS:
- void orientationChanged(int degree);
-
-private:
- int m_orientation;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameraservice.cpp b/src/multimedia/platform/qnx/camera/bbcameraservice.cpp
deleted file mode 100644
index 6f68e68ed..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraservice.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameraservice_p.h"
-
-#include "bbcameraaudioencodersettingscontrol_p.h"
-#include "bbcameracontrol_p.h"
-#include "bbcameraexposurecontrol_p.h"
-#include "bbcamerafocuscontrol_p.h"
-#include "bbcameraimagecapturecontrol_p.h"
-#include "bbcameraimageprocessingcontrol_p.h"
-#include "bbcameramediarecordercontrol_p.h"
-#include "bbcamerasession_p.h"
-#include "bbcameravideoencodersettingscontrol_p.h"
-#include "bbvideorenderercontrol_p.h"
-
-#include <QDebug>
-#include <QVariant>
-
-QT_BEGIN_NAMESPACE
-
-BbCameraService::BbCameraService(QObject *parent)
- : QObject(parent)
- , m_cameraSession(new BbCameraSession(this))
- , m_cameraAudioEncoderSettingsControl(new BbCameraAudioEncoderSettingsControl(m_cameraSession, this))
- , m_cameraControl(new BbCameraControl(m_cameraSession, this))
- , m_cameraExposureControl(new BbCameraExposureControl(m_cameraSession, this))
- , m_cameraFocusControl(new BbCameraFocusControl(m_cameraSession, this))
- , m_cameraImageCaptureControl(new BbCameraImageCaptureControl(m_cameraSession, this))
- , m_cameraImageProcessingControl(new BbCameraImageProcessingControl(m_cameraSession, this))
- , m_cameraMediaRecorderControl(new BbCameraMediaRecorderControl(m_cameraSession, this))
- , m_cameraVideoEncoderSettingsControl(new BbCameraVideoEncoderSettingsControl(m_cameraSession, this))
- , m_videoRendererControl(new BbVideoRendererControl(m_cameraSession, this))
-{
-}
-
-BbCameraService::~BbCameraService()
-{
-}
-
-QPlatformCamera *BbCameraService::camera()
-{
- return m_cameraControl;
-}
-
-QPlatformImageCapture *BbCameraService::imageCapture()
-{
- return m_cameraImageCaptureControl;
-}
-
-QPlatformMediaEncoder *BbCameraService::mediaEncoder()
-{
- return m_cameraMediaRecorderControl;
-}
-
-void BbCameraService::setVideoPreview(QVideoSink *surface)
-{
- // ####
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameraservice_p.h b/src/multimedia/platform/qnx/camera/bbcameraservice_p.h
deleted file mode 100644
index 128fc1154..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameraservice_p.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERASERVICE_H
-#define BBCAMERASERVICE_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>
-
-#include <private/qplatformmediacapture_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraAudioEncoderSettingsControl;
-class BbCameraControl;
-class BbCameraExposureControl;
-class BbCameraFocusControl;
-class BbCameraImageCaptureControl;
-class BbCameraImageProcessingControl;
-class BbCameraMediaRecorderControl;
-class BbCameraSession;
-class BbCameraVideoEncoderSettingsControl;
-class BbVideoRendererControl;
-
-class BbCameraService : public QPlatformMediaCaptureSession
-{
- Q_OBJECT
-
-public:
- explicit BbCameraService(QObject *parent = 0);
- ~BbCameraService();
-
- QPlatformCamera *camera() override;
- QPlatformImageCapture *imageCapture() override;
- QPlatformMediaEncoder *mediaEncoder() override;
-
- void setVideoPreview(QVideoSink *surface) override;
-
-private:
- BbCameraSession* m_cameraSession;
-
- BbCameraAudioEncoderSettingsControl* m_cameraAudioEncoderSettingsControl;
- BbCameraControl* m_cameraControl;
- BbCameraExposureControl* m_cameraExposureControl;
- BbCameraFocusControl* m_cameraFocusControl;
- BbCameraImageCaptureControl* m_cameraImageCaptureControl;
- BbCameraImageProcessingControl* m_cameraImageProcessingControl;
- BbCameraMediaRecorderControl* m_cameraMediaRecorderControl;
- BbCameraVideoEncoderSettingsControl* m_cameraVideoEncoderSettingsControl;
- BbVideoRendererControl* m_videoRendererControl;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcamerasession.cpp b/src/multimedia/platform/qnx/camera/bbcamerasession.cpp
deleted file mode 100644
index d82cbe482..000000000
--- a/src/multimedia/platform/qnx/camera/bbcamerasession.cpp
+++ /dev/null
@@ -1,1049 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcamerasession_p.h"
-
-#include "bbcameraorientationhandler_p.h"
-#include "windowgrabber_p.h"
-
-#include <QBuffer>
-#include <QDebug>
-#include <QImage>
-#include <QUrl>
-#include <QVideoFrameFormat>
-#include <qmath.h>
-#include <private/qmediarecorder_p.h>
-#include <private/qplatformimagecapture_p.h>
-#include <private/qmediastoragelocation_p.h>
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-static QString errorToString(camera_error_t error)
-{
- switch (error) {
- case CAMERA_EOK:
- return QLatin1String("No error");
- case CAMERA_EAGAIN:
- return QLatin1String("Camera unavailable");
- case CAMERA_EINVAL:
- return QLatin1String("Invalid argument");
- case CAMERA_ENODEV:
- return QLatin1String("Camera not found");
- case CAMERA_EMFILE:
- return QLatin1String("File table overflow");
- case CAMERA_EBADF:
- return QLatin1String("Invalid handle passed");
- case CAMERA_EACCESS:
- return QLatin1String("No permission");
- case CAMERA_EBADR:
- return QLatin1String("Invalid file descriptor");
- case CAMERA_ENOENT:
- return QLatin1String("File or directory does not exists");
- case CAMERA_ENOMEM:
- return QLatin1String("Memory allocation failed");
- case CAMERA_EOPNOTSUPP:
- return QLatin1String("Operation not supported");
- case CAMERA_ETIMEDOUT:
- return QLatin1String("Communication timeout");
- case CAMERA_EALREADY:
- return QLatin1String("Operation already in progress");
- case CAMERA_EUNINIT:
- return QLatin1String("Camera library not initialized");
- case CAMERA_EREGFAULT:
- return QLatin1String("Callback registration failed");
- case CAMERA_EMICINUSE:
- return QLatin1String("Microphone in use already");
- case CAMERA_ENODATA:
- return QLatin1String("Data does not exist");
- case CAMERA_EBUSY:
- return QLatin1String("Camera busy");
- case CAMERA_EDESKTOPCAMERAINUSE:
- return QLatin1String("Desktop camera in use already");
- case CAMERA_ENOSPC:
- return QLatin1String("Disk is full");
- case CAMERA_EPOWERDOWN:
- return QLatin1String("Camera in power down state");
- case CAMERA_3ALOCKED:
- return QLatin1String("3A have been locked");
-// case CAMERA_EVIEWFINDERFROZEN: // not yet available in 10.2 NDK
-// return QLatin1String("Freeze flag set");
- default:
- return QLatin1String("Unknown error");
- }
-}
-
-QDebug operator<<(QDebug debug, camera_error_t error)
-{
- debug.nospace() << errorToString(error);
- return debug.space();
-}
-
-BbCameraSession::BbCameraSession(QObject *parent)
- : QObject(parent)
- , m_nativeCameraOrientation(0)
- , m_orientationHandler(new BbCameraOrientationHandler(this))
- , m_status(QCamera::UnloadedStatus)
- , m_state(QCamera::UnloadedState)
- , m_captureMode(QCamera::CaptureStillImage)
- , m_device("bb:RearCamera")
- , m_previewIsVideo(true)
- , m_surface(0)
- , m_lastImageCaptureId(0)
- , m_videoState(QMediaRecorder::StoppedState)
- , m_handle(CAMERA_HANDLE_INVALID)
- , m_windowGrabber(new WindowGrabber(this))
-{
- connect(this, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateReadyForCapture()));
- connect(this, SIGNAL(captureModeChanged(QCamera::CaptureModes)), SLOT(updateReadyForCapture()));
- connect(m_orientationHandler, SIGNAL(orientationChanged(int)), SLOT(deviceOrientationChanged(int)));
-
- connect(m_windowGrabber, SIGNAL(frameGrabbed(QImage, int)), SLOT(viewfinderFrameGrabbed(QImage)));
-}
-
-BbCameraSession::~BbCameraSession()
-{
- stopViewFinder();
- closeCamera();
-}
-
-camera_handle_t BbCameraSession::handle() const
-{
- return m_handle;
-}
-
-QCamera::State BbCameraSession::state() const
-{
- return m_state;
-}
-
-void BbCameraSession::setState(QCamera::State state)
-{
- if (m_state == state)
- return;
-
- const QCamera::State previousState = m_state;
-
- if (previousState == QCamera::UnloadedState) {
- if (state == QCamera::LoadedState) {
- if (openCamera()) {
- m_state = state;
- }
- } else if (state == QCamera::ActiveState) {
- if (openCamera()) {
- QMetaObject::invokeMethod(this, "applyConfiguration", Qt::QueuedConnection);
- m_state = state;
- }
- }
- } else if (previousState == QCamera::LoadedState) {
- if (state == QCamera::UnloadedState) {
- closeCamera();
- m_state = state;
- } else if (state == QCamera::ActiveState) {
- QMetaObject::invokeMethod(this, "applyConfiguration", Qt::QueuedConnection);
- m_state = state;
- }
- } else if (previousState == QCamera::ActiveState) {
- if (state == QCamera::LoadedState) {
- stopViewFinder();
- m_state = state;
- } else if (state == QCamera::UnloadedState) {
- stopViewFinder();
- closeCamera();
- m_state = state;
- }
- }
-
- if (m_state != previousState)
- emit stateChanged(m_state);
-}
-
-QCamera::Status BbCameraSession::status() const
-{
- return m_status;
-}
-
-QCamera::CaptureModes BbCameraSession::captureMode() const
-{
- return m_captureMode;
-}
-
-void BbCameraSession::setCaptureMode(QCamera::CaptureModes captureMode)
-{
- if (m_captureMode == captureMode)
- return;
-
- m_captureMode = captureMode;
- emit captureModeChanged(m_captureMode);
-}
-
-bool BbCameraSession::isCaptureModeSupported(QCamera::CaptureModes mode) const
-{
- if (m_handle == CAMERA_HANDLE_INVALID) {
- // the camera has not been loaded yet via QCamera::load(), so
- // we open it temporarily to peek for the supported capture modes
-
- camera_unit_t unit = CAMERA_UNIT_REAR;
- if (m_device == cameraIdentifierFront())
- unit = CAMERA_UNIT_FRONT;
- else if (m_device == cameraIdentifierRear())
- unit = CAMERA_UNIT_REAR;
- else if (m_device == cameraIdentifierDesktop())
- unit = CAMERA_UNIT_DESKTOP;
-
- camera_handle_t handle;
- const camera_error_t result = camera_open(unit, CAMERA_MODE_RW, &handle);
- if (result != CAMERA_EOK)
- return true;
-
- const bool supported = isCaptureModeSupported(handle, mode);
-
- camera_close(handle);
-
- return supported;
- } else {
- return isCaptureModeSupported(m_handle, mode);
- }
-}
-
-QByteArray BbCameraSession::cameraIdentifierFront()
-{
- return "bb:FrontCamera";
-}
-
-QByteArray BbCameraSession::cameraIdentifierRear()
-{
- return "bb:RearCamera";
-}
-
-QByteArray BbCameraSession::cameraIdentifierDesktop()
-{
- return "bb:DesktopCamera";
-}
-
-void BbCameraSession::setDevice(const QByteArray &device)
-{
- m_device = device;
-}
-
-QByteArray BbCameraSession::device() const
-{
- return m_device;
-}
-
-void BbCameraSession::setSurface(QVideoSink *surface)
-{
- QMutexLocker locker(&m_surfaceMutex);
-
- if (m_surface == surface)
- return;
-
- m_surface = surface;
-}
-
-bool BbCameraSession::isReadyForCapture() const
-{
- if (m_captureMode & QCamera::CaptureStillImage)
- return (m_status == QCamera::ActiveStatus);
-
- if (m_captureMode & QCamera::CaptureVideo)
- return (m_status == QCamera::ActiveStatus);
-
- return false;
-}
-
-/**
- * A helper structure that keeps context data for image capture callbacks.
- */
-struct ImageCaptureData
-{
- int requestId;
- QString fileName;
- BbCameraSession *session;
-};
-
-static void imageCaptureShutterCallback(camera_handle_t handle, void *context)
-{
- Q_UNUSED(handle);
-
- const ImageCaptureData *data = static_cast<ImageCaptureData*>(context);
-
- // We are inside a worker thread here, so emit imageExposed inside the main thread
- QMetaObject::invokeMethod(data->session, "imageExposed", Qt::QueuedConnection,
- Q_ARG(int, data->requestId));
-}
-
-static void imageCaptureImageCallback(camera_handle_t handle, camera_buffer_t *buffer, void *context)
-{
- Q_UNUSED(handle);
-
- QScopedPointer<ImageCaptureData> data(static_cast<ImageCaptureData*>(context));
-
- if (buffer->frametype != CAMERA_FRAMETYPE_JPEG) {
- // We are inside a worker thread here, so emit error signal inside the main thread
- QMetaObject::invokeMethod(data->session, "imageCaptureError", Qt::QueuedConnection,
- Q_ARG(int, data->requestId),
- Q_ARG(QImageCapture::Error, QImageCapture::FormatError),
- Q_ARG(QString, BbCameraSession::tr("Camera provides image in unsupported format")));
- return;
- }
-
- const QByteArray rawData((const char*)buffer->framebuf, buffer->framedesc.jpeg.bufsize);
-
- QImage image;
- const bool ok = image.loadFromData(rawData, "JPG");
- if (!ok) {
- const QString errorMessage = BbCameraSession::tr("Could not load JPEG data from frame");
- // We are inside a worker thread here, so emit error signal inside the main thread
- QMetaObject::invokeMethod(data->session, "imageCaptureError", Qt::QueuedConnection,
- Q_ARG(int, data->requestId),
- Q_ARG(QImageCapture::Error, QImageCapture::FormatError),
- Q_ARG(QString, errorMessage));
- return;
- }
-
-
- // We are inside a worker thread here, so invoke imageCaptured inside the main thread
- QMetaObject::invokeMethod(data->session, "imageCaptured", Qt::QueuedConnection,
- Q_ARG(int, data->requestId),
- Q_ARG(QImage, image),
- Q_ARG(QString, data->fileName));
-}
-
-int BbCameraSession::capture(const QString &fileName)
-{
- m_lastImageCaptureId++;
-
- if (!isReadyForCapture()) {
- emit imageCaptureError(m_lastImageCaptureId, QImageCapture::NotReadyError,
- QPlatformImageCapture::msgCameraNotReady());
- return m_lastImageCaptureId;
- }
-
- // prepare context object for callback
- ImageCaptureData *context = new ImageCaptureData;
- context->requestId = m_lastImageCaptureId;
- context->fileName = fileName;
- context->session = this;
-
- const camera_error_t result = camera_take_photo(m_handle,
- imageCaptureShutterCallback,
- 0,
- 0,
- imageCaptureImageCallback,
- context, false);
-
- if (result != CAMERA_EOK)
- qWarning() << "Unable to take photo:" << result;
-
- return m_lastImageCaptureId;
-}
-
-void BbCameraSession::cancelCapture()
-{
- // BB10 API doesn't provide functionality for that
-}
-
-QList<QSize> BbCameraSession::supportedResolutions(const QImageEncoderSettings&, bool *continuous) const
-{
- if (continuous)
- *continuous = false;
-
- if (m_status == QCamera::UnloadedStatus)
- return QList<QSize>();
-
- if (m_captureMode & QCamera::CaptureStillImage) {
- return supportedResolutions(QCamera::CaptureStillImage);
- } else if (m_captureMode & QCamera::CaptureVideo) {
- return supportedResolutions(QCamera::CaptureVideo);
- }
-
- return QList<QSize>();
-}
-
-QImageEncoderSettings BbCameraSession::imageSettings() const
-{
- return m_imageEncoderSettings;
-}
-
-void BbCameraSession::setImageSettings(const QImageEncoderSettings &settings)
-{
- m_imageEncoderSettings = settings;
- if (m_imageEncoderSettings.codec().isEmpty())
- m_imageEncoderSettings.setCodec(QLatin1String("jpeg"));
-}
-
-QMediaRecorder::RecorderState BbCameraSession::videoState() const
-{
- return m_videoState;
-}
-
-qint64 BbCameraSession::duration() const
-{
- return (m_videoRecordingDuration.isValid() ? m_videoRecordingDuration.elapsed() : 0);
-}
-
-void BbCameraSession::applyVideoSettings()
-{
- if (m_handle == CAMERA_HANDLE_INVALID)
- return;
-
- // apply viewfinder configuration
- const QList<QSize> videoOutputResolutions = supportedResolutions(QCamera::CaptureVideo);
-
- if (!m_videoEncoderSettings.resolution().isValid() || !videoOutputResolutions.contains(m_videoEncoderSettings.resolution()))
- m_videoEncoderSettings.setResolution(videoOutputResolutions.first());
-
- QSize viewfinderResolution;
-
- if (m_previewIsVideo) {
- // The viewfinder is responsible for encoding the video frames, so the resolutions must match.
- viewfinderResolution = m_videoEncoderSettings.resolution();
- } else {
- // The frames are encoded separately from the viewfinder, so only the aspect ratio must match.
- const QSize videoResolution = m_videoEncoderSettings.resolution();
- const qreal aspectRatio = static_cast<qreal>(videoResolution.width())/static_cast<qreal>(videoResolution.height());
-
- QList<QSize> sizes = supportedViewfinderResolutions(QCamera::CaptureVideo);
- std::reverse(sizes.begin(), sizes.end()); // use smallest possible resolution
- for (const QSize &size : qAsConst(sizes)) {
- // search for viewfinder resolution with the same aspect ratio
- if (qFuzzyCompare(aspectRatio, (static_cast<qreal>(size.width())/static_cast<qreal>(size.height())))) {
- viewfinderResolution = size;
- break;
- }
- }
- }
-
- Q_ASSERT(viewfinderResolution.isValid());
-
- const QByteArray windowId = QString().sprintf("qcamera_vf_%p", this).toLatin1();
- m_windowGrabber->setWindowId(windowId);
-
- const QByteArray windowGroupId = m_windowGrabber->windowGroupId();
-
- const int rotationAngle = (360 - m_nativeCameraOrientation);
-
- camera_error_t result = CAMERA_EOK;
- result = camera_set_videovf_property(m_handle,
- CAMERA_IMGPROP_WIN_GROUPID, windowGroupId.data(),
- CAMERA_IMGPROP_WIN_ID, windowId.data(),
- CAMERA_IMGPROP_WIDTH, viewfinderResolution.width(),
- CAMERA_IMGPROP_HEIGHT, viewfinderResolution.height(),
- CAMERA_IMGPROP_ROTATION, rotationAngle);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to apply video viewfinder settings:" << result;
- return;
- }
-
- const QSize resolution = m_videoEncoderSettings.resolution();
-
- QString videoCodec = m_videoEncoderSettings.codec();
- if (videoCodec.isEmpty())
- videoCodec = QLatin1String("h264");
-
- camera_videocodec_t cameraVideoCodec = CAMERA_VIDEOCODEC_H264;
- if (videoCodec == QLatin1String("none"))
- cameraVideoCodec = CAMERA_VIDEOCODEC_NONE;
- else if (videoCodec == QLatin1String("avc1"))
- cameraVideoCodec = CAMERA_VIDEOCODEC_AVC1;
- else if (videoCodec == QLatin1String("h264"))
- cameraVideoCodec = CAMERA_VIDEOCODEC_H264;
-
- qreal frameRate = m_videoEncoderSettings.frameRate();
- if (frameRate == 0) {
- const QList<qreal> frameRates = supportedFrameRates(QVideoEncoderSettings(), 0);
- if (!frameRates.isEmpty())
- frameRate = frameRates.last();
- }
-
- QString audioCodec = m_audioEncoderSettings.codec();
- if (audioCodec.isEmpty())
- audioCodec = QLatin1String("aac");
-
- camera_audiocodec_t cameraAudioCodec = CAMERA_AUDIOCODEC_AAC;
- if (audioCodec == QLatin1String("none"))
- cameraAudioCodec = CAMERA_AUDIOCODEC_NONE;
- else if (audioCodec == QLatin1String("aac"))
- cameraAudioCodec = CAMERA_AUDIOCODEC_AAC;
- else if (audioCodec == QLatin1String("raw"))
- cameraAudioCodec = CAMERA_AUDIOCODEC_RAW;
-
- result = camera_set_video_property(m_handle,
- CAMERA_IMGPROP_WIDTH, resolution.width(),
- CAMERA_IMGPROP_HEIGHT, resolution.height(),
- CAMERA_IMGPROP_ROTATION, rotationAngle,
- CAMERA_IMGPROP_VIDEOCODEC, cameraVideoCodec,
- CAMERA_IMGPROP_AUDIOCODEC, cameraAudioCodec);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to apply video settings:" << result;
- emit videoError(QMediaRecorder::ResourceError, tr("Unable to apply video settings"));
- }
-}
-
-QList<QSize> BbCameraSession::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const
-{
- Q_UNUSED(settings);
-
- if (continuous)
- *continuous = false;
-
- return supportedResolutions(QCamera::CaptureVideo);
-}
-
-QList<qreal> BbCameraSession::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const
-{
- Q_UNUSED(settings);
-
- if (m_handle == CAMERA_HANDLE_INVALID)
- return QList<qreal>();
-
- int supported = 0;
- double rates[20];
- bool maxmin = false;
-
- /**
- * Since in current version of the BB10 platform the video viewfinder encodes the video frames, we use
- * the values as returned by camera_get_video_vf_framerates().
- */
- const camera_error_t result = camera_get_video_vf_framerates(m_handle, 20, &supported, rates, &maxmin);
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve supported viewfinder framerates:" << result;
- return QList<qreal>();
- }
-
- QList<qreal> frameRates;
- for (int i = 0; i < supported; ++i)
- frameRates << rates[i];
-
- if (continuous)
- *continuous = maxmin;
-
- return frameRates;
-}
-
-QVideoEncoderSettings BbCameraSession::videoSettings() const
-{
- return m_videoEncoderSettings;
-}
-
-void BbCameraSession::setVideoSettings(const QVideoEncoderSettings &settings)
-{
- m_videoEncoderSettings = settings;
-}
-
-QAudioEncoderSettings BbCameraSession::audioSettings() const
-{
- return m_audioEncoderSettings;
-}
-
-void BbCameraSession::setAudioSettings(const QAudioEncoderSettings &settings)
-{
- m_audioEncoderSettings = settings;
-}
-
-void BbCameraSession::updateReadyForCapture()
-{
- emit readyForCaptureChanged(isReadyForCapture());
-}
-
-void BbCameraSession::imageCaptured(int requestId, const QImage &rawImage, const QString &fileName)
-{
- QTransform transform;
-
- // subtract out the native rotation
- transform.rotate(m_nativeCameraOrientation);
-
- // subtract out the current device orientation
- if (m_device == cameraIdentifierRear())
- transform.rotate(360 - m_orientationHandler->orientation());
- else
- transform.rotate(m_orientationHandler->orientation());
-
- const QImage image = rawImage.transformed(transform);
-
- // Generate snap preview as downscaled image
- {
- QSize previewSize = image.size();
- int downScaleSteps = 0;
- while (previewSize.width() > 800 && downScaleSteps < 8) {
- previewSize.rwidth() /= 2;
- previewSize.rheight() /= 2;
- downScaleSteps++;
- }
-
- const QImage snapPreview = image.scaled(previewSize);
-
- emit imageCaptured(requestId, snapPreview);
- }
-
- if (/* capture to buffer */ fileName.isEmpty()) {
- QVideoFrame frame(image);
- emit imageAvailable(requestId, frame);
- } else {
- const QString actualFileName = QMediaStorageLocation::generateFileName(fileName, QStandardPaths::PicturesLocation, QLatin1String("jpg"));
- QFile file(actualFileName);
- if (file.open(QFile::WriteOnly)) {
- if (image.save(&file, "jpg")) {
- emit imageSaved(requestId, actualFileName);
- } else {
- emit imageCaptureError(requestId, QImageCapture::OutOfSpaceError, file.errorString());
- }
- } else {
- const QString errorMessage = tr("Could not open destination file:\n%1").arg(actualFileName);
- emit imageCaptureError(requestId, QImageCapture::ResourceError, errorMessage);
- }
- }
-}
-
-void BbCameraSession::handleVideoRecordingPaused()
-{
- //TODO: implement once BB10 API supports pausing a video
-}
-
-void BbCameraSession::handleVideoRecordingResumed()
-{
- if (m_videoRecordingDuration.isValid())
- m_videoRecordingDuration.restart();
-}
-
-void BbCameraSession::deviceOrientationChanged(int angle)
-{
- if (m_handle != CAMERA_HANDLE_INVALID)
- camera_set_device_orientation(m_handle, angle);
-}
-
-void BbCameraSession::handleCameraPowerUp()
-{
- stopViewFinder();
- startViewFinder();
-}
-
-void BbCameraSession::viewfinderFrameGrabbed(const QImage &image)
-{
- QTransform transform;
-
- // subtract out the native rotation
- transform.rotate(m_nativeCameraOrientation);
-
- // subtract out the current device orientation
- if (m_device == cameraIdentifierRear())
- transform.rotate(360 - m_orientationHandler->viewfinderOrientation());
- else
- transform.rotate(m_orientationHandler->viewfinderOrientation());
-
- QImage frame = image.copy().transformed(transform);
-
- QMutexLocker locker(&m_surfaceMutex);
- if (m_surface) {
- if (frame.size() != m_surface->surfaceFormat().frameSize()) {
- m_surface->stop();
- m_surface->start(QVideoFrameFormat(frame.size(), QVideoFrameFormat::Format_ARGB32));
- }
-
- QVideoFrame videoFrame(frame);
-
- m_surface->present(videoFrame);
- }
-}
-
-bool BbCameraSession::openCamera()
-{
- if (m_handle != CAMERA_HANDLE_INVALID) // camera is already open
- return true;
-
- m_status = QCamera::LoadingStatus;
- emit statusChanged(m_status);
-
- camera_unit_t unit = CAMERA_UNIT_REAR;
- if (m_device == cameraIdentifierFront())
- unit = CAMERA_UNIT_FRONT;
- else if (m_device == cameraIdentifierRear())
- unit = CAMERA_UNIT_REAR;
- else if (m_device == cameraIdentifierDesktop())
- unit = CAMERA_UNIT_DESKTOP;
-
- camera_error_t result = camera_open(unit, CAMERA_MODE_RW, &m_handle);
- if (result != CAMERA_EOK) {
- m_handle = CAMERA_HANDLE_INVALID;
- m_status = QCamera::UnloadedStatus;
- emit statusChanged(m_status);
-
- qWarning() << "Unable to open camera:" << result;
- emit error(QCamera::CameraError, tr("Unable to open camera"));
- return false;
- }
-
- result = camera_get_native_orientation(m_handle, &m_nativeCameraOrientation);
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve native camera orientation:" << result;
- emit error(QCamera::CameraError, tr("Unable to retrieve native camera orientation"));
- return false;
- }
-
- m_previewIsVideo = camera_has_feature(m_handle, CAMERA_FEATURE_PREVIEWISVIDEO);
-
- m_status = QCamera::LoadedStatus;
- emit statusChanged(m_status);
-
- emit cameraOpened();
-
- return true;
-}
-
-void BbCameraSession::closeCamera()
-{
- if (m_handle == CAMERA_HANDLE_INVALID) // camera is closed already
- return;
-
- m_status = QCamera::UnloadingStatus;
- emit statusChanged(m_status);
-
- const camera_error_t result = camera_close(m_handle);
- if (result != CAMERA_EOK) {
- m_status = QCamera::LoadedStatus;
- emit statusChanged(m_status);
-
- qWarning() << "Unable to close camera:" << result;
- emit error(QCamera::CameraError, tr("Unable to close camera"));
- return;
- }
-
- m_handle = CAMERA_HANDLE_INVALID;
-
- m_status = QCamera::UnloadedStatus;
- emit statusChanged(m_status);
-}
-
-static void viewFinderStatusCallback(camera_handle_t handle, camera_devstatus_t status, uint16_t value, void *context)
-{
- Q_UNUSED(handle);
-
- if (status == CAMERA_STATUS_FOCUS_CHANGE) {
- BbCameraSession *session = static_cast<BbCameraSession*>(context);
- QMetaObject::invokeMethod(session, "focusStatusChanged", Qt::QueuedConnection, Q_ARG(int, value));
- return;
- } else if (status == CAMERA_STATUS_POWERUP) {
- BbCameraSession *session = static_cast<BbCameraSession*>(context);
- QMetaObject::invokeMethod(session, "handleCameraPowerUp", Qt::QueuedConnection);
- }
-}
-
-bool BbCameraSession::startViewFinder()
-{
- m_status = QCamera::StartingStatus;
- emit statusChanged(m_status);
-
- QSize viewfinderResolution;
- camera_error_t result = CAMERA_EOK;
- if (m_captureMode & QCamera::CaptureStillImage) {
- result = camera_start_photo_viewfinder(m_handle, 0, viewFinderStatusCallback, this);
- viewfinderResolution = currentViewfinderResolution(QCamera::CaptureStillImage);
- } else if (m_captureMode & QCamera::CaptureVideo) {
- result = camera_start_video_viewfinder(m_handle, 0, viewFinderStatusCallback, this);
- viewfinderResolution = currentViewfinderResolution(QCamera::CaptureVideo);
- }
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to start viewfinder:" << result;
- return false;
- }
-
- const int angle = m_orientationHandler->viewfinderOrientation();
-
- const QSize rotatedSize = ((angle == 0 || angle == 180) ? viewfinderResolution
- : viewfinderResolution.transposed());
-
- m_surfaceMutex.lock();
- if (m_surface) {
- const bool ok = m_surface->start(QVideoFrameFormat(rotatedSize, QVideoFrameFormat::Format_ARGB32));
- if (!ok)
- qWarning() << "Unable to start camera viewfinder surface";
- }
- m_surfaceMutex.unlock();
-
- m_status = QCamera::ActiveStatus;
- emit statusChanged(m_status);
-
- return true;
-}
-
-void BbCameraSession::stopViewFinder()
-{
- m_windowGrabber->stop();
-
- m_status = QCamera::StoppingStatus;
- emit statusChanged(m_status);
-
- m_surfaceMutex.lock();
- if (m_surface) {
- m_surface->stop();
- }
- m_surfaceMutex.unlock();
-
- camera_error_t result = CAMERA_EOK;
- if (m_captureMode & QCamera::CaptureStillImage)
- result = camera_stop_photo_viewfinder(m_handle);
- else if (m_captureMode & QCamera::CaptureVideo)
- result = camera_stop_video_viewfinder(m_handle);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to stop viewfinder:" << result;
- return;
- }
-
- m_status = QCamera::LoadedStatus;
- emit statusChanged(m_status);
-}
-
-void BbCameraSession::applyConfiguration()
-{
- if (m_captureMode & QCamera::CaptureStillImage) {
- const QList<QSize> photoOutputResolutions = supportedResolutions(QCamera::CaptureStillImage);
-
- if (!m_imageEncoderSettings.resolution().isValid() || !photoOutputResolutions.contains(m_imageEncoderSettings.resolution()))
- m_imageEncoderSettings.setResolution(photoOutputResolutions.first());
-
- const QSize photoResolution = m_imageEncoderSettings.resolution();
- const qreal aspectRatio = static_cast<qreal>(photoResolution.width())/static_cast<qreal>(photoResolution.height());
-
- // apply viewfinder configuration
- QSize viewfinderResolution;
- QList<QSize> sizes = supportedViewfinderResolutions(QCamera::CaptureStillImage);
- std::reverse(sizes.begin(), sizes.end()); // use smallest possible resolution
- for (const QSize &size : qAsConst(sizes)) {
- // search for viewfinder resolution with the same aspect ratio
- if (qFuzzyCompare(aspectRatio, (static_cast<qreal>(size.width())/static_cast<qreal>(size.height())))) {
- viewfinderResolution = size;
- break;
- }
- }
-
- Q_ASSERT(viewfinderResolution.isValid());
-
- const QByteArray windowId = QString().sprintf("qcamera_vf_%p", this).toLatin1();
- m_windowGrabber->setWindowId(windowId);
-
- const QByteArray windowGroupId = m_windowGrabber->windowGroupId();
-
- camera_error_t result = camera_set_photovf_property(m_handle,
- CAMERA_IMGPROP_WIN_GROUPID, windowGroupId.data(),
- CAMERA_IMGPROP_WIN_ID, windowId.data(),
- CAMERA_IMGPROP_WIDTH, viewfinderResolution.width(),
- CAMERA_IMGPROP_HEIGHT, viewfinderResolution.height(),
- CAMERA_IMGPROP_FORMAT, CAMERA_FRAMETYPE_NV12,
- CAMERA_IMGPROP_ROTATION, 360 - m_nativeCameraOrientation);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to apply photo viewfinder settings:" << result;
- return;
- }
-
-
- int jpegQuality = 100;
- switch (m_imageEncoderSettings.quality()) {
- case QMediaRecorder::VeryLowQuality:
- jpegQuality = 20;
- break;
- case QMediaRecorder::LowQuality:
- jpegQuality = 40;
- break;
- case QMediaRecorder::NormalQuality:
- jpegQuality = 60;
- break;
- case QMediaRecorder::HighQuality:
- jpegQuality = 80;
- break;
- case QMediaRecorder::VeryHighQuality:
- jpegQuality = 100;
- break;
- }
-
- // apply photo configuration
- result = camera_set_photo_property(m_handle,
- CAMERA_IMGPROP_WIDTH, photoResolution.width(),
- CAMERA_IMGPROP_HEIGHT, photoResolution.height(),
- CAMERA_IMGPROP_JPEGQFACTOR, jpegQuality,
- CAMERA_IMGPROP_ROTATION, 360 - m_nativeCameraOrientation);
-
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to apply photo settings:" << result;
- return;
- }
-
- } else if (m_captureMode & QCamera::CaptureVideo) {
- applyVideoSettings();
- }
-
- startViewFinder();
-}
-
-static void videoRecordingStatusCallback(camera_handle_t handle, camera_devstatus_t status, uint16_t value, void *context)
-{
- Q_UNUSED(handle);
- Q_UNUSED(value);
-
- if (status == CAMERA_STATUS_VIDEO_PAUSE) {
- BbCameraSession *session = static_cast<BbCameraSession*>(context);
- QMetaObject::invokeMethod(session, "handleVideoRecordingPaused", Qt::QueuedConnection);
- } else if (status == CAMERA_STATUS_VIDEO_RESUME) {
- BbCameraSession *session = static_cast<BbCameraSession*>(context);
- QMetaObject::invokeMethod(session, "handleVideoRecordingResumed", Qt::QueuedConnection);
- }
-}
-
-void BbCameraSession::startVideoRecording(const QUrl &outputLocation)
-{
- if (m_videoState == QMediaRecorder::RecordingState)
- return;
-
- m_videoRecordingDuration.invalidate();
-
- auto videoOutputLocation = QMediaStorageLocation::generateFileName(outputLocation.toLocalFile(), QStandardPaths::MoviesLocation, QLatin1String("mp4"));
-
- emit actualLocationChanged(videoOutputLocation);
-
- const camera_error_t result = camera_start_video(m_handle, QFile::encodeName(videoOutputLocation), 0, videoRecordingStatusCallback, this);
- if (result != CAMERA_EOK) {
- emit videoError(QMediaRecorder::ResourceError,
- QMediaRecorderPrivate::msgFailedStartRecording());
- } else {
- m_videoState = QMediaRecorder::RecordingState;
- }
- emit videoStateChanged(m_videoState);
-}
-
-void BbCameraSession::stopVideoRecording()
-{
- if (m_videoState == QMediaRecorder::StoppedState)
- return;
-
- const camera_error_t result = camera_stop_video(m_handle);
- if (result != CAMERA_EOK) {
- emit videoError(QMediaRecorder::ResourceError, tr("Unable to stop video recording"));
- }
-
- m_videoRecordingDuration.invalidate();
- m_videoState = QMediaRecorder::StoppedState;
- emit videoStateChanged(m_videoState);
-}
-
-bool BbCameraSession::isCaptureModeSupported(camera_handle_t handle, QCamera::CaptureModes mode) const
-{
- if (mode & QCamera::CaptureStillImage)
- return camera_has_feature(handle, CAMERA_FEATURE_PHOTO);
-
- if (mode & QCamera::CaptureVideo)
- return camera_has_feature(handle, CAMERA_FEATURE_VIDEO);
-
- return false;
-}
-
-QList<QSize> BbCameraSession::supportedResolutions(QCamera::CaptureMode mode) const
-{
- Q_ASSERT(m_handle != CAMERA_HANDLE_INVALID);
-
- QList<QSize> list;
-
- camera_error_t result = CAMERA_EOK;
- camera_res_t resolutions[20];
- unsigned int supported = 0;
-
- if (mode == QCamera::CaptureStillImage)
- result = camera_get_photo_output_resolutions(m_handle, CAMERA_FRAMETYPE_JPEG, 20, &supported, resolutions);
- else if (mode == QCamera::CaptureVideo)
- result = camera_get_video_output_resolutions(m_handle, 20, &supported, resolutions);
-
- if (result != CAMERA_EOK)
- return list;
-
- for (unsigned int i = 0; i < supported; ++i)
- list << QSize(resolutions[i].width, resolutions[i].height);
-
- return list;
-}
-
-QList<QSize> BbCameraSession::supportedViewfinderResolutions(QCamera::CaptureMode mode) const
-{
- Q_ASSERT(m_handle != CAMERA_HANDLE_INVALID);
-
- QList<QSize> list;
-
- camera_error_t result = CAMERA_EOK;
- camera_res_t resolutions[20];
- unsigned int supported = 0;
-
- if (mode == QCamera::CaptureStillImage)
- result = camera_get_photo_vf_resolutions(m_handle, 20, &supported, resolutions);
- else if (mode == QCamera::CaptureVideo)
- result = camera_get_video_vf_resolutions(m_handle, 20, &supported, resolutions);
-
- if (result != CAMERA_EOK)
- return list;
-
- for (unsigned int i = 0; i < supported; ++i)
- list << QSize(resolutions[i].width, resolutions[i].height);
-
- return list;
-}
-
-QSize BbCameraSession::currentViewfinderResolution(QCamera::CaptureMode mode) const
-{
- Q_ASSERT(m_handle != CAMERA_HANDLE_INVALID);
-
- camera_error_t result = CAMERA_EOK;
- int width = 0;
- int height = 0;
-
- if (mode == QCamera::CaptureStillImage)
- result = camera_get_photovf_property(m_handle, CAMERA_IMGPROP_WIDTH, &width,
- CAMERA_IMGPROP_HEIGHT, &height);
- else if (mode == QCamera::CaptureVideo)
- result = camera_get_videovf_property(m_handle, CAMERA_IMGPROP_WIDTH, &width,
- CAMERA_IMGPROP_HEIGHT, &height);
-
- if (result != CAMERA_EOK)
- return QSize();
-
- return QSize(width, height);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcamerasession_p.h b/src/multimedia/platform/qnx/camera/bbcamerasession_p.h
deleted file mode 100644
index 4ea7110e7..000000000
--- a/src/multimedia/platform/qnx/camera/bbcamerasession_p.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERASESSION_H
-#define BBCAMERASESSION_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 <QCamera>
-#include <QImageCapture>
-#include <QElapsedTimer>
-#include <QMediaRecorder>
-#include <QMutex>
-#include <QObject>
-#include <QPointer>
-#include <qvideosink.h>
-
-#include <camera/camera_api.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraOrientationHandler;
-class WindowGrabber;
-
-class BbCameraSession : public QObject
-{
- Q_OBJECT
-public:
- explicit BbCameraSession(QObject *parent = 0);
- ~BbCameraSession();
-
- camera_handle_t handle() const;
-
- // camera control
- QCamera::State state() const;
- void setState(QCamera::State state);
- QCamera::Status status() const;
- QCamera::CaptureModes captureMode() const;
- void setCaptureMode(QCamera::CaptureModes);
- bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
-
- // video device selector control
- static QByteArray cameraIdentifierFront();
- static QByteArray cameraIdentifierRear();
- static QByteArray cameraIdentifierDesktop();
-
- void setDevice(const QByteArray &device);
- QByteArray device() const;
-
- // video renderer control
- void setSurface(QVideoSink *surface);
-
- // image capture control
- bool isReadyForCapture() const;
- int capture(const QString &fileName);
- void cancelCapture();
-
- // image encoder control
- QList<QSize> supportedResolutions(const QImageEncoderSettings &settings, bool *continuous) const;
- QImageEncoderSettings imageSettings() const;
- void setImageSettings(const QImageEncoderSettings &settings);
-
- // media recorder control
- QMediaRecorder::RecorderState videoState() const;
- qint64 duration() const;
- void applyVideoSettings();
-
- bool startVideoRecording(const QUrl &outputLocation);
- void stopVideoRecording();
-
- // video encoder settings control
- QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const;
- QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const;
- QVideoEncoderSettings videoSettings() const;
- void setVideoSettings(const QVideoEncoderSettings &settings);
-
- // audio encoder settings control
- QAudioEncoderSettings audioSettings() const;
- void setAudioSettings(const QAudioEncoderSettings &settings);
-
-Q_SIGNALS:
- // camera control
- void stateChanged(QCamera::State);
- void error(int error, const QString &errorString);
- void captureModeChanged(QCamera::CaptureModes);
-
- // image capture control
- void readyForCaptureChanged(bool);
- void imageExposed(int id);
- void imageCaptured(int id, const QImage &preview);
- void imageMetadataAvailable(int id, const QString &key, const QVariant &value);
- void imageAvailable(int id, const QVideoFrame &buffer);
- void imageSaved(int id, const QString &fileName);
- void imageCaptureError(int id, int error, const QString &errorString);
-
- // media recorder control
- void videoStateChanged(QMediaRecorder::RecorderState state);
- void durationChanged(qint64 duration);
- void actualLocationChanged(const QUrl &location);
- void videoError(int error, const QString &errorString);
-
- void cameraOpened();
- void focusStatusChanged(int status);
-
-private slots:
- void updateReadyForCapture();
- void imageCaptured(int, const QImage&, const QString&);
- void handleVideoRecordingPaused();
- void handleVideoRecordingResumed();
- void deviceOrientationChanged(int);
- void handleCameraPowerUp();
- void viewfinderFrameGrabbed(const QImage &image);
- void applyConfiguration();
-
-private:
- bool openCamera();
- void closeCamera();
- bool startViewFinder();
- void stopViewFinder();
-
- bool isCaptureModeSupported(camera_handle_t handle, QCamera::CaptureModes mode) const;
- QList<QSize> supportedResolutions(QCamera::CaptureMode mode) const;
- QList<QSize> supportedViewfinderResolutions(QCamera::CaptureMode mode) const;
- QSize currentViewfinderResolution(QCamera::CaptureMode mode) const;
-
- quint32 m_nativeCameraOrientation;
- BbCameraOrientationHandler* m_orientationHandler;
-
- QCamera::Status m_status;
- QCamera::State m_state;
- QCamera::CaptureModes m_captureMode;
-
- QByteArray m_device;
- bool m_previewIsVideo;
-
- QPointer<QVideoSink> m_surface;
- QMutex m_surfaceMutex;
-
- int m_lastImageCaptureId;
-
- QImageEncoderSettings m_imageEncoderSettings;
-
- QMediaRecorder::RecorderState m_videoState;
- QElapsedTimer m_videoRecordingDuration;
-
- QVideoEncoderSettings m_videoEncoderSettings;
- QAudioEncoderSettings m_audioEncoderSettings;
-
- camera_handle_t m_handle;
-
- WindowGrabber* m_windowGrabber;
-};
-
-QDebug operator<<(QDebug debug, camera_error_t error);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol.cpp b/src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol.cpp
deleted file mode 100644
index d16d7a307..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "bbcameravideoencodersettingscontrol_p.h"
-
-#include "bbcamerasession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-BbCameraVideoEncoderSettingsControl::BbCameraVideoEncoderSettingsControl(BbCameraSession *session, QObject *parent)
- : QVideoEncoderSettingsControl(parent)
- , m_session(session)
-{
-}
-
-QList<QSize> BbCameraVideoEncoderSettingsControl::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const
-{
- return m_session->supportedResolutions(settings, continuous);
-}
-
-QList<qreal> BbCameraVideoEncoderSettingsControl::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const
-{
- return m_session->supportedFrameRates(settings, continuous);
-}
-
-QStringList BbCameraVideoEncoderSettingsControl::supportedVideoCodecs() const
-{
- return QStringList() << QLatin1String("none") << QLatin1String("avc1") << QLatin1String("h264");
-}
-
-QString BbCameraVideoEncoderSettingsControl::videoCodecDescription(const QString &codecName) const
-{
- if (codecName == QLatin1String("none"))
- return tr("No compression");
- else if (codecName == QLatin1String("avc1"))
- return tr("AVC1 compression");
- else if (codecName == QLatin1String("h264"))
- return tr("H264 compression");
-
- return QString();
-}
-
-QVideoEncoderSettings BbCameraVideoEncoderSettingsControl::videoSettings() const
-{
- return m_session->videoSettings();
-}
-
-void BbCameraVideoEncoderSettingsControl::setVideoSettings(const QVideoEncoderSettings &settings)
-{
- m_session->setVideoSettings(settings);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol_p.h b/src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol_p.h
deleted file mode 100644
index 893b26d5d..000000000
--- a/src/multimedia/platform/qnx/camera/bbcameravideoencodersettingscontrol_p.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef BBCAMERAVIDEOENCODERSETTINGSCONTROL_H
-#define BBCAMERAVIDEOENCODERSETTINGSCONTROL_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 <qvideoencodersettingscontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-class BbCameraSession;
-
-class BbCameraVideoEncoderSettingsControl : public QVideoEncoderSettingsControl
-{
- Q_OBJECT
-public:
- explicit BbCameraVideoEncoderSettingsControl(BbCameraSession *session, QObject *parent = 0);
-
- QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous = 0) const override;
- QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous = 0) const override;
- QStringList supportedVideoCodecs() const override;
- QString videoCodecDescription(const QString &codecName) const override;
- QVideoEncoderSettings videoSettings() const override;
- void setVideoSettings(const QVideoEncoderSettings &settings) override;
-
-private:
- BbCameraSession *m_session;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/common/windowgrabber.cpp b/src/multimedia/platform/qnx/common/windowgrabber.cpp
deleted file mode 100644
index e4c8c926d..000000000
--- a/src/multimedia/platform/qnx/common/windowgrabber.cpp
+++ /dev/null
@@ -1,419 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "windowgrabber_p.h"
-
-#include <QAbstractEventDispatcher>
-#include <QDebug>
-#include <QGuiApplication>
-#include <QImage>
-#include <QThread>
-#include <qpa/qplatformnativeinterface.h>
-
-#include <QOpenGLContext>
-#include <QOpenGLFunctions>
-
-#include <errno.h>
-
-QT_BEGIN_NAMESPACE
-
-static PFNEGLCREATEIMAGEKHRPROC s_eglCreateImageKHR;
-static PFNEGLDESTROYIMAGEKHRPROC s_eglDestroyImageKHR;
-
-WindowGrabber::WindowGrabber(QObject *parent)
- : QObject(parent),
- m_windowParent(nullptr),
- m_screenContext(0),
- m_active(false),
- m_currentFrame(0),
- m_eglImageSupported(false),
- m_eglImageCheck(false)
-{
- // grab the window frame with 60 frames per second
- m_timer.setInterval(1000/60);
-
- connect(&m_timer, SIGNAL(timeout()), SLOT(triggerUpdate()));
-
- QCoreApplication::eventDispatcher()->installNativeEventFilter(this);
-
- for ( int i = 0; i < 2; ++i )
- m_images[i] = 0;
-
- // Use of EGL images can be disabled by setting QQNX_MM_DISABLE_EGLIMAGE_SUPPORT to something
- // non-zero. This is probably useful only to test that this path still works since it results
- // in a high CPU load.
- if (!s_eglCreateImageKHR && qgetenv("QQNX_MM_DISABLE_EGLIMAGE_SUPPORT").toInt() == 0) {
- s_eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
- s_eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
- }
-
- QPlatformNativeInterface *const nativeInterface = QGuiApplication::platformNativeInterface();
- if (nativeInterface) {
- m_screenContext = static_cast<screen_context_t>(
- nativeInterface->nativeResourceForIntegration("screenContext"));
- }
-
- // Create a parent window for the window whose content will be grabbed. Since the
- // window is only a buffer conduit, the characteristics of the parent window are
- // irrelevant. The contents of the window can be grabbed so long as the window
- // joins the parent window's group and the parent window is in this process.
- // Using the window that displays this content isn't possible because there's no
- // way to reliably retrieve it from this code or any calling code.
- screen_create_window(&m_windowParent, m_screenContext);
- screen_create_window_group(m_windowParent, nullptr);
-}
-
-WindowGrabber::~WindowGrabber()
-{
- screen_destroy_window(m_windowParent);
- QCoreApplication::eventDispatcher()->removeNativeEventFilter(this);
- cleanup();
-}
-
-void WindowGrabber::setFrameRate(int frameRate)
-{
- m_timer.setInterval(1000/frameRate);
-}
-
-
-void WindowGrabber::setWindowId(const QByteArray &windowId)
-{
- m_windowId = windowId;
-}
-
-void WindowGrabber::start()
-{
- if (m_active)
- return;
-
- if (!m_screenContext)
- screen_get_window_property_pv(m_window, SCREEN_PROPERTY_CONTEXT, reinterpret_cast<void**>(&m_screenContext));
-
- m_timer.start();
-
- m_active = true;
-}
-
-void WindowGrabber::stop()
-{
- if (!m_active)
- return;
-
- cleanup();
-
- m_timer.stop();
-
- m_active = false;
-}
-
-void WindowGrabber::pause()
-{
- m_timer.stop();
-}
-
-void WindowGrabber::resume()
-{
- if (!m_active)
- return;
-
- m_timer.start();
-}
-
-bool WindowGrabber::handleScreenEvent(screen_event_t screen_event)
-{
-
- int eventType;
- if (screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &eventType) != 0) {
- qWarning() << "WindowGrabber: Failed to query screen event type";
- return false;
- }
-
- if (eventType != SCREEN_EVENT_CREATE)
- return false;
-
- screen_window_t window = 0;
- if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0) {
- qWarning() << "WindowGrabber: Failed to query window property";
- return false;
- }
-
- const int maxIdStrLength = 128;
- char idString[maxIdStrLength];
- if (screen_get_window_property_cv(window, SCREEN_PROPERTY_ID_STRING, maxIdStrLength, idString) != 0) {
- qWarning() << "WindowGrabber: Failed to query window ID string";
- return false;
- }
-
- // Grab windows that have a non-empty ID string and a matching window id to grab
- if (idString[0] != '\0' && m_windowId == idString) {
- m_window = window;
- start();
- }
-
- return false;
-}
-
-bool WindowGrabber::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *)
-{
- if (eventType == "screen_event_t") {
- const screen_event_t event = static_cast<screen_event_t>(message);
- return handleScreenEvent(event);
- }
-
- return false;
-}
-
-QByteArray WindowGrabber::windowGroupId() const
-{
- char groupName[256];
- memset(groupName, 0, sizeof(groupName));
- screen_get_window_property_cv(m_windowParent,
- SCREEN_PROPERTY_GROUP,
- sizeof(groupName) - 1,
- groupName);
- return QByteArray(groupName);
-}
-
-bool WindowGrabber::eglImageSupported()
-{
- return m_eglImageSupported;
-}
-
-void WindowGrabber::checkForEglImageExtension()
-{
- QOpenGLContext *m_context = QOpenGLContext::currentContext();
- if (!m_context) //Should not happen, because we are called from the render thread
- return;
-
- QByteArray eglExtensions = QByteArray(eglQueryString(eglGetDisplay(EGL_DEFAULT_DISPLAY),
- EGL_EXTENSIONS));
- m_eglImageSupported = m_context->hasExtension(QByteArrayLiteral("GL_OES_EGL_image"))
- && eglExtensions.contains(QByteArrayLiteral("EGL_KHR_image"))
- && s_eglCreateImageKHR && s_eglDestroyImageKHR;
-
- if (strstr(reinterpret_cast<const char*>(glGetString(GL_VENDOR)), "VMware"))
- m_eglImageSupported = false;
-
- m_eglImageCheck = true;
-}
-
-void WindowGrabber::triggerUpdate()
-{
- if (!m_eglImageCheck) // We did not check for egl images yet
- return;
-
- int size[2] = { 0, 0 };
-
- int result = screen_get_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, size);
- if (result != 0) {
- cleanup();
- qWarning() << "WindowGrabber: cannot get window size:" << strerror(errno);
- return;
- }
-
- if (m_size.width() != size[0] || m_size.height() != size[1])
- m_size = QSize(size[0], size[1]);
-
- emit updateScene(m_size);
-}
-
-bool WindowGrabber::selectBuffer()
-{
- // If we're using egl images we need to double buffer since the gpu may still be using the last
- // video frame. If we're not, it doesn't matter since the data is immediately copied.
- if (eglImageSupported())
- m_currentFrame = (m_currentFrame + 1) % 2;
-
- if (!m_images[m_currentFrame]) {
- m_images[m_currentFrame] = new WindowGrabberImage();
- if (!m_images[m_currentFrame]->initialize(m_screenContext)) {
- delete m_images[m_currentFrame];
- m_images[m_currentFrame] = 0;
- return false;
- }
- }
- return true;
-}
-
-int WindowGrabber::getNextTextureId()
-{
- if (!selectBuffer())
- return 0;
- return m_images[m_currentFrame]->getTexture(m_window, m_size);
-}
-
-QImage WindowGrabber::getNextImage()
-{
- if (!selectBuffer())
- return QImage();
-
- return m_images[m_currentFrame]->getImage(m_window, m_size);
-}
-
-void WindowGrabber::cleanup()
-{
- for ( int i = 0; i < 2; ++i ) {
- if (m_images[i]) {
- m_images[i]->destroy();
- m_images[i] = 0;
- }
- }
-}
-
-
-WindowGrabberImage::WindowGrabberImage()
- : m_pixmap(0), m_pixmapBuffer(0), m_eglImage(0), m_glTexture(0), m_bufferAddress(0), m_bufferStride(0)
-{
-}
-
-WindowGrabberImage::~WindowGrabberImage()
-{
- if (m_glTexture)
- glDeleteTextures(1, &m_glTexture);
- if (m_eglImage)
- s_eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_eglImage);
- if (m_pixmap)
- screen_destroy_pixmap(m_pixmap);
-}
-
-bool
-WindowGrabberImage::initialize(screen_context_t screenContext)
-{
- if (screen_create_pixmap(&m_pixmap, screenContext) != 0) {
- qWarning() << "WindowGrabber: cannot create pixmap:" << strerror(errno);
- return false;
- }
- const int usage = SCREEN_USAGE_WRITE | SCREEN_USAGE_READ | SCREEN_USAGE_NATIVE;
- screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_USAGE, &usage);
-
- const int format = SCREEN_FORMAT_RGBX8888;
- screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_FORMAT, &format);
-
- return true;
-}
-
-void
-WindowGrabberImage::destroy()
-{
- // We want to delete in the thread we were created in since we need the thread that
- // has called eglMakeCurrent on the right EGL context. This doesn't actually guarantee
- // this but that would be hard to achieve and in practice it works.
- if (QThread::currentThread() == thread())
- delete this;
- else
- deleteLater();
-}
-
-bool
-WindowGrabberImage::resize(const QSize &newSize)
-{
- if (m_pixmapBuffer) {
- screen_destroy_pixmap_buffer(m_pixmap);
- m_pixmapBuffer = 0;
- m_bufferAddress = 0;
- m_bufferStride = 0;
- }
-
- int size[2] = { newSize.width(), newSize.height() };
-
- screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_BUFFER_SIZE, size);
-
- if (screen_create_pixmap_buffer(m_pixmap) == 0) {
- screen_get_pixmap_property_pv(m_pixmap, SCREEN_PROPERTY_RENDER_BUFFERS,
- reinterpret_cast<void**>(&m_pixmapBuffer));
- screen_get_buffer_property_pv(m_pixmapBuffer, SCREEN_PROPERTY_POINTER,
- reinterpret_cast<void**>(&m_bufferAddress));
- screen_get_buffer_property_iv(m_pixmapBuffer, SCREEN_PROPERTY_STRIDE, &m_bufferStride);
- m_size = newSize;
-
- return true;
- } else {
- m_size = QSize();
- return false;
- }
-}
-
-bool
-WindowGrabberImage::grab(screen_window_t window)
-{
- const int rect[] = { 0, 0, m_size.width(), m_size.height() };
- return screen_read_window(window, m_pixmapBuffer, 1, rect, 0) == 0;
-}
-
-QImage
-WindowGrabberImage::getImage(screen_window_t window, const QSize &size)
-{
- if (size != m_size) {
- if (!resize(size))
- return QImage();
- }
- if (!m_bufferAddress || !grab(window))
- return QImage();
-
- return QImage(m_bufferAddress, m_size.width(), m_size.height(), m_bufferStride, QImage::Format_ARGB32);
-}
-
-GLuint
-WindowGrabberImage::getTexture(screen_window_t window, const QSize &size)
-{
- if (size != m_size) {
- if (!m_glTexture)
- glGenTextures(1, &m_glTexture);
- glBindTexture(GL_TEXTURE_2D, m_glTexture);
- if (m_eglImage) {
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, 0);
- s_eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_eglImage);
- m_eglImage = 0;
- }
- if (!resize(size))
- return 0;
- m_eglImage = s_eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
- EGL_NATIVE_PIXMAP_KHR, m_pixmap, 0);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
- }
-
- if (!m_pixmap || !grab(window))
- return 0;
-
- return m_glTexture;
-}
-
-
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/common/windowgrabber_p.h b/src/multimedia/platform/qnx/common/windowgrabber_p.h
deleted file mode 100644
index 79a234b2d..000000000
--- a/src/multimedia/platform/qnx/common/windowgrabber_p.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef WINDOWGRABBER_H
-#define WINDOWGRABBER_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.
-//
-
-#define EGL_EGLEXT_PROTOTYPES
-#define GL_GLEXT_PROTOTYPES
-#include <EGL/egl.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <EGL/eglext.h>
-#include <QAbstractNativeEventFilter>
-#include <QObject>
-#include <QSize>
-#include <QTimer>
-
-#include <screen/screen.h>
-
-QT_BEGIN_NAMESPACE
-
-class WindowGrabberImage : public QObject
-{
- Q_OBJECT
-
-public:
- WindowGrabberImage();
- ~WindowGrabberImage();
-
- bool initialize(screen_context_t screenContext);
-
- void destroy();
-
- QImage getImage(screen_window_t window, const QSize &size);
- GLuint getTexture(screen_window_t window, const QSize &size);
-
-private:
- bool grab(screen_window_t window);
- bool resize(const QSize &size);
-
- QSize m_size;
- screen_pixmap_t m_pixmap;
- screen_buffer_t m_pixmapBuffer;
- EGLImageKHR m_eglImage;
- GLuint m_glTexture;
- unsigned char *m_bufferAddress;
- int m_bufferStride;
-};
-
-class WindowGrabber : public QObject, public QAbstractNativeEventFilter
-{
- Q_OBJECT
-
-public:
- explicit WindowGrabber(QObject *parent = 0);
- ~WindowGrabber();
-
- void setFrameRate(int frameRate);
-
- void setWindowId(const QByteArray &windowId);
-
- void start();
- void stop();
-
- void pause();
- void resume();
-
- bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override;
-
- bool handleScreenEvent(screen_event_t event);
-
- QByteArray windowGroupId() const;
-
- bool eglImageSupported();
- void checkForEglImageExtension();
-
- int getNextTextureId();
- QImage getNextImage();
-
-signals:
- void updateScene(const QSize &size);
-
-private slots:
- void triggerUpdate();
-
-private:
- bool selectBuffer();
- void cleanup();
-
- QTimer m_timer;
-
- QByteArray m_windowId;
-
- screen_window_t m_windowParent;
- screen_window_t m_window;
- screen_context_t m_screenContext;
-
- WindowGrabberImage *m_images[2];
- QSize m_size;
-
- bool m_active;
- int m_currentFrame;
- bool m_eglImageSupported;
- bool m_eglImageCheck; // We must not send a grabed frame before this is true
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp
deleted file mode 100644
index 4eff994e4..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp
+++ /dev/null
@@ -1,630 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "mmrendereraudiorolecontrol_p.h"
-#include "mmrenderermediaplayercontrol_p.h"
-#include "mmrendererplayervideorenderercontrol_p.h"
-#include "mmrendererutil_p.h"
-#include "mmrenderervideowindowcontrol_p.h"
-#include <QtCore/qabstracteventdispatcher.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/quuid.h>
-#include <mm/renderer.h>
-
-#include <errno.h>
-#include <sys/strm.h>
-#include <sys/stat.h>
-
-QT_BEGIN_NAMESPACE
-
-static int idCounter = 0;
-
-MmRendererMediaPlayerControl::MmRendererMediaPlayerControl(QMediaPlayer *parent)
- : QPlatformMediaPlayer(parent),
- m_context(0),
- m_id(-1),
- m_connection(0),
- m_audioId(-1),
- m_state(QMediaPlayer::StoppedState),
- m_volume(100),
- m_muted(false),
- m_rate(1),
- m_position(0),
- m_mediaStatus(QMediaPlayer::NoMedia),
- m_playAfterMediaLoaded(false),
- m_inputAttached(false),
- m_bufferLevel(0)
-{
- m_loadingTimer.setSingleShot(true);
- m_loadingTimer.setInterval(0);
- connect(&m_loadingTimer, SIGNAL(timeout()), this, SLOT(continueLoadMedia()));
- QCoreApplication::eventDispatcher()->installNativeEventFilter(this);
-}
-
-void MmRendererMediaPlayerControl::destroy()
-{
- stop();
- detach();
- closeConnection();
- QCoreApplication::eventDispatcher()->removeNativeEventFilter(this);
-}
-
-void MmRendererMediaPlayerControl::openConnection()
-{
- m_connection = mmr_connect(NULL);
- if (!m_connection) {
- emitPError("Unable to connect to the multimedia renderer");
- return;
- }
-
- m_id = idCounter++;
- m_contextName = QString("MmRendererMediaPlayerControl_%1_%2").arg(m_id)
- .arg(QCoreApplication::applicationPid());
- m_context = mmr_context_create(m_connection, m_contextName.toLatin1(),
- 0, S_IRWXU|S_IRWXG|S_IRWXO);
- if (!m_context) {
- emitPError("Unable to create context");
- closeConnection();
- return;
- }
-
- startMonitoring();
-}
-
-void MmRendererMediaPlayerControl::handleMmStopped()
-{
- // Only react to stop events that happen when the end of the stream is reached and
- // playback is stopped because of this.
- // Ignore other stop event sources, such as calling mmr_stop() ourselves.
- if (m_state != QMediaPlayer::StoppedState) {
- setMediaStatus(QMediaPlayer::EndOfMedia);
- stopInternal(IgnoreMmRenderer);
- }
-}
-
-void MmRendererMediaPlayerControl::handleMmSuspend(const QString &reason)
-{
- if (m_state == QMediaPlayer::StoppedState)
- return;
-
- Q_UNUSED(reason);
- setMediaStatus(QMediaPlayer::StalledMedia);
-}
-
-void MmRendererMediaPlayerControl::handleMmSuspendRemoval(const QString &bufferProgress)
-{
- if (m_state == QMediaPlayer::StoppedState)
- return;
-
- if (bufferProgress == QLatin1String("buffering"))
- setMediaStatus(QMediaPlayer::BufferingMedia);
- else
- setMediaStatus(QMediaPlayer::BufferedMedia);
-}
-
-void MmRendererMediaPlayerControl::handleMmPause()
-{
- if (m_state == QMediaPlayer::PlayingState) {
- setState(QMediaPlayer::PausedState);
- }
-}
-
-void MmRendererMediaPlayerControl::handleMmPlay()
-{
- if (m_state == QMediaPlayer::PausedState) {
- setState(QMediaPlayer::PlayingState);
- }
-}
-
-void MmRendererMediaPlayerControl::closeConnection()
-{
- stopMonitoring();
-
- if (m_context) {
- mmr_context_destroy(m_context);
- m_context = 0;
- m_contextName.clear();
- }
-
- if (m_connection) {
- mmr_disconnect(m_connection);
- m_connection = 0;
- }
-}
-
-QByteArray MmRendererMediaPlayerControl::resourcePathForUrl(const QUrl &url)
-{
- // If this is a local file, mmrenderer expects the file:// prefix and an absolute path.
- // We treat URLs without scheme as local files, most likely someone just forgot to set the
- // file:// prefix when constructing the URL.
- if (url.isLocalFile() || url.scheme().isEmpty()) {
- QString relativeFilePath;
- if (!url.scheme().isEmpty())
- relativeFilePath = url.toLocalFile();
- else
- relativeFilePath = url.path();
- const QFileInfo fileInfo(relativeFilePath);
- return QFile::encodeName(QStringLiteral("file://") + fileInfo.absoluteFilePath());
-
- // HTTP or similar URL
- } else {
- return url.toEncoded();
- }
-}
-
-void MmRendererMediaPlayerControl::attach()
-{
- // Should only be called in detached state
- Q_ASSERT(m_audioId == -1 && !m_inputAttached);
-
- if (m_media.isNull() || !m_context) {
- setMediaStatus(QMediaPlayer::NoMedia);
- return;
- }
-
- resetMonitoring();
-
- if (m_videoRendererControl)
- m_videoRendererControl->attachDisplay(m_context);
-
- if (m_videoWindowControl)
- m_videoWindowControl->attachDisplay(m_context);
-
- const QByteArray defaultAudioDevice = qgetenv("QQNX_RENDERER_DEFAULT_AUDIO_SINK");
- m_audioId = mmr_output_attach(m_context, defaultAudioDevice.isEmpty() ? "audio:default" : defaultAudioDevice.constData(), "audio");
- if (m_audioId == -1) {
- emitMmError("mmr_output_attach() for audio failed");
- return;
- }
-
- if (m_audioId != -1) {
- QString audioType = qnxAudioType(m_role);
- QByteArray latin1AudioType = audioType.toLatin1();
- if (!audioType.isEmpty() && latin1AudioType == audioType) {
- strm_dict_t *dict = strm_dict_new();
- dict = strm_dict_set(dict, "audio_type", latin1AudioType.constData());
- if (mmr_output_parameters(m_context, m_audioId, dict) != 0)
- emitMmError("mmr_output_parameters: Setting audio_type failed");
- }
- }
-
- const QByteArray resourcePath = resourcePathForUrl(m_media.request().url());
- if (resourcePath.isEmpty()) {
- detach();
- return;
- }
-
- if (mmr_input_attach(m_context, resourcePath.constData(), "track") != 0) {
- emitMmError(QStringLiteral("mmr_input_attach() failed for ") + QString(resourcePath));
- setMediaStatus(QMediaPlayer::InvalidMedia);
- detach();
- return;
- }
-
- m_inputAttached = true;
- setMediaStatus(QMediaPlayer::LoadedMedia);
-
- // mm-renderer has buffer properties "status" and "level"
- // QMediaPlayer's buffer status maps to mm-renderer's buffer level
- m_bufferLevel = 0;
- emit bufferProgressChanged(m_bufferLevel/100.);
-}
-
-void MmRendererMediaPlayerControl::detach()
-{
- if (m_context) {
- if (m_inputAttached) {
- mmr_input_detach(m_context);
- m_inputAttached = false;
- }
- if (m_videoRendererControl)
- m_videoRendererControl->detachDisplay();
- if (m_videoWindowControl)
- m_videoWindowControl->detachDisplay();
- if (m_audioId != -1 && m_context) {
- mmr_output_detach(m_context, m_audioId);
- m_audioId = -1;
- }
- }
-
- m_loadingTimer.stop();
-}
-
-QMediaPlayer::State MmRendererMediaPlayerControl::state() const
-{
- return m_state;
-}
-
-QMediaPlayer::MediaStatus MmRendererMediaPlayerControl::mediaStatus() const
-{
- return m_mediaStatus;
-}
-
-qint64 MmRendererMediaPlayerControl::duration() const
-{
- return m_metaData.duration();
-}
-
-qint64 MmRendererMediaPlayerControl::position() const
-{
- return m_position;
-}
-
-void MmRendererMediaPlayerControl::setPosition(qint64 position)
-{
- if (m_position != position) {
- m_position = position;
-
- // Don't update in stopped state, it would not have any effect. Instead, the position is
- // updated in play().
- if (m_state != QMediaPlayer::StoppedState)
- setPositionInternal(m_position);
-
- emit positionChanged(m_position);
- }
-}
-
-int MmRendererMediaPlayerControl::volume() const
-{
- return m_volume;
-}
-
-void MmRendererMediaPlayerControl::setVolumeInternal(int newVolume)
-{
- if (!m_context)
- return;
-
- newVolume = qBound(0, newVolume, 100);
- if (m_audioId != -1) {
- strm_dict_t * dict = strm_dict_new();
- dict = strm_dict_set(dict, "volume", QString::number(newVolume).toLatin1());
- if (mmr_output_parameters(m_context, m_audioId, dict) != 0)
- emitMmError("mmr_output_parameters: Setting volume failed");
- }
-}
-
-void MmRendererMediaPlayerControl::setPlaybackRateInternal(qreal rate)
-{
- if (!m_context)
- return;
-
- const int mmRate = rate * 1000;
- if (mmr_speed_set(m_context, mmRate) != 0)
- emitMmError("mmr_speed_set failed");
-}
-
-void MmRendererMediaPlayerControl::setPositionInternal(qint64 position)
-{
- if (!m_context)
- return;
-
- if (m_metaData.isSeekable()) {
- if (mmr_seek(m_context, QString::number(position).toLatin1()) != 0)
- emitMmError("Seeking failed");
- }
-}
-
-void MmRendererMediaPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status)
-{
- if (m_mediaStatus != status) {
- m_mediaStatus = status;
- emit mediaStatusChanged(m_mediaStatus);
- }
-}
-
-void MmRendererMediaPlayerControl::setState(QMediaPlayer::State state)
-{
- if (m_state != state) {
- if (m_videoRendererControl) {
- if (state == QMediaPlayer::PausedState || state == QMediaPlayer::StoppedState) {
- m_videoRendererControl->pause();
- } else if ((state == QMediaPlayer::PlayingState)
- && (m_state == QMediaPlayer::PausedState
- || m_state == QMediaPlayer::StoppedState)) {
- m_videoRendererControl->resume();
- }
- }
-
- m_state = state;
- emit stateChanged(m_state);
- }
-}
-
-void MmRendererMediaPlayerControl::stopInternal(StopCommand stopCommand)
-{
- resetMonitoring();
- setPosition(0);
-
- if (m_state != QMediaPlayer::StoppedState) {
-
- if (stopCommand == StopMmRenderer) {
- mmr_stop(m_context);
- }
-
- setState(QMediaPlayer::StoppedState);
- }
-}
-
-void MmRendererMediaPlayerControl::setVolume(int volume)
-{
- const int newVolume = qBound(0, volume, 100);
- if (m_volume != newVolume) {
- m_volume = newVolume;
- if (!m_muted)
- setVolumeInternal(m_volume);
- emit volumeChanged(m_volume);
- }
-}
-
-bool MmRendererMediaPlayerControl::isMuted() const
-{
- return m_muted;
-}
-
-void MmRendererMediaPlayerControl::setMuted(bool muted)
-{
- if (m_muted != muted) {
- m_muted = muted;
- setVolumeInternal(muted ? 0 : m_volume);
- emit mutedChanged(muted);
- }
-}
-
-float MmRendererMediaPlayerControl::bufferProgress() const
-{
- // mm-renderer has buffer properties "status" and "level"
- // QMediaPlayer's buffer status maps to mm-renderer's buffer level
- return m_bufferLevel/100.;
-}
-
-bool MmRendererMediaPlayerControl::isAudioAvailable() const
-{
- return m_metaData.hasAudio();
-}
-
-bool MmRendererMediaPlayerControl::isVideoAvailable() const
-{
- return m_metaData.hasVideo();
-}
-
-bool MmRendererMediaPlayerControl::isSeekable() const
-{
- return m_metaData.isSeekable();
-}
-
-QMediaTimeRange MmRendererMediaPlayerControl::availablePlaybackRanges() const
-{
- // We can't get this information from the mmrenderer API yet, so pretend we can seek everywhere
- return QMediaTimeRange(0, m_metaData.duration());
-}
-
-qreal MmRendererMediaPlayerControl::playbackRate() const
-{
- return m_rate;
-}
-
-void MmRendererMediaPlayerControl::setPlaybackRate(qreal rate)
-{
- if (m_rate != rate) {
- m_rate = rate;
- setPlaybackRateInternal(m_rate);
- emit playbackRateChanged(m_rate);
- }
-}
-
-QUrl MmRendererMediaPlayerControl::media() const
-{
- return m_media;
-}
-
-const QIODevice *MmRendererMediaPlayerControl::mediaStream() const
-{
- // Always 0, we don't support QIODevice streams
- return 0;
-}
-
-void MmRendererMediaPlayerControl::setMedia(const QUrl &media, QIODevice *stream)
-{
- Q_UNUSED(stream); // not supported
-
- stop();
- detach();
-
- m_media = media;
-
- // Slight hack: With MediaPlayer QtQuick elements that have autoPlay set to true, playback
- // would start before the QtQuick canvas is propagated to all elements, and therefore our
- // video output would not work. Therefore, delay actually playing the media a bit so that the
- // canvas is ready.
- // The mmrenderer doesn't allow to attach video outputs after playing has started, otherwise
- // this would be unnecessary.
- if (!m_media.isNull()) {
- setMediaStatus(QMediaPlayer::LoadingMedia);
- m_loadingTimer.start(); // singleshot timer to continueLoadMedia()
- } else {
- continueLoadMedia(); // still needed, as it will update the media status and clear metadata
- }
-}
-
-void MmRendererMediaPlayerControl::continueLoadMedia()
-{
- updateMetaData(nullptr);
- attach();
- if (m_playAfterMediaLoaded)
- play();
-}
-
-MmRendererVideoWindowControl *MmRendererMediaPlayerControl::videoWindowControl() const
-{
- return m_videoWindowControl;
-}
-
-void MmRendererMediaPlayerControl::play()
-{
- if (m_playAfterMediaLoaded)
- m_playAfterMediaLoaded = false;
-
- // No-op if we are already playing, except if we were called from continueLoadMedia(), in which
- // case m_playAfterMediaLoaded is true (hence the 'else').
- else if (m_state == QMediaPlayer::PlayingState)
- return;
-
- if (m_mediaStatus == QMediaPlayer::LoadingMedia) {
-
- // State changes are supposed to be synchronous
- setState(QMediaPlayer::PlayingState);
-
- // Defer playing to later, when the timer triggers continueLoadMedia()
- m_playAfterMediaLoaded = true;
- return;
- }
-
- // Un-pause the state when it is paused
- if (m_state == QMediaPlayer::PausedState) {
- setPlaybackRateInternal(m_rate);
- setState(QMediaPlayer::PlayingState);
- return;
- }
-
- if (m_media.isNull() || !m_connection || !m_context || m_audioId == -1) {
- setState(QMediaPlayer::StoppedState);
- return;
- }
-
- if (m_mediaStatus == QMediaPlayer::EndOfMedia)
- m_position = 0;
-
- resetMonitoring();
- setPositionInternal(m_position);
- setVolumeInternal(m_muted ? 0 : m_volume);
- setPlaybackRateInternal(m_rate);
-
- if (mmr_play(m_context) != 0) {
- setState(QMediaPlayer::StoppedState);
- emitMmError("mmr_play() failed");
- return;
- }
-
- setState( QMediaPlayer::PlayingState);
-}
-
-void MmRendererMediaPlayerControl::pause()
-{
- if (m_state == QMediaPlayer::PlayingState) {
- setPlaybackRateInternal(0);
- setState(QMediaPlayer::PausedState);
- }
-}
-
-void MmRendererMediaPlayerControl::stop()
-{
- stopInternal(StopMmRenderer);
-}
-
-MmRendererPlayerVideoRendererControl *MmRendererMediaPlayerControl::videoRendererControl() const
-{
- return m_videoRendererControl;
-}
-
-void MmRendererMediaPlayerControl::setVideoRendererControl(MmRendererPlayerVideoRendererControl *videoControl)
-{
- m_videoRendererControl = videoControl;
-}
-
-void MmRendererMediaPlayerControl::setVideoWindowControl(MmRendererVideoWindowControl *videoControl)
-{
- m_videoWindowControl = videoControl;
-}
-
-void MmRendererMediaPlayerControl::setMmPosition(qint64 newPosition)
-{
- if (newPosition != 0 && newPosition != m_position) {
- m_position = newPosition;
- emit positionChanged(m_position);
- }
-}
-
-void MmRendererMediaPlayerControl::setMmBufferStatus(const QString &bufferProgress)
-{
- if (bufferProgress == QLatin1String("buffering"))
- setMediaStatus(QMediaPlayer::BufferingMedia);
- else if (bufferProgress == QLatin1String("playing"))
- setMediaStatus(QMediaPlayer::BufferedMedia);
- // ignore "idle" buffer status
-}
-
-void MmRendererMediaPlayerControl::setMmBufferLevel(int level, int capacity)
-{
- m_bufferLevel = capacity == 0 ? 0 : level / static_cast<float>(capacity) * 100.0f;
- m_bufferLevel = qBound(0, m_bufferLevel, 100);
- emit bufferProgressChanged(m_bufferLevel/100.);
-}
-
-void MmRendererMediaPlayerControl::updateMetaData(const strm_dict *dict)
-{
- m_metaData.update(dict);
-
- if (m_videoWindowControl)
- m_videoWindowControl->setMetaData(m_metaData);
-
- // ### convert to QMediaMetaData and notify the player about metadata changes
- emit durationChanged(m_metaData.duration());
- emit audioAvailableChanged(m_metaData.hasAudio());
- emit videoAvailableChanged(m_metaData.hasVideo());
- emit availablePlaybackRangesChanged(availablePlaybackRanges());
- emit seekableChanged(m_metaData.isSeekable());
-}
-
-void MmRendererMediaPlayerControl::emitMmError(const QString &msg)
-{
- int errorCode = MMR_ERROR_NONE;
- const QString errorMessage = mmErrorMessage(msg, m_context, &errorCode);
- qDebug() << errorMessage;
- emit error(errorCode, errorMessage);
-}
-
-void MmRendererMediaPlayerControl::emitPError(const QString &msg)
-{
- const QString errorMessage = QString("%1: %2").arg(msg).arg(strerror(errno));
- qDebug() << errorMessage;
- emit error(errno, errorMessage);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol_p.h b/src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol_p.h
deleted file mode 100644
index 63ae3c407..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrenderermediaplayercontrol_p.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef MMRENDERERMEDIAPLAYERCONTROL_H
-#define MMRENDERERMEDIAPLAYERCONTROL_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 "mmrenderermetadata_p.h"
-#include <private/qplatformmediaplayer_p.h>
-#include <QtCore/qabstractnativeeventfilter.h>
-#include <QtCore/qpointer.h>
-#include <QtCore/qtimer.h>
-
-typedef struct mmr_connection mmr_connection_t;
-typedef struct mmr_context mmr_context_t;
-typedef struct mmrenderer_monitor mmrenderer_monitor_t;
-typedef struct strm_dict strm_dict_t;
-
-QT_BEGIN_NAMESPACE
-
-class MmRendererAudioRoleControl;
-class MmRendererPlayerVideoRendererControl;
-class MmRendererVideoWindowControl;
-
-class MmRendererMediaPlayerControl : public QPlatformMediaPlayer, public QAbstractNativeEventFilter
-{
- Q_OBJECT
-public:
- explicit MmRendererMediaPlayerControl(QMediaPlayer *parent = 0);
-
- QMediaPlayer::State state() const override;
-
- QMediaPlayer::MediaStatus mediaStatus() const override;
-
- qint64 duration() const override;
-
- qint64 position() const override;
- void setPosition(qint64 position) override;
-
- int volume() const override;
- void setVolume(int volume) override;
-
- bool isMuted() const override;
- void setMuted(bool muted) override;
-
- float bufferProgress() const override;
-
- bool isAudioAvailable() const override;
- bool isVideoAvailable() const override;
-
- bool isSeekable() const override;
-
- QMediaTimeRange availablePlaybackRanges() const override;
-
- qreal playbackRate() const override;
- void setPlaybackRate(qreal rate) override;
-
- QUrl media() const override;
- const QIODevice *mediaStream() const override;
- void setMedia(const QUrl &media, QIODevice *stream) override;
-
- void play() override;
- void pause() override;
- void stop() override;
-
- MmRendererPlayerVideoRendererControl *videoRendererControl() const;
- void setVideoRendererControl(MmRendererPlayerVideoRendererControl *videoControl);
-
- MmRendererVideoWindowControl *videoWindowControl() const;
- void setVideoWindowControl(MmRendererVideoWindowControl *videoControl);
-
-protected:
- virtual void startMonitoring() = 0;
- virtual void stopMonitoring() = 0;
- virtual void resetMonitoring() = 0;
-
- void openConnection();
- void emitMmError(const QString &msg);
- void emitPError(const QString &msg);
- void setMmPosition(qint64 newPosition);
- void setMmBufferStatus(const QString &bufferProgress);
- void setMmBufferLevel(int level, int capacity);
- void handleMmStopped();
- void handleMmSuspend(const QString &reason);
- void handleMmSuspendRemoval(const QString &bufferProgress);
- void handleMmPause();
- void handleMmPlay();
- void updateMetaData(const strm_dict_t *dict);
-
- // must be called from subclass dtors (calls virtual function stopMonitoring())
- void destroy();
-
- mmr_context_t *m_context;
- int m_id;
- QString m_contextName;
-
-private Q_SLOTS:
- void continueLoadMedia();
-
-private:
- QByteArray resourcePathForUrl(const QUrl &url);
- void closeConnection();
- void attach();
- void detach();
-
- // All these set the specified value to the backend, but neither emit changed signals
- // nor change the member value.
- void setVolumeInternal(int newVolume);
- void setPlaybackRateInternal(qreal rate);
- void setPositionInternal(qint64 position);
-
- void setMediaStatus(QMediaPlayer::MediaStatus status);
- void setState(QMediaPlayer::State state);
-
- enum StopCommand { StopMmRenderer, IgnoreMmRenderer };
- void stopInternal(StopCommand stopCommand);
-
- QUrl m_media;
- mmr_connection_t *m_connection;
- int m_audioId;
- QMediaPlayer::State m_state;
- int m_volume;
- bool m_muted;
- qreal m_rate;
- QPointer<MmRendererPlayerVideoRendererControl> m_videoRendererControl;
- QPointer<MmRendererVideoWindowControl> m_videoWindowControl;
- MmRendererMetaData m_metaData;
- qint64 m_position;
- QMediaPlayer::MediaStatus m_mediaStatus;
- bool m_playAfterMediaLoaded;
- bool m_inputAttached;
- int m_bufferLevel;
- QTimer m_loadingTimer;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata.cpp b/src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata.cpp
deleted file mode 100644
index d369ea560..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "mmrenderermetadata_p.h"
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qstringlist.h>
-
-#include <mm/renderer/events.h>
-#include <sys/neutrino.h>
-#include <sys/strm.h>
-
-static const char *strm_string_getx(const strm_string_t *sstr, const char *defaultValue)
-{
- return sstr ? strm_string_get(sstr) : defaultValue;
-}
-
-#if _NTO_VERSION < 700
-static strm_dict_t *mmr_metadata_split(strm_dict_t const *, const char *, unsigned)
-{
- return nullptr;
-}
-#endif
-
-QT_BEGIN_NAMESPACE
-
-MmRendererMetaData::MmRendererMetaData()
-{
- clear();
-}
-
-static const char * titleKey = "md_title_name";
-static const char * artistKey = "md_title_artist";
-static const char * commentKey = "md_title_comment";
-static const char * genreKey = "md_title_genre";
-static const char * yearKey = "md_title_year";
-static const char * durationKey = "md_title_duration";
-static const char * bitRateKey = "md_title_bitrate";
-static const char * sampleKey = "md_title_samplerate";
-static const char * albumKey = "md_title_album";
-static const char * trackKey = "md_title_track";
-static const char * widthKey = "md_video_width";
-static const char * heightKey = "md_video_height";
-static const char * mediaTypeKey = "md_title_mediatype";
-static const char * pixelWidthKey = "md_video_pixel_width";
-static const char * pixelHeightKey = "md_video_pixel_height";
-static const char * seekableKey = "md_title_seekable";
-static const char * trackSampleKey = "sample_rate";
-static const char * trackBitRateKey = "bitrate";
-static const char * trackWidthKey = "width";
-static const char * trackHeightKey = "height";
-static const char * trackPixelWidthKey = "pixel_width";
-static const char * trackPixelHeightKey = "pixel_height";
-
-static const int mediaTypeAudioFlag = 4;
-static const int mediaTypeVideoFlag = 2;
-
-bool MmRendererMetaData::update(const strm_dict_t *dict)
-{
- if (!dict) {
- clear();
- return true;
- }
-
- const strm_string_t *value;
-
- value = strm_dict_find_rstr(dict, durationKey);
- m_duration = QByteArray(strm_string_getx(value, "0")).toLongLong();
-
- value = strm_dict_find_rstr(dict, mediaTypeKey);
- m_mediaType = QByteArray(strm_string_getx(value, "-1")).toInt();
-
- value = strm_dict_find_rstr(dict, titleKey);
- m_title = QString::fromLatin1(QByteArray(strm_string_getx(value, nullptr)));
-
- value = strm_dict_find_rstr(dict, seekableKey);
- m_seekable = (strcmp(strm_string_getx(value, "1"), "0") != 0);
-
- value = strm_dict_find_rstr(dict, artistKey);
- m_artist = QString::fromLatin1(QByteArray(strm_string_getx(value, nullptr)));
-
- value = strm_dict_find_rstr(dict, commentKey);
- m_comment = QString::fromLatin1(QByteArray(strm_string_getx(value, nullptr)));
-
- value = strm_dict_find_rstr(dict, genreKey);
- m_genre = QString::fromLatin1(QByteArray(strm_string_getx(value, nullptr)));
-
- value = strm_dict_find_rstr(dict, yearKey);
- m_year = QByteArray(strm_string_getx(value, "0")).toInt();
-
- value = strm_dict_find_rstr(dict, albumKey);
- m_album = QString::fromLatin1(QByteArray(strm_string_getx(value, nullptr)));
-
- value = strm_dict_find_rstr(dict, trackKey);
- m_track = QByteArray(strm_string_getx(value, "0")).toInt();
-
- strm_dict_t *at = mmr_metadata_split(dict, "audio", 0);
- if (at) {
- value = strm_dict_find_rstr(at, trackSampleKey);
- m_sampleRate = QByteArray(strm_string_getx(value, "0")).toInt();
-
- value = strm_dict_find_rstr(at, trackBitRateKey);
- m_audioBitRate = QByteArray(strm_string_getx(value, "0")).toInt();
-
- strm_dict_destroy(at);
- } else {
- value = strm_dict_find_rstr(dict, sampleKey);
- m_sampleRate = QByteArray(strm_string_getx(value, "0")).toInt();
-
- value = strm_dict_find_rstr(dict, bitRateKey);
- m_audioBitRate = QByteArray(strm_string_getx(value, "0")).toInt();
- }
-
- strm_dict_t *vt = mmr_metadata_split(dict, "video", 0);
- if (vt) {
- value = strm_dict_find_rstr(vt, trackWidthKey);
- m_width = QByteArray(strm_string_getx(value, "0")).toInt();
-
- value = strm_dict_find_rstr(vt, trackHeightKey);
- m_height = QByteArray(strm_string_getx(value, "0")).toInt();
-
- value = strm_dict_find_rstr(vt, trackPixelWidthKey);
- m_pixelWidth = QByteArray(strm_string_getx(value, "1")).toFloat();
-
- value = strm_dict_find_rstr(vt, trackPixelHeightKey);
- m_pixelHeight = QByteArray(strm_string_getx(value, "1")).toFloat();
-
- strm_dict_destroy(vt);
- } else {
- value = strm_dict_find_rstr(dict, widthKey);
- m_width = QByteArray(strm_string_getx(value, "0")).toInt();
-
- value = strm_dict_find_rstr(dict, heightKey);
- m_height = QByteArray(strm_string_getx(value, "0")).toInt();
-
- value = strm_dict_find_rstr(dict, pixelWidthKey);
- m_pixelWidth = QByteArray(strm_string_getx(value, "1")).toFloat();
-
- value = strm_dict_find_rstr(dict, pixelHeightKey);
- m_pixelHeight = QByteArray(strm_string_getx(value, "1")).toFloat();
- }
-
- return true;
-}
-
-void MmRendererMetaData::clear()
-{
- strm_dict_t *dict;
- dict = strm_dict_new();
- update(dict);
- strm_dict_destroy(dict);
-}
-
-qlonglong MmRendererMetaData::duration() const
-{
- return m_duration;
-}
-
-// Handling of pixel aspect ratio
-//
-// If the pixel aspect ratio is different from 1:1, it means the video needs to be stretched in
-// order to look natural.
-// For example, if the pixel width is 2, and the pixel height is 1, it means a video of 300x200
-// pixels needs to be displayed as 600x200 to look correct.
-// In order to support this the easiest way, we simply pretend that the actual size of the video
-// is 600x200, which will cause the video to be displayed in an aspect ratio of 3:1 instead of 3:2,
-// and therefore look correct.
-
-int MmRendererMetaData::height() const
-{
- return m_height * m_pixelHeight;
-}
-
-int MmRendererMetaData::width() const
-{
- return m_width * m_pixelWidth;
-}
-
-bool MmRendererMetaData::hasVideo() const
-{
- // By default, assume no video if we can't extract the information
- if (m_mediaType == -1)
- return false;
-
- return (m_mediaType & mediaTypeVideoFlag);
-}
-
-bool MmRendererMetaData::hasAudio() const
-{
- // By default, assume audio only if we can't extract the information
- if (m_mediaType == -1)
- return true;
-
- return (m_mediaType & mediaTypeAudioFlag);
-}
-
-QString MmRendererMetaData::title() const
-{
- return m_title;
-}
-
-bool MmRendererMetaData::isSeekable() const
-{
- return m_seekable;
-}
-
-QString MmRendererMetaData::artist() const
-{
- return m_artist;
-}
-
-QString MmRendererMetaData::comment() const
-{
- return m_comment;
-}
-
-QString MmRendererMetaData::genre() const
-{
- return m_genre;
-}
-
-int MmRendererMetaData::year() const
-{
- return m_year;
-}
-
-QString MmRendererMetaData::mediaType() const
-{
- if (hasVideo())
- return QLatin1String("video");
- else if (hasAudio())
- return QLatin1String("audio");
- else
- return QString();
-}
-
-int MmRendererMetaData::audioBitRate() const
-{
- return m_audioBitRate;
-}
-
-int MmRendererMetaData::sampleRate() const
-{
- return m_sampleRate;
-}
-
-QString MmRendererMetaData::album() const
-{
- return m_album;
-}
-
-int MmRendererMetaData::track() const
-{
- return m_track;
-}
-
-QSize MmRendererMetaData::resolution() const
-{
- return QSize(width(), height());
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata_p.h b/src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata_p.h
deleted file mode 100644
index 72b10a110..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrenderermetadata_p.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef MMRENDERERMETADATA_H
-#define MMRENDERERMETADATA_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/qglobal.h>
-#include <QtCore/QSize>
-#include <QtCore/QString>
-
-typedef struct strm_dict strm_dict_t;
-
-QT_BEGIN_NAMESPACE
-
-class MmRendererMetaData
-{
-public:
- MmRendererMetaData();
- bool update(const strm_dict_t *dict);
- void clear();
-
- // Duration in milliseconds
- qlonglong duration() const;
-
- int height() const;
- int width() const;
- bool hasVideo() const;
- bool hasAudio() const;
- bool isSeekable() const;
-
- QString title() const;
- QString artist() const;
- QString comment() const;
- QString genre() const;
- int year() const;
- QString mediaType() const;
- int audioBitRate() const;
- int sampleRate() const;
- QString album() const;
- int track() const;
- QSize resolution() const;
-
-private:
- qlonglong m_duration;
- int m_height;
- int m_width;
- int m_mediaType;
- float m_pixelWidth;
- float m_pixelHeight;
- bool m_seekable;
- QString m_title;
- QString m_artist;
- QString m_comment;
- QString m_genre;
- int m_year;
- int m_audioBitRate;
- int m_sampleRate;
- QString m_album;
- int m_track;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp b/src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp
deleted file mode 100644
index dbcfad245..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mmrendererplayervideorenderercontrol_p.h"
-
-#include "windowgrabber.h"
-
-#include <QCoreApplication>
-#include <QDebug>
-#include <QVideoFrameFormat>
-#include <QOpenGLContext>
-
-#include <mm/renderer.h>
-
-QT_BEGIN_NAMESPACE
-
-static int winIdCounter = 0;
-
-MmRendererPlayerVideoRendererControl::MmRendererPlayerVideoRendererControl(QObject *parent)
- : QVideoRendererControl(parent)
- , m_windowGrabber(new WindowGrabber(this))
- , m_context(0)
- , m_videoId(-1)
-{
- connect(m_windowGrabber, SIGNAL(updateScene(const QSize &)), SLOT(updateScene(const QSize &)));
-}
-
-MmRendererPlayerVideoRendererControl::~MmRendererPlayerVideoRendererControl()
-{
- detachDisplay();
-}
-
-QVideoSink *MmRendererPlayerVideoRendererControl::sink() const
-{
- return m_sink;
-}
-
-void MmRendererPlayerVideoRendererControl::setSink(QVideoSink *surface)
-{
- m_sink = QPointer<QAbstractVideoSurface>(surface);
- if (QOpenGLContext::currentContext())
- m_windowGrabber->checkForEglImageExtension();
- else if (m_sink)
- m_sink->setProperty("_q_GLThreadCallback", QVariant::fromValue<QObject*>(this));
-}
-
-void MmRendererPlayerVideoRendererControl::attachDisplay(mmr_context_t *context)
-{
- if (m_videoId != -1) {
- qWarning() << "MmRendererPlayerVideoRendererControl: Video output already attached!";
- return;
- }
-
- if (!context) {
- qWarning() << "MmRendererPlayerVideoRendererControl: No media player context!";
- return;
- }
-
- const QByteArray windowGroupId = m_windowGrabber->windowGroupId();
- if (windowGroupId.isEmpty()) {
- qWarning() << "MmRendererPlayerVideoRendererControl: Unable to find window group";
- return;
- }
-
- const QString windowName = QStringLiteral("MmRendererPlayerVideoRendererControl_%1_%2")
- .arg(winIdCounter++)
- .arg(QCoreApplication::applicationPid());
-
- m_windowGrabber->setWindowId(windowName.toLatin1());
-
- // Start with an invisible window, because we just want to grab the frames from it.
- const QString videoDeviceUrl = QStringLiteral("screen:?winid=%1&wingrp=%2&initflags=invisible&nodstviewport=1")
- .arg(windowName)
- .arg(QString::fromLatin1(windowGroupId));
-
- m_videoId = mmr_output_attach(context, videoDeviceUrl.toLatin1(), "video");
- if (m_videoId == -1) {
- qWarning() << "mmr_output_attach() for video failed";
- return;
- }
-
- m_context = context;
-}
-
-void MmRendererPlayerVideoRendererControl::detachDisplay()
-{
- m_windowGrabber->stop();
-
- if (m_sink)
- m_sink->stop();
-
- if (m_context && m_videoId != -1)
- mmr_output_detach(m_context, m_videoId);
-
- m_context = 0;
- m_videoId = -1;
-}
-
-void MmRendererPlayerVideoRendererControl::pause()
-{
- m_windowGrabber->pause();
-}
-
-void MmRendererPlayerVideoRendererControl::resume()
-{
- m_windowGrabber->resume();
-}
-
-class QnxTextureBuffer : public QAbstractVideoBuffer
-{
-public:
- QnxTextureBuffer(WindowGrabber *windowGrabber) :
- QAbstractVideoBuffer(QVideoFrame::GLTextureHandle)
- {
- m_windowGrabber = windowGrabber;
- m_handle = 0;
- }
- MapMode mapMode() const {
- return QVideoFrame::ReadWrite;
- }
- void unmap() {}
- MapData map(MapMode mode) override { return {}; }
- QVariant handle() const {
- if (!m_handle) {
- const_cast<QnxTextureBuffer*>(this)->m_handle = m_windowGrabber->getNextTextureId();
- }
- return m_handle;
- }
-private:
- WindowGrabber *m_windowGrabber;
- int m_handle;
-};
-
-void MmRendererPlayerVideoRendererControl::updateScene(const QSize &size)
-{
- if (m_sink) {
- // Depending on the support of EGL images on the current platform we either pass a texture
- // handle or a copy of the image data
- if (m_windowGrabber->eglImageSupported()) {
- QnxTextureBuffer *textBuffer = new QnxTextureBuffer(m_windowGrabber);
- QVideoFrame actualFrame(textBuffer, QVideoFrameFormat(size, QVideoFrameFormat::Format_BGR32));
- m_sink->setVideoFrame(actualFrame);
- } else {
- m_sink->setVideoFrame(m_windowGrabber->getNextImage().copy());
- }
- }
-}
-
-void MmRendererPlayerVideoRendererControl::customEvent(QEvent *e)
-{
- // This is running in the render thread (OpenGL enabled)
- if (e->type() == QEvent::User)
- m_windowGrabber->checkForEglImageExtension();
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol_p.h b/src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol_p.h
deleted file mode 100644
index 3c529e0b4..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrendererplayervideorenderercontrol_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef MMRENDERERPLAYERVIDEORENDERERCONTROL_H
-#define MMRENDERERPLAYERVIDEORENDERERCONTROL_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 <QPointer>
-#include <qobject.h>
-
-typedef struct mmr_context mmr_context_t;
-
-QT_BEGIN_NAMESPACE
-
-class WindowGrabber;
-class QVideoSink;
-
-class MmRendererPlayerVideoRendererControl : public QObject
-{
- Q_OBJECT
-public:
- explicit MmRendererPlayerVideoRendererControl(QObject *parent = 0);
- ~MmRendererPlayerVideoRendererControl();
-
- QVideoSink *sink() const;
- void setSink(QVideoSink *sink);
-
- // Called by media control
- void attachDisplay(mmr_context_t *context);
- void detachDisplay();
- void pause();
- void resume();
-
- void customEvent(QEvent *) override;
-
-private Q_SLOTS:
- void updateScene(const QSize &size);
-
-private:
- QPointer<QVideoSink> m_sink;
-
- WindowGrabber* m_windowGrabber;
- mmr_context_t *m_context;
-
- int m_videoId;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrendererutil.cpp b/src/multimedia/platform/qnx/mediaplayer/mmrendererutil.cpp
deleted file mode 100644
index 89cf8489b..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrendererutil.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "mmrendererutil_p.h"
-
-#include <QDebug>
-#include <QDir>
-#include <QFile>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonValue>
-#include <QMutex>
-#include <QMutex>
-#include <QString>
-#include <QXmlStreamReader>
-
-#include <mm/renderer.h>
-
-QT_BEGIN_NAMESPACE
-
-struct MmError {
- int errorCode;
- const char *name;
-};
-
-#define MM_ERROR_ENTRY(error) { error, #error }
-static const MmError mmErrors[] = {
- MM_ERROR_ENTRY(MMR_ERROR_NONE),
- MM_ERROR_ENTRY(MMR_ERROR_UNKNOWN ),
- MM_ERROR_ENTRY(MMR_ERROR_INVALID_PARAMETER ),
- MM_ERROR_ENTRY(MMR_ERROR_INVALID_STATE),
- MM_ERROR_ENTRY(MMR_ERROR_UNSUPPORTED_VALUE),
- MM_ERROR_ENTRY(MMR_ERROR_UNSUPPORTED_MEDIA_TYPE),
- MM_ERROR_ENTRY(MMR_ERROR_MEDIA_PROTECTED),
- MM_ERROR_ENTRY(MMR_ERROR_UNSUPPORTED_OPERATION),
- MM_ERROR_ENTRY(MMR_ERROR_READ),
- MM_ERROR_ENTRY(MMR_ERROR_WRITE),
- MM_ERROR_ENTRY(MMR_ERROR_MEDIA_UNAVAILABLE),
- MM_ERROR_ENTRY(MMR_ERROR_MEDIA_CORRUPTED),
- MM_ERROR_ENTRY(MMR_ERROR_OUTPUT_UNAVAILABLE),
- MM_ERROR_ENTRY(MMR_ERROR_NO_MEMORY),
- MM_ERROR_ENTRY(MMR_ERROR_RESOURCE_UNAVAILABLE),
- MM_ERROR_ENTRY(MMR_ERROR_MEDIA_DRM_NO_RIGHTS),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_CORRUPTED_DATA_STORE),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OUTPUT_PROTECTION),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_HDMI),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_DISPLAYPORT),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_DVI),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_ANALOG_VIDEO),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_ANALOG_AUDIO),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_TOSLINK),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_SPDIF),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_BLUETOOTH),
- MM_ERROR_ENTRY(MMR_ERROR_DRM_OPL_WIRELESSHD),
-};
-static const unsigned int numMmErrors = sizeof(mmErrors) / sizeof(MmError);
-
-static QBasicMutex roleMapMutex;
-static bool roleMapInitialized = false;
-static QString roleMap[QAudio::GameRole + 1];
-
-template <typename T, size_t N>
-constexpr size_t countof(T (&)[N])
-{
- return N;
-}
-
-QString keyValueMapsLocation()
-{
- QByteArray qtKeyValueMaps = qgetenv("QT_KEY_VALUE_MAPS");
- if (qtKeyValueMaps.isNull())
- return QStringLiteral("/etc/qt/keyvaluemaps");
- else
- return qtKeyValueMaps;
-}
-
-QJsonObject loadMapObject(const QString &keyValueMapPath)
-{
- QFile mapFile(keyValueMapsLocation() + keyValueMapPath);
- if (mapFile.open(QIODevice::ReadOnly)) {
- QByteArray mapFileContents = mapFile.readAll();
- QJsonDocument mapDocument = QJsonDocument::fromJson(mapFileContents);
- if (mapDocument.isObject()) {
- QJsonObject mapObject = mapDocument.object();
- return mapObject;
- }
- }
- return QJsonObject();
-}
-
-QString mmErrorMessage(const QString &msg, mmr_context_t *context, int *errorCode)
-{
- const mmr_error_info_t * const mmError = mmr_error_info(context);
-
- if (errorCode)
- *errorCode = mmError->error_code;
-
- if (mmError->error_code < numMmErrors) {
- return QString("%1: %2 (code %3)").arg(msg).arg(mmErrors[mmError->error_code].name)
- .arg(mmError->error_code);
- } else {
- return QString("%1: Unknown error code %2").arg(msg).arg(mmError->error_code);
- }
-}
-
-bool checkForDrmPermission()
-{
- QDir sandboxDir = QDir::home(); // always returns 'data' directory
- sandboxDir.cdUp(); // change to app sandbox directory
-
- QFile file(sandboxDir.filePath("app/native/bar-descriptor.xml"));
- if (!file.open(QIODevice::ReadOnly)) {
- qWarning() << "checkForDrmPermission: Unable to open bar-descriptor.xml";
- return false;
- }
-
- QXmlStreamReader reader(&file);
- while (!reader.atEnd()) {
- reader.readNextStartElement();
- if (reader.name() == QLatin1String("action")
- || reader.name() == QLatin1String("permission")) {
- if (reader.readElementText().trimmed() == QLatin1String("access_protected_media"))
- return true;
- }
- }
-
- return false;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrendererutil_p.h b/src/multimedia/platform/qnx/mediaplayer/mmrendererutil_p.h
deleted file mode 100644
index e1f972840..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrendererutil_p.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef MMRENDERERUTIL_H
-#define MMRENDERERUTIL_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/qglobal.h>
-#include <QtMultimedia/qaudio.h>
-
-typedef struct mmr_context mmr_context_t;
-
-QT_BEGIN_NAMESPACE
-
-class QString;
-
-QString mmErrorMessage(const QString &msg, mmr_context_t *context, int * errorCode = 0);
-
-bool checkForDrmPermission();
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp b/src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp
deleted file mode 100644
index aca860828..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "mmrenderervideowindowcontrol_p.h"
-#include "mmrendererutil_p.h"
-#include <QtCore/qdebug.h>
-#include <QtGui/qguiapplication.h>
-#include <QtGui/qpa/qplatformnativeinterface.h>
-#include <QtGui/qscreen.h>
-#include <QtGui/qwindow.h>
-#include <mm/renderer.h>
-
-QT_BEGIN_NAMESPACE
-
-static int winIdCounter = 0;
-
-MmRendererVideoWindowControl::MmRendererVideoWindowControl(QObject *parent)
- : QPlatformVideoSink(parent),
- m_videoId(-1),
- m_winId(0),
- m_context(0),
- m_fullscreen(false),
- m_aspectRatioMode(Qt::IgnoreAspectRatio),
- m_window(0),
- m_hue(0),
- m_brightness(0),
- m_contrast(0),
- m_saturation(0)
-{
-}
-
-MmRendererVideoWindowControl::~MmRendererVideoWindowControl()
-{
-}
-
-WId MmRendererVideoWindowControl::winId() const
-{
- return m_winId;
-}
-
-void MmRendererVideoWindowControl::setWinId(WId id)
-{
- m_winId = id;
-}
-
-void MmRendererVideoWindowControl::setDisplayRect(const QRect &rect)
-{
- if (m_displayRect != rect) {
- m_displayRect = rect;
- updateVideoPosition();
- }
-}
-
-void MmRendererVideoWindowControl::setFullScreen(bool fullScreen)
-{
- if (m_fullscreen != fullScreen) {
- m_fullscreen = fullScreen;
- updateVideoPosition();
- emit fullScreenChanged(m_fullscreen);
- }
-}
-
-void MmRendererVideoWindowControl::repaint()
-{
- // Nothing we can or should do here
-}
-
-Qt::AspectRatioMode MmRendererVideoWindowControl::aspectRatioMode() const
-{
- return m_aspectRatioMode;
-}
-
-void MmRendererVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
-{
- m_aspectRatioMode = mode;
-}
-
-void MmRendererVideoWindowControl::setBrightness(float brightness)
-{
- if (m_brightness != brightness) {
- m_brightness = brightness;
- updateBrightness();
- emit brightnessChanged(m_brightness);
- }
-}
-
-void MmRendererVideoWindowControl::setContrast(float contrast)
-{
- if (m_contrast != contrast) {
- m_contrast = contrast;
- updateContrast();
- emit contrastChanged(m_contrast);
- }
-}
-
-void MmRendererVideoWindowControl::setHue(float hue)
-{
- if (m_hue != hue) {
- m_hue = hue;
- updateHue();
- emit hueChanged(m_hue);
- }
-}
-
-void MmRendererVideoWindowControl::setSaturation(float saturation)
-{
- if (m_saturation != saturation) {
- m_saturation = saturation;
- updateSaturation();
- emit saturationChanged(m_saturation);
- }
-}
-
-void MmRendererVideoWindowControl::attachDisplay(mmr_context_t *context)
-{
- if (m_videoId != -1) {
- qDebug() << "MmRendererVideoWindowControl: Video output already attached!";
- return;
- }
-
- if (!context) {
- qDebug() << "MmRendererVideoWindowControl: No media player context!";
- return;
- }
-
- QWindow *window = findWindow(m_winId);
- if (!window) {
- qDebug() << "MmRendererVideoWindowControl: No video window!";
- return;
- }
-
- QPlatformNativeInterface * const nativeInterface = QGuiApplication::platformNativeInterface();
- if (!nativeInterface) {
- qDebug() << "MmRendererVideoWindowControl: Unable to get platform native interface";
- return;
- }
-
- const char * const groupNameData = static_cast<const char *>(
- nativeInterface->nativeResourceForWindow("windowGroup", window));
- if (!groupNameData) {
- qDebug() << "MmRendererVideoWindowControl: Unable to find window group for window"
- << window;
- return;
- }
-
- const QString groupName = QString::fromLatin1(groupNameData);
- m_windowName = QString("MmRendererVideoWindowControl_%1_%2").arg(winIdCounter++)
- .arg(QCoreApplication::applicationPid());
-
- nativeInterface->setWindowProperty(window->handle(),
- QStringLiteral("mmRendererWindowName"), m_windowName);
-
- // Start with an invisible window. If it would be visible right away, it would be at the wrong
- // position, and we can only change the position once we get the window handle.
- const QString videoDeviceUrl =
- QString("screen:?winid=%1&wingrp=%2&initflags=invisible&nodstviewport=1").arg(m_windowName).arg(groupName);
-
- m_videoId = mmr_output_attach(context, videoDeviceUrl.toLatin1(), "video");
- if (m_videoId == -1) {
- qDebug() << mmErrorMessage("mmr_output_attach() for video failed", context);
- return;
- }
-
- m_context = context;
- updateVideoPosition();
- updateHue();
- updateContrast();
- updateBrightness();
- updateSaturation();
-}
-
-void MmRendererVideoWindowControl::updateVideoPosition()
-{
- QWindow * const window = findWindow(m_winId);
- if (m_context && m_videoId != -1 && window) {
- QPoint topLeft = m_displayRect.topLeft();
-
- QScreen * const screen = window->screen();
- int width = m_fullscreen ?
- screen->size().width() :
- m_displayRect.width();
- int height = m_fullscreen ?
- screen->size().height() :
- m_displayRect.height();
-
- if (m_metaData.hasVideo() && m_metaData.width() > 0 && m_metaData.height() > 0) {
- // We need the source size to do aspect ratio scaling
- const qreal sourceRatio = m_metaData.width() / static_cast<float>(m_metaData.height());
- const qreal targetRatio = width / static_cast<float>(height);
-
- if (m_aspectRatioMode == Qt::KeepAspectRatio) {
- if (targetRatio < sourceRatio) {
- // Need to make height smaller
- const int newHeight = width / sourceRatio;
- const int heightDiff = height - newHeight;
- topLeft.ry() += heightDiff / 2;
- height = newHeight;
- } else {
- // Need to make width smaller
- const int newWidth = sourceRatio * height;
- const int widthDiff = width - newWidth;
- topLeft.rx() += widthDiff / 2;
- width = newWidth;
- }
-
- } else if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
- if (targetRatio < sourceRatio) {
- // Need to make width larger
- const int newWidth = sourceRatio * height;
- const int widthDiff = newWidth - width;
- topLeft.rx() -= widthDiff / 2;
- width = newWidth;
- } else {
- // Need to make height larger
- const int newHeight = width / sourceRatio;
- const int heightDiff = newHeight - height;
- topLeft.ry() -= heightDiff / 2;
- height = newHeight;
- }
- }
- }
-
- if (m_window != 0) {
- const int position[2] = { topLeft.x(), topLeft.y() };
- const int size[2] = { width, height };
- const int visible = m_displayRect.isValid();
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, position) != 0)
- perror("Setting video position failed");
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, size) != 0)
- perror("Setting video size failed");
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &visible) != 0)
- perror("Setting video visibility failed");
- }
- }
-}
-
-void MmRendererVideoWindowControl::updateBrightness()
-{
- if (m_window != 0) {
- const int backendValue = m_brightness * 255f;
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BRIGHTNESS, &backendValue) != 0)
- perror("Setting brightness failed");
- }
-}
-
-void MmRendererVideoWindowControl::updateContrast()
-{
- if (m_window != 0) {
- const int backendValue = m_contrast * 127f;
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_CONTRAST, &backendValue) != 0)
- perror("Setting contrast failed");
- }
-}
-
-void MmRendererVideoWindowControl::updateHue()
-{
- if (m_window != 0) {
- const int backendValue = m_hue * 127f;
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_HUE, &backendValue) != 0)
- perror("Setting hue failed");
- }
-}
-
-void MmRendererVideoWindowControl::updateSaturation()
-{
- if (m_window != 0) {
- const int backendValue = m_saturation * 127f;
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SATURATION, &backendValue) != 0)
- perror("Setting saturation failed");
- }
-}
-
-void MmRendererVideoWindowControl::detachDisplay()
-{
- if (m_context && m_videoId != -1)
- mmr_output_detach(m_context, m_videoId);
-
- m_context = 0;
- m_videoId = -1;
- m_metaData.clear();
- m_windowName.clear();
- m_window = 0;
- m_hue = 0;
- m_brightness = 0;
- m_contrast = 0;
- m_saturation = 0;
-}
-
-void MmRendererVideoWindowControl::setMetaData(const MmRendererMetaData &metaData)
-{
- m_metaData = metaData;
- setNativeSize(QSize(m_metaData.width(), m_metaData.height());)
-
- // To handle the updated source size data
- updateVideoPosition();
-}
-
-void MmRendererVideoWindowControl::screenEventHandler(const screen_event_t &screen_event)
-{
- int eventType;
- if (screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &eventType) != 0) {
- perror("MmRendererVideoWindowControl: Failed to query screen event type");
- return;
- }
-
- if (eventType != SCREEN_EVENT_CREATE)
- return;
-
- screen_window_t window = 0;
- if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0) {
- perror("MmRendererVideoWindowControl: Failed to query window property");
- return;
- }
-
- const int maxIdStrLength = 128;
- char idString[maxIdStrLength];
- if (screen_get_window_property_cv(window, SCREEN_PROPERTY_ID_STRING, maxIdStrLength, idString) != 0) {
- perror("MmRendererVideoWindowControl: Failed to query window ID string");
- return;
- }
-
- if (m_windowName == idString) {
- m_window = window;
- updateVideoPosition();
-
- const int visibleFlag = 1;
- if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &visibleFlag) != 0) {
- perror("MmRendererVideoWindowControl: Failed to make window visible");
- return;
- }
- }
-}
-
-QWindow *MmRendererVideoWindowControl::findWindow(WId id) const
-{
- const auto allWindows = QGuiApplication::allWindows();
- for (QWindow *window : allWindows)
- if (window->winId() == id)
- return window;
- return 0;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol_p.h b/src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol_p.h
deleted file mode 100644
index 6e9cc92f3..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmrenderervideowindowcontrol_p.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef MMRENDERERVIDEOWINDOWCONTROL_H
-#define MMRENDERERVIDEOWINDOWCONTROL_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 "mmrenderermetadata_p.h"
-#include "private/qplatformvideosink_p.h"
-#include <screen/screen.h>
-
-typedef struct mmr_context mmr_context_t;
-
-QT_BEGIN_NAMESPACE
-
-class MmRendererVideoWindowControl : public QPlatformVideoSink
-{
- Q_OBJECT
-public:
- explicit MmRendererVideoWindowControl(QObject *parent = 0);
- ~MmRendererVideoWindowControl();
-
- WId winId() const override;
- void setWinId(WId id) override;
-
- void setDisplayRect(const QRect &rect) override;
-
- void setFullScreen(bool fullScreen) override;
-
- void repaint() override;
-
- Qt::AspectRatioMode aspectRatioMode() const override;
- void setAspectRatioMode(Qt::AspectRatioMode mode) override;
-
- void setBrightness(float brightness) override;
- void setContrast(float contrast) override;
- void setHue(float hue) override;
- void setSaturation(float saturation) override;
-
- //
- // Called by media control
- //
- void detachDisplay();
- void attachDisplay(mmr_context_t *context);
- void setMetaData(const MmRendererMetaData &metaData);
- void screenEventHandler(const screen_event_t &event);
-
-private:
- QWindow *findWindow(WId id) const;
- void updateVideoPosition();
- void updateBrightness();
- void updateContrast();
- void updateHue();
- void updateSaturation();
-
- int m_videoId;
- WId m_winId;
- QRect m_displayRect;
- mmr_context_t *m_context;
- bool m_fullscreen;
- MmRendererMetaData m_metaData;
- Qt::AspectRatioMode m_aspectRatioMode;
- QString m_windowName;
- screen_window_t m_window;
- float m_hue;
- float m_brightness;
- float m_contrast;
- float m_saturation;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol.cpp b/src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol.cpp
deleted file mode 100644
index 218fab7e9..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 QNX Software Systems. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mmreventmediaplayercontrol_p.h"
-#include "mmreventthread_p.h"
-#include "mmrenderervideowindowcontrol_p.h"
-
-#include <mm/renderer.h>
-#include <tuple>
-
-QT_BEGIN_NAMESPACE
-
-static std::tuple<int, int, bool> parseBufferLevel(const QByteArray &value)
-{
- const int slashPos = value.indexOf('/');
- if (slashPos <= 0)
- return std::make_tuple(0, 0, false);
-
- bool ok = false;
- const int level = value.left(slashPos).toInt(&ok);
- if (!ok || level < 0)
- return std::make_tuple(0, 0, false);
-
- const int capacity = value.mid(slashPos + 1).toInt(&ok);
- if (!ok || capacity < 0)
- return std::make_tuple(0, 0, false);
-
- return std::make_tuple(level, capacity, true);
-}
-
-MmrEventMediaPlayerControl::MmrEventMediaPlayerControl(QObject *parent)
- : MmRendererMediaPlayerControl(parent)
- , m_eventThread(nullptr)
- , m_bufferProgress("")
- , m_bufferLevel(0)
- , m_bufferCapacity(0)
- , m_position(0)
- , m_suspended(false)
- , m_suspendedReason("unknown")
- , m_state(MMR_STATE_IDLE)
- , m_speed(0)
-{
- openConnection();
-}
-
-MmrEventMediaPlayerControl::~MmrEventMediaPlayerControl()
-{
- destroy();
-}
-
-void MmrEventMediaPlayerControl::startMonitoring()
-{
- m_eventThread = new MmrEventThread(m_context);
-
- connect(m_eventThread, &MmrEventThread::eventPending,
- this, &MmrEventMediaPlayerControl::readEvents);
-
- m_eventThread->setObjectName(QStringLiteral("MmrEventThread-") + QString::number(m_id));
- m_eventThread->start();
-}
-
-void MmrEventMediaPlayerControl::stopMonitoring()
-{
- delete m_eventThread;
- m_eventThread = nullptr;
-}
-
-void MmrEventMediaPlayerControl::resetMonitoring()
-{
- m_bufferProgress = "";
- m_bufferLevel = 0;
- m_bufferCapacity = 0;
- m_position = 0;
- m_suspended = false;
- m_suspendedReason = "unknown";
- m_state = MMR_STATE_IDLE;
- m_speed = 0;
-}
-
-bool MmrEventMediaPlayerControl::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
-{
- Q_UNUSED(result);
- if (eventType == "screen_event_t") {
- screen_event_t event = static_cast<screen_event_t>(message);
- if (MmRendererVideoWindowControl *control = videoWindowControl())
- control->screenEventHandler(event);
- }
-
- return false;
-}
-
-void MmrEventMediaPlayerControl::readEvents()
-{
- const mmr_event_t *event;
-
- while ((event = mmr_event_get(m_context))) {
- if (event->type == MMR_EVENT_NONE)
- break;
-
- switch (event->type) {
- case MMR_EVENT_STATUS: {
- if (event->data) {
- const strm_string_t *value;
- value = strm_dict_find_rstr(event->data, "bufferstatus");
- if (value) {
- m_bufferProgress = QByteArray(strm_string_get(value));
- if (!m_suspended)
- setMmBufferStatus(m_bufferProgress);
- }
-
- value = strm_dict_find_rstr(event->data, "bufferlevel");
- if (value) {
- const char *cstrValue = strm_string_get(value);
- int level;
- int capacity;
- bool ok;
- std::tie(level, capacity, ok) = parseBufferLevel(QByteArray(cstrValue));
- if (!ok) {
- qCritical("Could not parse buffer capacity from '%s'", cstrValue);
- } else {
- m_bufferLevel = level;
- m_bufferCapacity = capacity;
- setMmBufferLevel(level, capacity);
- }
- }
-
- value = strm_dict_find_rstr(event->data, "suspended");
- if (value) {
- if (!m_suspended) {
- m_suspended = true;
- m_suspendedReason = strm_string_get(value);
- handleMmSuspend(m_suspendedReason);
- }
- } else if (m_suspended) {
- m_suspended = false;
- handleMmSuspendRemoval(m_bufferProgress);
- }
- }
-
- if (event->pos_str) {
- const QByteArray valueBa = QByteArray(event->pos_str);
- bool ok;
- m_position = valueBa.toLongLong(&ok);
- if (!ok) {
- qCritical("Could not parse position from '%s'", valueBa.constData());
- } else {
- setMmPosition(m_position);
- }
- }
- break;
- }
- case MMR_EVENT_STATE: {
- if (event->state == MMR_STATE_PLAYING && m_speed != event->speed) {
- m_speed = event->speed;
- if (m_speed == 0)
- handleMmPause();
- else
- handleMmPlay();
- }
- break;
- }
- case MMR_EVENT_METADATA: {
- updateMetaData(event->data);
- break;
- }
- case MMR_EVENT_ERROR:
- case MMR_EVENT_NONE:
- case MMR_EVENT_OVERFLOW:
- case MMR_EVENT_WARNING:
- case MMR_EVENT_PLAYLIST:
- case MMR_EVENT_INPUT:
- case MMR_EVENT_OUTPUT:
- case MMR_EVENT_CTXTPAR:
- case MMR_EVENT_TRKPAR:
- case MMR_EVENT_OTHER: {
- break;
- }
- }
-
- // Currently, any exit from the playing state is considered a stop (end-of-media).
- // If you ever need to separate end-of-media from things like "stopped unexpectedly"
- // or "stopped because of an error", you'll find that end-of-media is signaled by an
- // MMR_EVENT_ERROR of MMR_ERROR_NONE with state changed to MMR_STATE_STOPPED.
- if (event->state != m_state && m_state == MMR_STATE_PLAYING)
- handleMmStopped();
- m_state = event->state;
- }
-
- if (m_eventThread)
- m_eventThread->signalRead();
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol_p.h b/src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol_p.h
deleted file mode 100644
index d8e437b1d..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmreventmediaplayercontrol_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 QNX Software Systems. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef MMREVENTMEDIAPLAYERCONTROL_H
-#define MMREVENTMEDIAPLAYERCONTROL_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 "mmrenderermediaplayercontrol_p.h"
-
-#include <mm/renderer/events.h>
-
-QT_BEGIN_NAMESPACE
-
-class MmrEventThread;
-
-class MmrEventMediaPlayerControl final : public MmRendererMediaPlayerControl
-{
- Q_OBJECT
-public:
- explicit MmrEventMediaPlayerControl(QObject *parent = 0);
- ~MmrEventMediaPlayerControl() override;
-
- void startMonitoring() override;
- void stopMonitoring() override;
- void resetMonitoring() override;
-
- bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override;
-
-private Q_SLOTS:
- void readEvents();
-
-private:
- MmrEventThread *m_eventThread;
-
- // status properties.
- QByteArray m_bufferProgress;
- int m_bufferLevel;
- int m_bufferCapacity;
- qint64 m_position;
- bool m_suspended;
- QByteArray m_suspendedReason;
-
- // state properties.
- mmr_state_t m_state;
- int m_speed;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmreventthread.cpp b/src/multimedia/platform/qnx/mediaplayer/mmreventthread.cpp
deleted file mode 100644
index 25f26e216..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmreventthread.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 QNX Software Systems. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mmreventthread.h"
-
-#include <QtCore/QDebug>
-
-#include <errno.h>
-#include <mm/renderer/events.h>
-#include <sys/neutrino.h>
-
-static const int c_mmrCode = _PULSE_CODE_MINAVAIL + 0;
-static const int c_readCode = _PULSE_CODE_MINAVAIL + 1;
-static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2;
-
-MmrEventThread::MmrEventThread(mmr_context_t *context)
- : QThread(),
- m_mmrContext(context)
-{
- if (Q_UNLIKELY((m_channelId = ChannelCreate(_NTO_CHF_DISCONNECT
- | _NTO_CHF_UNBLOCK
- | _NTO_CHF_PRIVATE)) == -1)) {
- qFatal("MmrEventThread: Can't continue without a channel");
- }
-
- if (Q_UNLIKELY((m_connectionId = ConnectAttach(0, 0, m_channelId,
- _NTO_SIDE_CHANNEL, 0)) == -1)) {
- ChannelDestroy(m_channelId);
- qFatal("MmrEventThread: Can't continue without a channel connection");
- }
-
- SIGEV_PULSE_INIT(&m_mmrEvent, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_mmrCode, 0);
-}
-
-MmrEventThread::~MmrEventThread()
-{
- // block until thread terminates
- shutdown();
-
- ConnectDetach(m_connectionId);
- ChannelDestroy(m_channelId);
-}
-
-void MmrEventThread::run()
-{
- int armResult = mmr_event_arm(m_mmrContext, &m_mmrEvent);
- if (armResult > 0)
- emit eventPending();
-
- while (1) {
- struct _pulse msg;
- memset(&msg, 0, sizeof(msg));
- int receiveId = MsgReceive(m_channelId, &msg, sizeof(msg), nullptr);
- if (receiveId == 0) {
- if (msg.code == c_mmrCode) {
- emit eventPending();
- } else if (msg.code == c_readCode) {
- armResult = mmr_event_arm(m_mmrContext, &m_mmrEvent);
- if (armResult > 0)
- emit eventPending();
- } else if (msg.code == c_quitCode) {
- break;
- } else {
- qWarning() << Q_FUNC_INFO << "Unexpected pulse" << msg.code;
- }
- } else if (receiveId > 0) {
- qWarning() << Q_FUNC_INFO << "Unexpected message" << msg.code;
- } else {
- qWarning() << Q_FUNC_INFO << "MsgReceive error" << strerror(errno);
- }
- }
-}
-
-void MmrEventThread::signalRead()
-{
- MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_readCode, 0);
-}
-
-void MmrEventThread::shutdown()
-{
- MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_quitCode, 0);
-
- // block until thread terminates
- wait();
-}
diff --git a/src/multimedia/platform/qnx/mediaplayer/mmreventthread_p.h b/src/multimedia/platform/qnx/mediaplayer/mmreventthread_p.h
deleted file mode 100644
index 946548686..000000000
--- a/src/multimedia/platform/qnx/mediaplayer/mmreventthread_p.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 QNX Software Systems. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MMREVENTTHREAD_H
-#define MMREVENTTHREAD_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/QThread>
-
-#include <sys/neutrino.h>
-#include <sys/siginfo.h>
-
-QT_BEGIN_NAMESPACE
-
-typedef struct mmr_context mmr_context_t;
-
-class MmrEventThread : public QThread
-{
- Q_OBJECT
-
-public:
- MmrEventThread(mmr_context_t *context);
- ~MmrEventThread() override;
-
- void signalRead();
-
-protected:
- void run() override;
-
-Q_SIGNALS:
- void eventPending();
-
-private:
- void shutdown();
-
- int m_channelId;
- int m_connectionId;
- struct sigevent m_mmrEvent;
- mmr_context_t *m_mmrContext;
-};
-
-QT_END_NAMESPACE
-
-#endif // MMREVENTTHREAD_H
diff --git a/src/multimedia/platform/qnx/qqnxdevicemanager.cpp b/src/multimedia/platform/qnx/qqnxdevicemanager.cpp
deleted file mode 100644
index 23bc0bcf0..000000000
--- a/src/multimedia/platform/qnx/qqnxdevicemanager.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqnxmediadevices_p.h"
-#include "qmediadevices.h"
-#include "qcameradevice_p.h"
-
-#include "private/qqnxaudiosource_p.h"
-#include "private/qqnxaudiosink_p.h"
-#include "private/qqnxaudiodevice_p.h"
-#include "bbcamerasession_p.h"
-
-QT_BEGIN_NAMESPACE
-
-static QList<QCameraDevice> enumerateCameras()
-{
-
- camera_unit_t cameras[10];
-
- unsigned int knownCameras = 0;
- const camera_error_t result = camera_get_supported_cameras(10, &knownCameras, cameras);
- if (result != CAMERA_EOK) {
- qWarning() << "Unable to retrieve supported camera types:" << result;
- return {};
- }
-
- QList<QCameraDevice> cameras;
- for (unsigned int i = 0; i < knownCameras; ++i) {
- QCameraDevicePrivate *p = new QCameraDevicePrivate;
- switch (cameras[i]) {
- case CAMERA_UNIT_FRONT:
- p->id = BbCameraSession::cameraIdentifierFront();
- p->description = tr("Front Camera");
- p->position = QCameraDevice::FrontFace;
- break;
- case CAMERA_UNIT_REAR:
- p->id = BbCameraSession::cameraIdentifierRear();
- p->description = tr("Rear Camera");
- p->position = QCameraDevice::BackFace;
- break;
- case CAMERA_UNIT_DESKTOP:
- p->id = devices->append(BbCameraSession::cameraIdentifierDesktop();
- p->description = tr("Desktop Camera");
- p->position = QCameraDevice::UnspecifiedPosition;
- break;
- default:
- break;
- }
- if (i == 0)
- p->isDefault = true;
- cameras.append(p->create());
- }
- return cameras;
-}
-
-QQnxMediaDevices::QQnxMediaDevices()
- : QMediaPlatformMediaDevices()
-{
-}
-
-QList<QAudioDevice> QQnxMediaDevices::audioInputs() const
-{
- return { QAudioDevice(new QnxAudioDeviceInfo("default", QAudioDevice::Input)) };
-}
-
-QList<QAudioDevice> QQnxMediaDevices::audioOutputs() const
-{
- return { QAudioDevice(new QnxAudioDeviceInfo("default", QAudioDevice::Output)) };
-}
-
-QList<QCameraDevice> QQnxMediaDevices::videoInputs() const
-{
- return enumerateCameras();
-}
-
-QPlatformAudioSource *QQnxMediaDevices::createAudioSource(const QAudioDevice &deviceInfo)
-{
- return new QQnxAudioSource();
-}
-
-QPlatformAudioSink *QQnxMediaDevices::createAudioSink(const QAudioDevice &deviceInfo)
-{
- return new QNxAudioOutput();
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/qqnxdevicemanager_p.h b/src/multimedia/platform/qnx/qqnxdevicemanager_p.h
deleted file mode 100644
index a23d451c8..000000000
--- a/src/multimedia/platform/qnx/qqnxdevicemanager_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQNXMEDIADEVICES_H
-#define QQNXMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <qaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQnxMediaDevices : public QPlatformMediaDevices
-{
-public:
- QQnxMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) override;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qnx/qqnxintegration.cpp b/src/multimedia/platform/qnx/qqnxintegration.cpp
deleted file mode 100644
index 2e5496434..000000000
--- a/src/multimedia/platform/qnx/qqnxintegration.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqnxintegration_p.h"
-#include "qqnxmediadevices_p.h"
-#include "private/mmrenderermediaplayercontrol_p.h"
-#include "private/mmrendererutil_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QQnxIntegration::QQnxIntegration()
-{
-
-}
-
-QQnxIntegration::~QQnxIntegration()
-{
- delete m_devices;
-}
-
-QMediaPlatformMediaDevices *QQnxIntegration::devices()
-{
- if (!m_devices)
- m_devices = new QQnxMediaDevices();
- return m_devices;
-}
-
-QPlatformMediaPlayer *QQnxIntegration::createPlayer(QMediaPlayer *parent)
-{
- return new MmRendererMediaPlayerControl(parent);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qnx/qqnxintegration_p.h b/src/multimedia/platform/qnx/qqnxintegration_p.h
deleted file mode 100644
index 8cc4ce9fb..000000000
--- a/src/multimedia/platform/qnx/qqnxintegration_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQNXINTEGRATION_H
-#define QQNXINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQnxMediaDevices;
-class QQnxPlayerInterface;
-
-class QQnxIntegration : public QPlatformMediaIntegration
-{
-public:
- QQnxIntegration();
- ~QQnxIntegration();
-
- QPlatformMediaDevices *devices() override;
-
- QPlatformMediaPlayer *createPlayer(QMediaPlayer *parent) override;
-
- QQnxMediaDevices *m_devices = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/qplatformaudiodecoder.cpp b/src/multimedia/platform/qplatformaudiodecoder.cpp
index 61492defb..0bf472410 100644
--- a/src/multimedia/platform/qplatformaudiodecoder.cpp
+++ b/src/multimedia/platform/qplatformaudiodecoder.cpp
@@ -1,122 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qplatformaudiodecoder_p.h"
#include "qthread.h"
QT_BEGIN_NAMESPACE
+QPlatformAudioDecoder::QPlatformAudioDecoder(QAudioDecoder *parent) : q(parent) { }
-/*!
- \class QPlatformAudioDecoder
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QPlatformAudioDecoder class provides access to audio decoding
- functionality.
-
- \preliminary
-*/
-
-/*!
- Constructs a new audio decoder control with the given \a parent.
-*/
-QPlatformAudioDecoder::QPlatformAudioDecoder(QAudioDecoder *parent)
- : QObject(parent),
- q(parent)
-{
-}
-
-/*!
- \fn QPlatformAudioDecoder::source() const
-
- Returns the current media source filename, or a null QString if none (or a device)
-*/
-
-/*!
- \fn QPlatformAudioDecoder::setSource(const QUrl &fileName)
-
- Sets the current source to \a fileName. Changing the source will
- stop any current decoding and discard any buffers.
-
- Sources are exclusive, so only one can be set.
-*/
-
-/*!
- \fn QPlatformAudioDecoder::sourceDevice() const
-
- Returns the current media source QIODevice, or 0 if none (or a file).
-*/
-
-/*!
- \fn QPlatformAudioDecoder::setSourceDevice(QIODevice *device)
-
- Sets the current source to \a device. Changing the source will
- stop any current decoding and discard any buffers.
-
- Sources are exclusive, so only one can be set.
-*/
-
-/*!
- \fn QPlatformAudioDecoder::start()
-
- Starts decoding the current media.
-
- \sa read()
-*/
-
-/*!
- \fn QPlatformAudioDecoder::stop()
-
- Stops playback of the current media and discards any buffers.
-
- If successful, the player control will immediately stop decoding.
-*/
-
-/*!
- \fn QPlatformAudioDecoder::error(int error, const QString &errorString)
-
- Signals that an \a error has occurred. The \a errorString provides a more detailed explanation.
-*/
+QPlatformAudioDecoder::~QPlatformAudioDecoder() = default;
void QPlatformAudioDecoder::error(int error, const QString &errorString)
{
@@ -124,29 +16,25 @@ void QPlatformAudioDecoder::error(int error, const QString &errorString)
return;
m_error = QAudioDecoder::Error(error);
m_errorString = errorString;
- setIsDecoding(false);
- emit q->error(m_error);
+ if (m_error != QAudioDecoder::NoError) {
+ setIsDecoding(false);
+ emit q->error(m_error);
+ }
}
-/*!
- \fn QPlatformAudioDecoder::bufferAvailableChanged(bool available)
-
- Signals that the bufferAvailable property has changed to \a available.
-*/
void QPlatformAudioDecoder::bufferAvailableChanged(bool available)
{
+ if (m_bufferAvailable == available)
+ return;
+ m_bufferAvailable = available;
+
if (QThread::currentThread() != q->thread())
QMetaObject::invokeMethod(q, "bufferAvailableChanged", Qt::QueuedConnection, Q_ARG(bool, available));
else
emit q->bufferAvailableChanged(available);
}
-/*!
- \fn QPlatformAudioDecoder::bufferReady()
-
- Signals that a new buffer is ready for reading.
-*/
void QPlatformAudioDecoder::bufferReady()
{
if (QThread::currentThread() != q->thread())
@@ -155,82 +43,39 @@ void QPlatformAudioDecoder::bufferReady()
emit q->bufferReady();
}
-/*!
- \fn QPlatformAudioDecoder::sourceChanged()
-
- Signals that the current source of the decoder has changed.
-
- \sa source(), sourceDevice()
-*/
void QPlatformAudioDecoder::sourceChanged()
{
emit q->sourceChanged();
}
-/*!
- \fn QPlatformAudioDecoder::formatChanged(const QAudioFormat &format)
-
- Signals that the current audio format of the decoder has changed to \a format.
-*/
void QPlatformAudioDecoder::formatChanged(const QAudioFormat &format)
{
emit q->formatChanged(format);
}
-/*!
- \fn void QPlatformAudioDecoder::finished()
-
- Signals that the decoding has finished successfully.
- If decoding fails, error signal is emitted instead.
-
- \sa start(), stop(), error()
-*/
void QPlatformAudioDecoder::finished()
{
+ durationChanged(-1);
setIsDecoding(false);
emit q->finished();
}
-/*!
- \fn void QPlatformAudioDecoder::positionChanged(qint64 position)
-
- Signals that the current \a position of the decoder has changed.
-
- \sa durationChanged()
-*/
void QPlatformAudioDecoder::positionChanged(qint64 position)
{
- q->positionChanged(position);
+ if (m_position == position)
+ return;
+ m_position = position;
+ emit q->positionChanged(position);
}
-/*!
- \fn void QPlatformAudioDecoder::durationChanged(qint64 duration)
-
- Signals that the estimated \a duration of the decoded data has changed.
-
- \sa positionChanged()
-*/
void QPlatformAudioDecoder::durationChanged(qint64 duration)
{
- q->durationChanged(duration);
+ if (m_duration == duration)
+ return;
+ m_duration = duration;
+ emit q->durationChanged(duration);
}
-/*!
- \fn QPlatformAudioDecoder::read()
- Attempts to read a buffer from the decoder, without blocking. Returns invalid buffer if there are
- no decoded buffers available, or on error.
-*/
-
-/*!
- \fn QPlatformAudioDecoder::position() const
- Returns position (in milliseconds) of the last buffer read from
- the decoder or -1 if no buffers have been read.
-*/
-
-/*!
- \fn QPlatformAudioDecoder::duration() const
- Returns total duration (in milliseconds) of the audio stream
- or -1 if not available.
-*/
-
QT_END_NAMESPACE
+
+#include "moc_qplatformaudiodecoder_p.cpp"
diff --git a/src/multimedia/platform/qplatformaudiodecoder_p.h b/src/multimedia/platform/qplatformaudiodecoder_p.h
index b9334102a..1159a37ca 100644
--- a/src/multimedia/platform/qplatformaudiodecoder_p.h
+++ b/src/multimedia/platform/qplatformaudiodecoder_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QAUDIODECODERCONTROL_H
#define QAUDIODECODERCONTROL_H
@@ -51,12 +15,11 @@
// We mean it.
//
-#include <QtMultimedia/qaudiodecoder.h>
-
-#include <QtCore/qpair.h>
-
#include <QtMultimedia/qaudiobuffer.h>
#include <QtMultimedia/qaudiodecoder.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qurl.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -79,10 +42,10 @@ public:
virtual void setAudioFormat(const QAudioFormat &format) = 0;
virtual QAudioBuffer read() = 0;
- virtual bool bufferAvailable() const = 0;
+ virtual bool bufferAvailable() const { return m_bufferAvailable; }
- virtual qint64 position() const = 0;
- virtual qint64 duration() const = 0;
+ virtual qint64 position() const { return m_position; }
+ virtual qint64 duration() const { return m_duration; }
void formatChanged(const QAudioFormat &format);
@@ -108,14 +71,20 @@ public:
QAudioDecoder::Error error() const { return m_error; }
QString errorString() const { return m_errorString; }
+ virtual ~QPlatformAudioDecoder();
+
protected:
explicit QPlatformAudioDecoder(QAudioDecoder *parent);
+
private:
QAudioDecoder *q = nullptr;
+ qint64 m_duration = -1;
+ qint64 m_position = -1;
QAudioDecoder::Error m_error = QAudioDecoder::NoError;
QString m_errorString;
bool m_isDecoding = false;
+ bool m_bufferAvailable = false;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformaudioinput_p.h b/src/multimedia/platform/qplatformaudioinput_p.h
index c4e4334b3..d6497c06e 100644
--- a/src/multimedia/platform/qplatformaudioinput_p.h
+++ b/src/multimedia/platform/qplatformaudioinput_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMAUDIOINPUT_H
#define QPLATFORMAUDIOINPUT_H
@@ -53,6 +17,8 @@
#include <private/qtmultimediaglobal_p.h>
#include <qaudiodevice.h>
+#include <functional>
+
QT_BEGIN_NAMESPACE
class QAudioInput;
@@ -60,10 +26,10 @@ class QAudioInput;
class Q_MULTIMEDIA_EXPORT QPlatformAudioInput
{
public:
- QPlatformAudioInput(QAudioInput *qq) : q(qq) {}
- virtual ~QPlatformAudioInput() {}
+ explicit QPlatformAudioInput(QAudioInput *qq) : q(qq) { }
+ virtual ~QPlatformAudioInput() = default;
- virtual void setAudioDevice(const QAudioDevice &/*device*/) {}
+ virtual void setAudioDevice(const QAudioDevice & /*device*/) { }
virtual void setMuted(bool /*muted*/) {}
virtual void setVolume(float /*volume*/) {}
@@ -71,6 +37,7 @@ public:
QAudioDevice device;
float volume = 1.;
bool muted = false;
+ std::function<void()> disconnectFunction;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformaudiooutput_p.h b/src/multimedia/platform/qplatformaudiooutput_p.h
index 594d59ed0..b8f5af6f3 100644
--- a/src/multimedia/platform/qplatformaudiooutput_p.h
+++ b/src/multimedia/platform/qplatformaudiooutput_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMAUDIOOUTPUT_H
#define QPLATFORMAUDIOOUTPUT_H
@@ -60,8 +24,8 @@ class QAudioOutput;
class Q_MULTIMEDIA_EXPORT QPlatformAudioOutput
{
public:
- QPlatformAudioOutput(QAudioOutput *qq) : q(qq) {}
- virtual ~QPlatformAudioOutput() {}
+ explicit QPlatformAudioOutput(QAudioOutput *qq) : q(qq) { }
+ virtual ~QPlatformAudioOutput() = default;
virtual void setAudioDevice(const QAudioDevice &/*device*/) {}
virtual void setMuted(bool /*muted*/) {}
@@ -71,6 +35,7 @@ public:
QAudioDevice device;
float volume = 1.;
bool muted = false;
+ std::function<void()> disconnectFunction;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformaudioresampler_p.h b/src/multimedia/platform/qplatformaudioresampler_p.h
new file mode 100644
index 000000000..fd8edc2be
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudioresampler_p.h
@@ -0,0 +1,33 @@
+// 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 QPLATFORMAUDIORESAMPLER_P_H
+#define QPLATFORMAUDIORESAMPLER_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 <private/qtmultimediaglobal_p.h>
+#include <qaudiobuffer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformAudioResampler
+{
+public:
+ virtual ~QPlatformAudioResampler() = default;
+
+ virtual QAudioBuffer resample(const char *data, size_t size) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMAUDIORESAMPLER_P_H
diff --git a/src/multimedia/platform/qplatformcamera.cpp b/src/multimedia/platform/qplatformcamera.cpp
index 21a13ea97..0d3975550 100644
--- a/src/multimedia/platform/qplatformcamera.cpp
+++ b/src/multimedia/platform/qplatformcamera.cpp
@@ -1,93 +1,59 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qplatformcamera_p.h"
+#include "private/qcameradevice_p.h"
QT_BEGIN_NAMESPACE
-/*!
- \class QPlatformCamera
- \obsolete
-
+QPlatformCamera::QPlatformCamera(QCamera *parent) : QPlatformVideoSource(parent), m_camera(parent)
+{
+ qRegisterMetaType<QVideoFrame>();
+}
+QCameraFormat QPlatformCamera::findBestCameraFormat(const QCameraDevice &camera) const
+{
+ // check if fmt is better. We try to find the highest resolution that offers
+ // at least 30 FPS
+ // we use 29 FPS to compare against as some cameras report 29.97 FPS...
- \brief The QPlatformCamera class is an abstract base class for
- classes that control still cameras or video cameras.
+ auto makeCriteria = [this](const QCameraFormat &fmt) {
+ constexpr float MinSufficientFrameRate = 29.f;
- \inmodule QtMultimedia
+ const auto isValid = fmt.pixelFormat() != QVideoFrameFormat::Format_Invalid;
+ const auto resolution = fmt.resolution();
+ const auto sufficientFrameRate = std::min(fmt.maxFrameRate(), MinSufficientFrameRate);
+ const auto pixelFormatScore =
+ cameraPixelFormatScore(fmt.pixelFormat(), QCameraFormatPrivate::getColorRange(fmt));
- \ingroup multimedia_control
-*/
+ return std::make_tuple(
+ isValid, // 1st: ensure valid formats
+ sufficientFrameRate, // 2nd: ensure the highest frame rate in the range [0; 29]*/
+ resolution.width() * resolution.height(), // 3rd: ensure the highest resolution
+ pixelFormatScore, // 4th: eshure the best pixel format
+ fmt.maxFrameRate()); // 5th: ensure the highest framerate in the whole range
+ };
-/*!
- Constructs a camera control object with \a parent.
-*/
+ const auto formats = camera.videoFormats();
+ const auto found =
+ std::max_element(formats.begin(), formats.end(),
+ [makeCriteria](const QCameraFormat &fmtA, const QCameraFormat &fmtB) {
+ return makeCriteria(fmtA) < makeCriteria(fmtB);
+ });
-QPlatformCamera::QPlatformCamera(QCamera *parent)
- : QObject(parent),
- m_camera(parent)
-{
+ return found == formats.end() ? QCameraFormat{} : *found;
}
-QCameraFormat QPlatformCamera::findBestCameraFormat(const QCameraDevice &camera)
+QVideoFrameFormat QPlatformCamera::frameFormat() const
{
- QCameraFormat f;
- const auto formats = camera.videoFormats();
- for (const auto &fmt : formats) {
- // check if fmt is better. We try to find the highest resolution that offers
- // at least 30 FPS
- if (f.maxFrameRate() < 30 && fmt.maxFrameRate() > f.maxFrameRate())
- f = fmt;
- else if (f.maxFrameRate() == fmt.maxFrameRate() &&
- f.resolution().width()*f.resolution().height() < fmt.resolution().width()*fmt.resolution().height())
- f = fmt;
- }
- return f;
+ QVideoFrameFormat result(m_cameraFormat.resolution(),
+ m_framePixelFormat == QVideoFrameFormat::Format_Invalid
+ ? m_cameraFormat.pixelFormat()
+ : m_framePixelFormat);
+ result.setFrameRate(m_cameraFormat.maxFrameRate());
+ return result;
}
-/*!
- \fn void QPlatformCamera::error(int error, const QString &errorString)
-
- Signal emitted when an error occurs with error code \a error and
- a description of the error \a errorString.
-*/
-
void QPlatformCamera::supportedFeaturesChanged(QCamera::Features f)
{
if (m_supportedFeatures == f)
@@ -255,8 +221,6 @@ int QPlatformCamera::colorTemperatureForWhiteBalance(QCamera::WhiteBalanceMode m
return 0;
}
-
-
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 8ddaf51ae..85624c0ce 100644
--- a/src/multimedia/platform/qplatformcamera_p.h
+++ b/src/multimedia/platform/qplatformcamera_p.h
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QCAMERACONTROL_H
-#define QCAMERACONTROL_H
+// 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
+
+#ifndef QPLATFORMCAMERA_H
+#define QPLATFORMCAMERA_H
//
// W A R N I N G
@@ -51,25 +15,20 @@
// We mean it.
//
-#include <QtCore/qobject.h>
-#include <QtMultimedia/qtmultimediaglobal.h>
+#include "qplatformvideosource_p.h"
#include <QtMultimedia/qcamera.h>
QT_BEGIN_NAMESPACE
-class Q_MULTIMEDIA_EXPORT QPlatformCamera : public QObject
+class Q_MULTIMEDIA_EXPORT QPlatformCamera : public QPlatformVideoSource
{
Q_OBJECT
public:
- virtual bool isActive() const = 0;
- virtual void setActive(bool active) = 0;
-
virtual void setCamera(const QCameraDevice &camera) = 0;
virtual bool setCameraFormat(const QCameraFormat &/*format*/) { return false; }
-
- virtual void setCaptureSession(QPlatformMediaCaptureSession *) {}
+ QCameraFormat cameraFormat() const { return m_cameraFormat; }
virtual bool isFocusModeSupported(QCamera::FocusMode mode) const { return mode == QCamera::FocusModeAuto; }
virtual void setFocusMode(QCamera::FocusMode /*mode*/) {}
@@ -100,6 +59,8 @@ public:
virtual void setWhiteBalanceMode(QCamera::WhiteBalanceMode /*mode*/) {}
virtual void setColorTemperature(int /*temperature*/) {}
+ QVideoFrameFormat frameFormat() const override;
+
QCamera::Features supportedFeatures() const { return m_supportedFeatures; }
QCamera::FocusMode focusMode() const { return m_focusMode; }
@@ -150,13 +111,21 @@ public:
static int colorTemperatureForWhiteBalance(QCamera::WhiteBalanceMode mode);
Q_SIGNALS:
- void activeChanged(bool);
void error(int error, const QString &errorString);
protected:
explicit QPlatformCamera(QCamera *parent);
- static QCameraFormat findBestCameraFormat(const QCameraDevice &camera);
+ virtual int cameraPixelFormatScore(QVideoFrameFormat::PixelFormat /*format*/,
+ QVideoFrameFormat::ColorRange /*colorRange*/) const
+ {
+ return 0;
+ }
+
+ QCameraFormat findBestCameraFormat(const QCameraDevice &camera) const;
+ QCameraFormat m_cameraFormat;
+ QVideoFrameFormat::PixelFormat m_framePixelFormat = QVideoFrameFormat::Format_Invalid;
+
private:
QCamera *m_camera = nullptr;
QCamera::Features m_supportedFeatures = {};
@@ -186,5 +155,5 @@ private:
QT_END_NAMESPACE
-#endif // QCAMERACONTROL_H
+#endif // QPLATFORMCAMERA_H
diff --git a/src/multimedia/platform/qplatformcapturablewindows_p.h b/src/multimedia/platform/qplatformcapturablewindows_p.h
new file mode 100644
index 000000000..41949aaac
--- /dev/null
+++ b/src/multimedia/platform/qplatformcapturablewindows_p.h
@@ -0,0 +1,44 @@
+// 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 QPLATFORMCAPTURABLEWINDOWS_P_H
+#define QPLATFORMCAPTURABLEWINDOWS_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 "private/qtmultimediaglobal_p.h"
+#include "qcapturablewindow.h"
+
+#include <qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCapturableWindow;
+class QCapturableWindowPrivate;
+
+class QPlatformCapturableWindows
+{
+public:
+ QPlatformCapturableWindows() = default;
+
+ virtual ~QPlatformCapturableWindows() = default;
+
+ virtual QList<QCapturableWindow> windows() const { return {}; }
+
+ virtual bool isWindowValid(const QCapturableWindowPrivate &) const { return false; }
+
+ Q_DISABLE_COPY(QPlatformCapturableWindows);
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMCAPTURABLEWINDOWS_P_H
diff --git a/src/multimedia/platform/qplatformimagecapture.cpp b/src/multimedia/platform/qplatformimagecapture.cpp
index 5cfc7e31e..5d8349256 100644
--- a/src/multimedia/platform/qplatformimagecapture.cpp
+++ b/src/multimedia/platform/qplatformimagecapture.cpp
@@ -1,58 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qplatformimagecapture_p.h"
#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
-/*!
- \class QPlatformImageCapture
- \obsolete
-
- \brief The QPlatformImageCapture class provides a control interface
- for image capture services.
-
- \inmodule QtMultimedia
- \ingroup multimedia_control
-
-*/
+QPlatformImageCapture::QPlatformImageCapture(QImageCapture *parent)
+ : QObject(parent),
+ m_imageCapture(parent)
+{
+}
QString QPlatformImageCapture::msgCameraNotReady()
{
@@ -64,114 +22,6 @@ QString QPlatformImageCapture::msgImageCaptureNotSet()
return QImageCapture::tr("No instance of QImageCapture set on QMediaCaptureSession.");
}
-/*!
- Constructs a new image capture control object with the given \a parent
-*/
-QPlatformImageCapture::QPlatformImageCapture(QImageCapture *parent)
- : QObject(parent),
- m_imageCapture(parent)
-{
-}
-
-/*!
- \fn QPlatformImageCapture::isReadyForCapture() const
-
- Identifies if a capture control is ready to perform a capture
- immediately (all the resources necessary for image capture are allocated,
- hardware initialized, flash is charged, etc).
-
- Returns true if the camera is ready for capture; and false if it is not.
-
- It's permissible to call capture() while the camera status is QCamera::ActiveStatus
- regardless of isReadyForCapture property value.
- If camera is not ready to capture image immediately,
- the capture request is queued with all the related camera settings
- to be executed as soon as possible.
-*/
-
-/*!
- \fn QPlatformImageCapture::readyForCaptureChanged(bool ready)
-
- Signals that a capture control's \a ready state has changed.
-*/
-
-/*!
- \fn QPlatformImageCapture::capture(const QString &fileName)
-
- Initiates the capture of an image to \a fileName.
- The \a fileName can be relative or empty,
- in this case the service should use the system specific place
- and file naming scheme.
-
- The Camera service should save all the capture parameters
- like exposure settings or image processing parameters,
- so changes to camera parameters after capture() is called
- do not affect previous capture requests.
-
- Returns the capture request id number, which is used later
- with imageExposed(), imageCaptured() and imageSaved() signals.
-*/
-
-/*!
- \fn QPlatformImageCapture::imageExposed(int requestId)
-
- Signals that an image with it \a requestId
- has just been exposed.
- This signal can be used for the shutter sound or other indicaton.
-*/
-
-/*!
- \fn QPlatformImageCapture::imageCaptured(int requestId, const QImage &preview)
-
- Signals that an image with it \a requestId
- has been captured and a \a preview is available.
-*/
-
-/*!
- \fn QPlatformImageCapture::imageMetadataAvailable(int id, const QMediaMetaData &metaData)
-
- Signals that a metadata for an image with request \a id is available.
-
- This signal should be emitted between imageExposed and imageSaved signals.
-*/
-
-/*!
- \fn QPlatformImageCapture::imageAvailable(int requestId, const QVideoFrame &buffer)
-
- Signals that a captured \a buffer with a \a requestId is available.
-*/
-
-/*!
- \fn QPlatformImageCapture::imageSaved(int requestId, const QString &fileName)
-
- Signals that a captured image with a \a requestId has been saved
- to \a fileName.
-*/
-
-/*!
- \fn QPlatformImageCapture::imageSettings() const
-
- Returns the currently used image encoder settings.
-
- The returned value may be different than passed to setImageSettings()
- if the settings contains defaulted or undefined parameters.
-*/
-
-/*!
- \fn QPlatformImageCapture::setImageSettings(const QImageEncoderSettings &settings)
-
- Sets the selected image encoder \a settings.
-*/
-
-/*!
- \fn QPlatformImageCapture::error(int id, int error, const QString &errorString)
-
- Signals the capture request \a id failed with \a error code and message \a errorString.
-
- \sa QImageCapture::Error
-*/
-
-
QT_END_NAMESPACE
#include "moc_qplatformimagecapture_p.cpp"
diff --git a/src/multimedia/platform/qplatformimagecapture_p.h b/src/multimedia/platform/qplatformimagecapture_p.h
index 01842987d..5bfb15ced 100644
--- a/src/multimedia/platform/qplatformimagecapture_p.h
+++ b/src/multimedia/platform/qplatformimagecapture_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCAMERAIMAGECAPTURECONTROL_H
#define QCAMERAIMAGECAPTURECONTROL_H
@@ -54,6 +18,7 @@
#include <QtMultimedia/qimagecapture.h>
#include <QtMultimedia/qmediametadata.h>
#include <QtMultimedia/qimagecapture.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediacapture.cpp b/src/multimedia/platform/qplatformmediacapture.cpp
index b041f69db..826228764 100644
--- a/src/multimedia/platform/qplatformmediacapture.cpp
+++ b/src/multimedia/platform/qplatformmediacapture.cpp
@@ -1,52 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qtmultimediaglobal_p.h>
#include "qplatformmediacapture_p.h"
#include "qaudiodevice.h"
#include "qaudioinput.h"
+#include "qplatformcamera_p.h"
+#include "qplatformsurfacecapture_p.h"
QT_BEGIN_NAMESPACE
-QPlatformMediaCaptureSession::~QPlatformMediaCaptureSession()
+QPlatformMediaCaptureSession::~QPlatformMediaCaptureSession() = default;
+
+std::vector<QPlatformVideoSource *> QPlatformMediaCaptureSession::activeVideoSources()
{
+ std::vector<QPlatformVideoSource *> result;
+
+ auto checkSource = [&result](QPlatformVideoSource *source) {
+ if (source && source->isActive())
+ result.push_back(source);
+ };
+
+ checkSource(camera());
+ checkSource(screenCapture());
+ checkSource(windowCapture());
+
+ return result;
}
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 a988f3de4..814fa160c 100644
--- a/src/multimedia/platform/qplatformmediacapture_p.h
+++ b/src/multimedia/platform/qplatformmediacapture_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMMEDIACAPTURE_H
#define QPLATFORMMEDIACAPTURE_H
@@ -56,28 +20,40 @@
QT_BEGIN_NAMESPACE
class QPlatformCamera;
class QPlatformImageCapture;
-class QPlatformMediaEncoder;
+class QPlatformMediaRecorder;
class QAudioDevice;
class QCameraDevice;
class QVideoSink;
class QPlatformAudioInput;
class QPlatformAudioOutput;
+class QMediaCaptureSession;
+class QPlatformSurfaceCapture;
+class QPlatformVideoSource;
class Q_MULTIMEDIA_EXPORT QPlatformMediaCaptureSession : public QObject
{
Q_OBJECT
public:
QPlatformMediaCaptureSession() = default;
- virtual ~QPlatformMediaCaptureSession();
+ ~QPlatformMediaCaptureSession() override;
+
+ void setCaptureSession(QMediaCaptureSession *session) { m_session = session; }
+ QMediaCaptureSession *captureSession() const { return m_session; }
virtual QPlatformCamera *camera() = 0;
virtual void setCamera(QPlatformCamera *) {}
+ virtual QPlatformSurfaceCapture *screenCapture() { return nullptr; }
+ virtual void setScreenCapture(QPlatformSurfaceCapture *) {}
+
+ virtual QPlatformSurfaceCapture *windowCapture() { return nullptr; }
+ virtual void setWindowCapture(QPlatformSurfaceCapture *) { }
+
virtual QPlatformImageCapture *imageCapture() = 0;
virtual void setImageCapture(QPlatformImageCapture *) {}
- virtual QPlatformMediaEncoder *mediaEncoder() = 0;
- virtual void setMediaEncoder(QPlatformMediaEncoder *) {}
+ virtual QPlatformMediaRecorder *mediaRecorder() = 0;
+ virtual void setMediaRecorder(QPlatformMediaRecorder *) {}
virtual void setAudioInput(QPlatformAudioInput *input) = 0;
@@ -85,10 +61,18 @@ public:
virtual void setAudioOutput(QPlatformAudioOutput *) {}
+ // TBD: implement ordering of the sources basing on the order of adding
+ std::vector<QPlatformVideoSource *> activeVideoSources();
+
Q_SIGNALS:
void cameraChanged();
+ void screenCaptureChanged();
+ void windowCaptureChanged();
void imageCaptureChanged();
void encoderChanged();
+
+private:
+ QMediaCaptureSession *m_session = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediadevices.cpp b/src/multimedia/platform/qplatformmediadevices.cpp
index 4ac1ec14c..a6029228d 100644
--- a/src/multimedia/platform/qplatformmediadevices.cpp
+++ b/src/multimedia/platform/qplatformmediadevices.cpp
@@ -1,125 +1,114 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformmediadevices_p.h"
-#include "qmediadevices.h"
-#include "qaudiodevice.h"
+#include "qplatformmediaintegration_p.h"
#include "qcameradevice.h"
#include "qaudiosystem_p.h"
+#include "qaudiodevice.h"
+#include "qplatformvideodevices_p.h"
+
+#if defined(Q_OS_ANDROID)
+#include <qandroidmediadevices_p.h>
+#elif defined(Q_OS_DARWIN)
+#include <qdarwinmediadevices_p.h>
+#elif defined(Q_OS_WINDOWS) && QT_CONFIG(wmf)
+#include <qwindowsmediadevices_p.h>
+#elif QT_CONFIG(alsa)
+#include <qalsamediadevices_p.h>
+#elif QT_CONFIG(pulseaudio)
+#include <qpulseaudiomediadevices_p.h>
+#elif defined(Q_OS_QNX)
+#include <qqnxmediadevices_p.h>
+#elif defined(Q_OS_WASM)
+#include <private/qwasmmediadevices_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
+std::unique_ptr<QPlatformMediaDevices> QPlatformMediaDevices::create()
+{
+#ifdef Q_OS_DARWIN
+ return std::make_unique<QDarwinMediaDevices>();
+#elif defined(Q_OS_WINDOWS) && QT_CONFIG(wmf)
+ return std::make_unique<QWindowsMediaDevices>();
+#elif defined(Q_OS_ANDROID)
+ return std::make_unique<QAndroidMediaDevices>();
+#elif QT_CONFIG(alsa)
+ return std::make_unique<QAlsaMediaDevices>();
+#elif QT_CONFIG(pulseaudio)
+ return std::make_unique<QPulseAudioMediaDevices>();
+#elif defined(Q_OS_QNX)
+ return std::make_unique<QQnxMediaDevices>();
+#elif defined(Q_OS_WASM)
+ return std::make_unique<QWasmMediaDevices>();
+#else
+ return std::make_unique<QPlatformMediaDevices>();
+#endif
+}
+
QPlatformMediaDevices::QPlatformMediaDevices() = default;
+void QPlatformMediaDevices::initVideoDevicesConnection()
+{
+ // Make sure we are notified if video inputs changed
+ if (const auto videoDevices = QPlatformMediaIntegration::instance()->videoDevices())
+ connect(videoDevices, &QPlatformVideoDevices::videoInputsChanged, this,
+ &QPlatformMediaDevices::videoInputsChanged, Qt::UniqueConnection);
+}
+
QPlatformMediaDevices::~QPlatformMediaDevices() = default;
-QAudioDevice QPlatformMediaDevices::audioInput(const QByteArray &id) const
+QList<QAudioDevice> QPlatformMediaDevices::audioInputs() const
{
- const auto inputs = audioInputs();
- for (auto i : inputs) {
- if (i.id() == id)
- return i;
- }
return {};
}
-QAudioDevice QPlatformMediaDevices::audioOutput(const QByteArray &id) const
+QList<QAudioDevice> QPlatformMediaDevices::audioOutputs() const
{
- const auto outputs = audioOutputs();
- for (auto o : outputs) {
- if (o.id() == id)
- return o;
- }
return {};
}
-QCameraDevice QPlatformMediaDevices::videoInput(const QByteArray &id) const
+QPlatformAudioSource *QPlatformMediaDevices::createAudioSource(const QAudioDevice &, QObject *)
+{
+ return nullptr;
+}
+QPlatformAudioSink *QPlatformMediaDevices::createAudioSink(const QAudioDevice &, QObject *)
{
- const auto inputs = videoInputs();
- for (auto i : inputs) {
- if (i.id() == id)
- return i;
- }
- return QCameraDevice();
+ return nullptr;
}
-QPlatformAudioSource* QPlatformMediaDevices::audioInputDevice(const QAudioFormat &format, const QAudioDevice &deviceInfo)
+QPlatformAudioSource *QPlatformMediaDevices::audioInputDevice(const QAudioFormat &format,
+ const QAudioDevice &deviceInfo,
+ QObject *parent)
{
QAudioDevice info = deviceInfo;
if (info.isNull())
info = audioInputs().value(0);
- QPlatformAudioSource* p = createAudioSource(info);
+ QPlatformAudioSource* p = !info.isNull() ? createAudioSource(info, parent) : nullptr;
if (p)
p->setFormat(format);
return p;
}
-QPlatformAudioSink* QPlatformMediaDevices::audioOutputDevice(const QAudioFormat &format, const QAudioDevice &deviceInfo)
+QPlatformAudioSink *QPlatformMediaDevices::audioOutputDevice(const QAudioFormat &format,
+ const QAudioDevice &deviceInfo,
+ QObject *parent)
{
QAudioDevice info = deviceInfo;
if (info.isNull())
info = audioOutputs().value(0);
- QPlatformAudioSink* p = createAudioSink(info);
+ QPlatformAudioSink* p = !info.isNull() ? createAudioSink(info, parent) : nullptr;
if (p)
p->setFormat(format);
return p;
}
-void QPlatformMediaDevices::audioInputsChanged() const
-{
- for (auto m : m_devices)
- emit m->audioInputsChanged();
-}
-
-void QPlatformMediaDevices::audioOutputsChanged() const
-{
- for (auto m : m_devices)
- emit m->audioOutputsChanged();
-}
-
-void QPlatformMediaDevices::videoInputsChanged() const
-{
- for (auto m : m_devices)
- emit m->videoInputsChanged();
-}
-
+void QPlatformMediaDevices::prepareAudio() { }
QT_END_NAMESPACE
+
+#include "moc_qplatformmediadevices_p.cpp"
diff --git a/src/multimedia/platform/qplatformmediadevices_p.h b/src/multimedia/platform/qplatformmediadevices_p.h
index 62b7229ab..0de41a973 100644
--- a/src/multimedia/platform/qplatformmediadevices_p.h
+++ b/src/multimedia/platform/qplatformmediadevices_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMMEDIADEVICES_H
#define QPLATFORMMEDIADEVICES_H
@@ -53,51 +17,44 @@
#include <private/qtmultimediaglobal_p.h>
#include <qlist.h>
+#include <qobject.h>
+#include <memory>
QT_BEGIN_NAMESPACE
-class QMediaDevices;
class QAudioDevice;
-class QCameraDevice;
class QPlatformAudioSource;
class QPlatformAudioSink;
class QAudioFormat;
-class Q_MULTIMEDIA_EXPORT QPlatformMediaDevices
+class Q_MULTIMEDIA_EXPORT QPlatformMediaDevices : public QObject
{
+ Q_OBJECT
public:
QPlatformMediaDevices();
- virtual ~QPlatformMediaDevices();
-
- virtual QList<QAudioDevice> audioInputs() const = 0;
- virtual QList<QAudioDevice> audioOutputs() const = 0;
- virtual QList<QCameraDevice> videoInputs() const = 0;
- virtual QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) = 0;
- virtual QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) = 0;
-
- QAudioDevice audioInput(const QByteArray &id) const;
- QAudioDevice audioOutput(const QByteArray &id) const;
- QCameraDevice videoInput(const QByteArray &id) const;
-
- QPlatformAudioSource *audioInputDevice(const QAudioFormat &format, const QAudioDevice &deviceInfo);
- QPlatformAudioSink *audioOutputDevice(const QAudioFormat &format, const QAudioDevice &deviceInfo);
-
- void addDevices(QMediaDevices *m)
- {
- m_devices.append(m);
- }
- void removeDevices(QMediaDevices *m)
- {
- m_devices.removeAll(m);
- }
-
-protected:
- void audioInputsChanged() const;
- void audioOutputsChanged() const;
- void videoInputsChanged() const;
-
-private:
- QList<QMediaDevices *> m_devices;
+ ~QPlatformMediaDevices() override;
+
+ static std::unique_ptr<QPlatformMediaDevices> create();
+
+ virtual QList<QAudioDevice> audioInputs() const;
+ virtual QList<QAudioDevice> audioOutputs() const;
+
+ virtual QPlatformAudioSource *createAudioSource(const QAudioDevice &, QObject *parent);
+ virtual QPlatformAudioSink *createAudioSink(const QAudioDevice &, QObject *parent);
+
+ QPlatformAudioSource *audioInputDevice(const QAudioFormat &format,
+ const QAudioDevice &deviceInfo, QObject *parent);
+ QPlatformAudioSink *audioOutputDevice(const QAudioFormat &format,
+ const QAudioDevice &deviceInfo, QObject *parent);
+
+ virtual void prepareAudio();
+
+ void initVideoDevicesConnection();
+
+Q_SIGNALS:
+ void audioInputsChanged();
+ void audioOutputsChanged();
+ void videoInputsChanged();
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaencoder.cpp b/src/multimedia/platform/qplatformmediaencoder.cpp
deleted file mode 100644
index b803740c3..000000000
--- a/src/multimedia/platform/qplatformmediaencoder.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qplatformmediaencoder_p.h"
-#include <QObject>
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QPlatformMediaEncoder
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QPlatformMediaEncoder class provides access to the recording
- functionality.
-
- This control provides a means to set the \l {outputLocation()}{output location},
- and record(), pause(), resume(), and stop() recording. It also
- provides feedback on the \l {duration()}{duration} of the recording.
-
- \sa QMediaRecorder
-
-*/
-
-/*!
- Constructs a media recorder control with the given \a parent.
-*/
-
-QPlatformMediaEncoder::QPlatformMediaEncoder(QMediaRecorder *parent)
- : q(parent)
-{
-}
-
-/*!
- \fn QUrl QPlatformMediaEncoder::outputLocation() const
-
- Returns the current output location being used.
-*/
-
-/*!
- \fn bool QPlatformMediaEncoder::setOutputLocation(const QUrl &location)
-
- Sets the output \a location and returns if this operation is successful.
- If file at the output location already exists, it should be overwritten.
-
- The \a location can be relative or empty;
- in this case the service should use the system specific place and file naming scheme.
-
- After recording has started, the backend should report the actual file location
- with actualLocationChanged() signal.
-*/
-
-/*!
- \fn QMediaRecorder::RecorderState QPlatformMediaEncoder::state() const
-
- Return the current recording state.
-*/
-
-/*!
- \fn qint64 QPlatformMediaEncoder::duration() const
-
- Return the current duration in milliseconds.
-*/
-
-/*!
- \fn void QPlatformMediaEncoder::record(QMediaEncoderSettings &settings)
-
- Start media recording in accordance with \a{settings}.
-*/
-
-/*!
- \fn void QPlatformMediaEncoder::pause()
-
- Pause media recording. Not all platforms supports this operation
-*/
-void QPlatformMediaEncoder::pause() {
- error(QMediaRecorder::FormatError, QMediaRecorder::tr("Pause not supported"));
-}
-
-/*!
- \fn void QPlatformMediaEncoder::resume()
-
- Resume media recording. Not all platforms supports this operation
-*/
-void QPlatformMediaEncoder::resume() {
- error(QMediaRecorder::FormatError, QMediaRecorder::tr("Resume not supported"));
-}
-
-/*!
- \fn void QPlatformMediaEncoder::stop()
-
- Stop media recording
-*/
-
-/*!
- \fn void QPlatformMediaEncoder::stateChanged(QMediaRecorder::RecorderState state)
-
- Signals that the \a state of a media recorder has changed.
-*/
-void QPlatformMediaEncoder::stateChanged(QMediaRecorder::RecorderState state)
-{
- if (m_state == state)
- return;
- m_state = state;
- emit q->recorderStateChanged(state);
-}
-
-/*!
- \fn void QPlatformMediaEncoder::durationChanged(qint64 duration)
-
- Signals that the \a duration of the recorded media has changed.
-
- This only emitted when there is a discontinuous change in the duration such as being reset to 0.
-*/
-void QPlatformMediaEncoder::durationChanged(qint64 duration)
-{
- emit q->durationChanged(duration);
-}
-
-/*!
- \fn void QPlatformMediaEncoder::actualLocationChanged(const QUrl &location)
-
- Signals that the actual media \a location has changed.
- This signal should be emitted at start of recording.
-*/
-void QPlatformMediaEncoder::actualLocationChanged(const QUrl &location)
-{
- if (m_actualLocation == location)
- return;
- m_actualLocation = location;
- emit q->actualLocationChanged(location);
-}
-
-/*!
- \fn void QPlatformMediaEncoder::error(QMediaRecorder::Error error, const QString &errorString)
-
- Signals that an \a error has occurred. The \a errorString describes the error.
-*/
-void QPlatformMediaEncoder::error(QMediaRecorder::Error error, const QString &errorString)
-{
- if (error == m_error && errorString == m_errorString)
- return;
- m_error = error;
- m_errorString = errorString;
- if (error != QMediaRecorder::NoError)
- emit q->errorOccurred(error, errorString);
- emit q->errorChanged();
-}
-
-void QPlatformMediaEncoder::metaDataChanged()
-{
- emit q->metaDataChanged();
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaformatinfo.cpp b/src/multimedia/platform/qplatformmediaformatinfo.cpp
index d4bfecafc..e69b32ed3 100644
--- a/src/multimedia/platform/qplatformmediaformatinfo.cpp
+++ b/src/multimedia/platform/qplatformmediaformatinfo.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformmediaformatinfo_p.h"
#include <qset.h>
diff --git a/src/multimedia/platform/qplatformmediaformatinfo_p.h b/src/multimedia/platform/qplatformmediaformatinfo_p.h
index 8842304ca..4229a3c4c 100644
--- a/src/multimedia/platform/qplatformmediaformatinfo_p.h
+++ b/src/multimedia/platform/qplatformmediaformatinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMMEDIAFORMATINFO_H
#define QPLATFORMMEDIAFORMATINFO_H
diff --git a/src/multimedia/platform/qplatformmediaintegration.cpp b/src/multimedia/platform/qplatformmediaintegration.cpp
index c3b4f1444..c8f662963 100644
--- a/src/multimedia/platform/qplatformmediaintegration.cpp
+++ b/src/multimedia/platform/qplatformmediaintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qtmultimediaglobal_p.h>
#include "qplatformmediaintegration_p.h"
@@ -43,88 +7,249 @@
#include <qmutex.h>
#include <qplatformaudioinput_p.h>
#include <qplatformaudiooutput_p.h>
+#include <qplatformaudioresampler_p.h>
+#include <qplatformvideodevices_p.h>
+#include <qmediadevices.h>
+#include <qcameradevice.h>
+#include <qloggingcategory.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qapplicationstatic.h>
-#if QT_CONFIG(gstreamer)
-#include <private/qgstreamerintegration_p.h>
-using PlatformIntegration = QGstreamerIntegration;
-#elif QT_CONFIG(pulseaudio)
-#include <private/qpulseaudiointegration_p.h>
-using PlatformIntegration = QPulseAudioIntegration;
-#elif QT_CONFIG(alsa)
-#include <private/qalsaintegration_p.h>
-using PlatformIntegration = QAlsaIntegration;
-#elif QT_CONFIG(avfoundation)
-#include <private/qdarwinintegration_p.h>
-using PlatformIntegration = QDarwinIntegration;
-#elif QT_CONFIG(wmf)
-#include <private/qwindowsintegration_p.h>
-using PlatformIntegration = QWindowsMediaIntegration;
-#elif defined(Q_OS_ANDROID)
-#include <private/qandroidintegration_p.h>
-using PlatformIntegration = QAndroidIntegration;
-#elif defined(Q_OS_WASM)
-#include <private/qwasmmediaintegration_p.h>
-using PlatformIntegration = QWasmMediaIntegration;
-#else
-class QDummyIntegration : public QPlatformMediaIntegration
+#include "qplatformcapturablewindows_p.h"
+#include "qplatformmediadevices_p.h"
+#include <QtCore/private/qfactoryloader_p.h>
+#include <QtCore/private/qcoreapplication_p.h>
+#include <private/qplatformmediaformatinfo_p.h>
+#include "qplatformmediaplugin_p.h"
+
+namespace {
+
+class QFallbackIntegration : public QPlatformMediaIntegration
{
public:
- QDummyIntegration() { qFatal("QtMultimedia is not currently supported on this platform or compiler."); }
- QPlatformMediaDevices *devices() override { return nullptr; }
- QPlatformMediaFormatInfo *formatInfo() override { return nullptr; }
+ QFallbackIntegration() : QPlatformMediaIntegration(QLatin1String("fallback"))
+ {
+ qWarning("No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available.");
+ }
};
-using PlatformIntegration = QDummyIntegration;
+
+static Q_LOGGING_CATEGORY(qLcMediaPlugin, "qt.multimedia.plugin")
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QPlatformMediaPlugin_iid,
+ QLatin1String("/multimedia")))
+
+static const auto FFmpegBackend = QStringLiteral("ffmpeg");
+
+static QString defaultBackend(const QStringList &backends)
+{
+#ifdef QT_DEFAULT_MEDIA_BACKEND
+ auto backend = QString::fromUtf8(QT_DEFAULT_MEDIA_BACKEND);
+ if (backends.contains(backend))
+ return backend;
#endif
-QT_BEGIN_NAMESPACE
+#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
+ // Return ffmpeg backend by default.
+ // Platform backends for the OS list are optionally available but have limited support.
+ if (backends.contains(FFmpegBackend))
+ return FFmpegBackend;
+#else
+ // Return platform backend (non-ffmpeg) by default.
+ if (backends.size() > 1 && backends[0] == FFmpegBackend)
+ return backends[1];
+#endif
-namespace {
-struct Holder {
- ~Holder()
+ return backends[0];
+}
+
+struct InstanceHolder
+{
+ InstanceHolder()
+ {
+ if (!QCoreApplication::instance())
+ qCCritical(qLcMediaPlugin()) << "Qt Multimedia requires a QCoreApplication instance";
+
+ const QStringList backends = QPlatformMediaIntegration::availableBackends();
+ QString backend = QString::fromUtf8(qgetenv("QT_MEDIA_BACKEND"));
+ if (backend.isEmpty() && !backends.isEmpty())
+ backend = defaultBackend(backends);
+
+ qCDebug(qLcMediaPlugin) << "Loading media backend" << backend;
+ instance.reset(
+ qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(), backend));
+
+ if (!instance) {
+ // No backends found. Use fallback to support basic functionality
+ instance = std::make_unique<QFallbackIntegration>();
+ }
+ }
+
+ ~InstanceHolder()
+ {
+ instance.reset();
+ qCDebug(qLcMediaPlugin) << "Released media backend";
+ }
+
+ // Play nice with QtGlobalStatic::ApplicationHolder
+ using QAS_Type = InstanceHolder;
+ static void innerFunction(void *pointer)
+ {
+ new (pointer) InstanceHolder();
+ }
+
+ std::unique_ptr<QPlatformMediaIntegration> instance;
+};
+
+// Specialized implementation of Q_APPLICATION_STATIC which behaves as
+// an application static if a Qt application is present, otherwise as a Q_GLOBAL_STATIC.
+// By doing this, and we have a Qt application, all system resources allocated by the
+// backend is released when application lifetime ends. This is important on Windows,
+// where Windows Media Foundation instances should not be released during static destruction.
+//
+// If we don't have a Qt application available when instantiating the instance holder,
+// it will be created once, and not destroyed until static destruction. This can cause
+// abrupt termination of Windows applications during static destruction. This is not a
+// supported use case, but we keep this as a fallback to keep old applications functional.
+// See also QTBUG-120198
+struct ApplicationHolder : QtGlobalStatic::ApplicationHolder<InstanceHolder>
+{
+ // Replace QtGlobalStatic::ApplicationHolder::pointer to prevent crash if
+ // no application is present
+ static InstanceHolder* pointer()
{
+ if (guard.loadAcquire() == QtGlobalStatic::Initialized)
+ return realPointer();
+
QMutexLocker locker(&mutex);
- delete nativeInstance;
- nativeInstance = nullptr;
- instance = nullptr;
+ if (guard.loadRelaxed() == QtGlobalStatic::Uninitialized) {
+ InstanceHolder::innerFunction(&storage);
+
+ if (const QCoreApplication *app = QCoreApplication::instance())
+ QObject::connect(app, &QObject::destroyed, app, reset, Qt::DirectConnection);
+
+ guard.storeRelease(QtGlobalStatic::Initialized);
+ }
+ return realPointer();
}
- QBasicMutex mutex;
- QPlatformMediaIntegration *instance = nullptr;
- QAtomicPointer<QPlatformMediaIntegration> nativeInstance = nullptr;
-} holder;
+};
-}
+} // namespace
+
+QT_BEGIN_NAMESPACE
QPlatformMediaIntegration *QPlatformMediaIntegration::instance()
{
- if (!holder.nativeInstance.loadRelaxed()) {
- QMutexLocker locker(&holder.mutex);
- if (!holder.nativeInstance.loadAcquire())
- holder.nativeInstance.storeRelease(new PlatformIntegration);
- }
- if (!holder.instance)
- holder.instance = holder.nativeInstance.loadRelaxed();
- return holder.instance;
+ static QGlobalStatic<ApplicationHolder> s_instanceHolder;
+ return s_instanceHolder->instance.get();
}
-/*
- This API is there to be able to test with a mock backend.
-*/
-void QPlatformMediaIntegration::setIntegration(QPlatformMediaIntegration *integration)
+QList<QCameraDevice> QPlatformMediaIntegration::videoInputs()
{
- holder.instance = integration;
+ auto devices = videoDevices();
+ return devices ? devices->videoDevices() : QList<QCameraDevice>{};
}
-QPlatformAudioInput *QPlatformMediaIntegration::createAudioInput(QAudioInput *q)
+QMaybe<std::unique_ptr<QPlatformAudioResampler>>
+QPlatformMediaIntegration::createAudioResampler(const QAudioFormat &, const QAudioFormat &)
+{
+ return notAvailable;
+}
+
+QMaybe<QPlatformAudioInput *> QPlatformMediaIntegration::createAudioInput(QAudioInput *q)
{
return new QPlatformAudioInput(q);
}
-QPlatformAudioOutput *QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q)
+QMaybe<QPlatformAudioOutput *> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q)
{
return new QPlatformAudioOutput(q);
}
-QPlatformMediaIntegration::~QPlatformMediaIntegration()
-= default;
+QList<QCapturableWindow> QPlatformMediaIntegration::capturableWindowsList()
+{
+ const auto capturableWindows = this->capturableWindows();
+ return capturableWindows ? capturableWindows->windows() : QList<QCapturableWindow>{};
+}
+
+bool QPlatformMediaIntegration::isCapturableWindowValid(const QCapturableWindowPrivate &window)
+{
+ const auto capturableWindows = this->capturableWindows();
+ return capturableWindows && capturableWindows->isWindowValid(window);
+}
+
+const QPlatformMediaFormatInfo *QPlatformMediaIntegration::formatInfo()
+{
+ std::call_once(m_formatInfoOnceFlg, [this]() {
+ m_formatInfo.reset(createFormatInfo());
+ Q_ASSERT(m_formatInfo);
+ });
+ return m_formatInfo.get();
+}
+
+QPlatformMediaFormatInfo *QPlatformMediaIntegration::createFormatInfo()
+{
+ return new QPlatformMediaFormatInfo;
+}
+
+std::unique_ptr<QPlatformMediaDevices> QPlatformMediaIntegration::createMediaDevices()
+{
+ return QPlatformMediaDevices::create();
+}
+
+// clang-format off
+QPlatformVideoDevices *QPlatformMediaIntegration::videoDevices()
+{
+ std::call_once(m_videoDevicesOnceFlag,
+ [this]() {
+ m_videoDevices.reset(createVideoDevices());
+ });
+ return m_videoDevices.get();
+}
+
+QPlatformCapturableWindows *QPlatformMediaIntegration::capturableWindows()
+{
+ std::call_once(m_capturableWindowsOnceFlag,
+ [this]() {
+ m_capturableWindows.reset(createCapturableWindows());
+ });
+ return m_capturableWindows.get();
+}
+
+QPlatformMediaDevices *QPlatformMediaIntegration::mediaDevices()
+{
+ std::call_once(m_mediaDevicesOnceFlag, [this] {
+ m_mediaDevices = createMediaDevices();
+ });
+ return m_mediaDevices.get();
+}
+
+// clang-format on
+
+QStringList QPlatformMediaIntegration::availableBackends()
+{
+ QStringList list;
+
+ if (QFactoryLoader *fl = loader()) {
+ const auto keyMap = fl->keyMap();
+ for (auto it = keyMap.constBegin(); it != keyMap.constEnd(); ++it)
+ if (!list.contains(it.value()))
+ list << it.value();
+ }
+
+ qCDebug(qLcMediaPlugin) << "Available backends" << list;
+ return list;
+}
+
+QLatin1String QPlatformMediaIntegration::name()
+{
+ return m_backendName;
+}
+
+QPlatformMediaIntegration::QPlatformMediaIntegration(QLatin1String name) : m_backendName(name) { }
+
+QPlatformMediaIntegration::~QPlatformMediaIntegration() = default;
QT_END_NAMESPACE
+
+#include "moc_qplatformmediaintegration_p.cpp"
diff --git a/src/multimedia/platform/qplatformmediaintegration_p.h b/src/multimedia/platform/qplatformmediaintegration_p.h
index 67938d910..19fa40baf 100644
--- a/src/multimedia/platform/qplatformmediaintegration_p.h
+++ b/src/multimedia/platform/qplatformmediaintegration_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMMEDIAINTEGRATION_H
#define QPLATFORMMEDIAINTEGRATION_H
@@ -51,13 +15,21 @@
//
#include <private/qtmultimediaglobal_p.h>
+#include <private/qmultimediautils_p.h>
+#include <qcapturablewindow.h>
#include <qmediarecorder.h>
+#include <qstring.h>
+
+#include <memory>
+#include <mutex>
QT_BEGIN_NAMESPACE
class QMediaPlayer;
class QAudioDecoder;
class QCamera;
+class QScreenCapture;
+class QWindowCapture;
class QMediaRecorder;
class QImageCapture;
class QMediaDevices;
@@ -65,8 +37,10 @@ class QPlatformMediaDevices;
class QPlatformMediaCaptureSession;
class QPlatformMediaPlayer;
class QPlatformAudioDecoder;
+class QPlatformAudioResampler;
class QPlatformCamera;
-class QPlatformMediaEncoder;
+class QPlatformSurfaceCapture;
+class QPlatformMediaRecorder;
class QPlatformImageCapture;
class QPlatformMediaFormatInfo;
class QObject;
@@ -76,30 +50,75 @@ class QAudioInput;
class QAudioOutput;
class QPlatformAudioInput;
class QPlatformAudioOutput;
+class QPlatformVideoDevices;
+class QCapturableWindow;
+class QPlatformCapturableWindows;
-class Q_MULTIMEDIA_EXPORT QPlatformMediaIntegration
+class Q_MULTIMEDIA_EXPORT QPlatformMediaIntegration : public QObject
{
+ Q_OBJECT
+ inline static const QString notAvailable = QStringLiteral("Not available");
public:
static QPlatformMediaIntegration *instance();
- // API to be able to test with a mock backend
- static void setIntegration(QPlatformMediaIntegration *);
-
+ explicit QPlatformMediaIntegration(QLatin1String);
virtual ~QPlatformMediaIntegration();
- virtual QPlatformMediaDevices *devices() = 0;
- virtual QPlatformMediaFormatInfo *formatInfo() = 0;
+ const QPlatformMediaFormatInfo *formatInfo();
+
+ virtual QList<QCameraDevice> videoInputs();
+ virtual QMaybe<QPlatformCamera *> createCamera(QCamera *) { return notAvailable; }
+ virtual QPlatformSurfaceCapture *createScreenCapture(QScreenCapture *) { return nullptr; }
+ virtual QPlatformSurfaceCapture *createWindowCapture(QWindowCapture *) { return nullptr; }
+
+ virtual QMaybe<QPlatformAudioDecoder *> createAudioDecoder(QAudioDecoder *) { return notAvailable; }
+ virtual QMaybe<std::unique_ptr<QPlatformAudioResampler>>
+ createAudioResampler(const QAudioFormat & /*inputFormat*/,
+ const QAudioFormat & /*outputFormat*/);
+ virtual QMaybe<QPlatformMediaCaptureSession *> createCaptureSession() { return notAvailable; }
+ virtual QMaybe<QPlatformMediaPlayer *> createPlayer(QMediaPlayer *) { return notAvailable; }
+ virtual QMaybe<QPlatformMediaRecorder *> createRecorder(QMediaRecorder *) { return notAvailable; }
+ virtual QMaybe<QPlatformImageCapture *> createImageCapture(QImageCapture *) { return notAvailable; }
+
+ virtual QMaybe<QPlatformAudioInput *> createAudioInput(QAudioInput *);
+ virtual QMaybe<QPlatformAudioOutput *> createAudioOutput(QAudioOutput *);
+
+ virtual QMaybe<QPlatformVideoSink *> createVideoSink(QVideoSink *) { return notAvailable; }
+
+ QList<QCapturableWindow> capturableWindowsList();
+ bool isCapturableWindowValid(const QCapturableWindowPrivate &);
+
+ QPlatformVideoDevices *videoDevices();
+
+ QPlatformCapturableWindows *capturableWindows();
+
+ QPlatformMediaDevices *mediaDevices();
+
+ static QStringList availableBackends();
+ QLatin1String name(); // for unit tests
+
+protected:
+ virtual QPlatformMediaFormatInfo *createFormatInfo();
+
+ virtual QPlatformVideoDevices *createVideoDevices() { return nullptr; }
+
+ virtual QPlatformCapturableWindows *createCapturableWindows() { return nullptr; }
+
+ virtual std::unique_ptr<QPlatformMediaDevices> createMediaDevices();
+
+private:
+ std::unique_ptr<QPlatformVideoDevices> m_videoDevices;
+ std::once_flag m_videoDevicesOnceFlag;
+
+ std::unique_ptr<QPlatformCapturableWindows> m_capturableWindows;
+ std::once_flag m_capturableWindowsOnceFlag;
- virtual QPlatformAudioDecoder *createAudioDecoder(QAudioDecoder *) { return nullptr; }
- virtual QPlatformMediaCaptureSession *createCaptureSession() { return nullptr; }
- virtual QPlatformMediaPlayer *createPlayer(QMediaPlayer *) { return nullptr; }
- virtual QPlatformCamera *createCamera(QCamera *) { return nullptr; }
- virtual QPlatformMediaEncoder *createEncoder(QMediaRecorder *) { return nullptr; }
- virtual QPlatformImageCapture *createImageCapture(QImageCapture *) { return nullptr; }
+ mutable std::unique_ptr<QPlatformMediaFormatInfo> m_formatInfo;
+ mutable std::once_flag m_formatInfoOnceFlg;
- virtual QPlatformAudioInput *createAudioInput(QAudioInput *);
- virtual QPlatformAudioOutput *createAudioOutput(QAudioOutput *);
+ std::unique_ptr<QPlatformMediaDevices> m_mediaDevices;
+ std::once_flag m_mediaDevicesOnceFlag;
- virtual QPlatformVideoSink *createVideoSink(QVideoSink *) { return nullptr; }
+ const QLatin1String m_backendName;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaplayer.cpp b/src/multimedia/platform/qplatformmediaplayer.cpp
index 21e25ec9b..ea22f94df 100644
--- a/src/multimedia/platform/qplatformmediaplayer.cpp
+++ b/src/multimedia/platform/qplatformmediaplayer.cpp
@@ -1,92 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qplatformmediaplayer_p.h"
#include <private/qmediaplayer_p.h>
#include "qmediaplayer.h"
+#include "qplatformmediadevices_p.h"
+#include "qplatformmediaintegration_p.h"
QT_BEGIN_NAMESPACE
-
-/*!
- \class QPlatformMediaPlayer
- \internal
-
- \brief The QPlatformMediaPlayer class provides access to the media playing
- functionality.
-
- This control provides a means to set the \l {setMedia()}{media} to play,
- \l {play()}{start}, \l {pause()} {pause} and \l {stop()}{stop} playback,
- \l {setPosition()}{seek}, and control the \l {setVolume()}{volume}.
- It also provides feedback on the \l {duration()}{duration} of the media,
- the current \l {position()}{position}, and \l {bufferProgress()}{buffering}
- progress.
-
- The functionality provided by this control is exposed to application
- code through the QMediaPlayer class.
-
- \sa QMediaPlayer
-*/
+QPlatformMediaPlayer::QPlatformMediaPlayer(QMediaPlayer *parent) : player(parent)
+{
+ QPlatformMediaIntegration::instance()->mediaDevices()->prepareAudio();
+}
QPlatformMediaPlayer::~QPlatformMediaPlayer()
{
}
-/*! \fn QPlatformMediaPlayer::QPlatformMediaPlayer(QMediaPlayer *parent)
-
- Constructs a new media player control with the given \a parent.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::state() const
-
- Returns the state of a player control.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::stateChanged(QMediaPlayer::State newState)
-
- Signals that the state of a player control has changed to \a newState.
-
- \sa state()
-*/
-
void QPlatformMediaPlayer::stateChanged(QMediaPlayer::PlaybackState newState)
{
if (newState == m_state)
@@ -95,20 +26,6 @@ void QPlatformMediaPlayer::stateChanged(QMediaPlayer::PlaybackState newState)
player->d_func()->setState(newState);
}
-/*!
- \fn QPlatformMediaPlayer::mediaStatus() const
-
- Returns the status of the current media.
-*/
-
-
-/*!
- \fn QPlatformMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
-
- Signals that the \a status of the current media has changed.
-
- \sa mediaStatus()
-*/
void QPlatformMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
{
if (m_status == status)
@@ -119,254 +36,19 @@ void QPlatformMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
void QPlatformMediaPlayer::error(int error, const QString &errorString)
{
- player->d_func()->setError(error, errorString);
+ player->d_func()->setError(QMediaPlayer::Error(error), errorString);
}
-/*!
- \fn QPlatformMediaPlayer::duration() const
-
- Returns the duration of the current media in milliseconds.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::durationChanged(qint64 duration)
-
- Signals that the \a duration of the current media has changed.
-
- \sa duration()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::position() const
-
- Returns the current playback position in milliseconds.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::setPosition(qint64 position)
-
- Sets the playback \a position of the current media. This will initiate a seek and it may take
- some time for playback to reach the position set.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::positionChanged(qint64 position)
-
- Signals the playback \a position has changed.
-
- This is only emitted in when there has been a discontinous change in the playback postion, such
- as a seek or the position being reset.
-
- \sa position()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::volume() const
-
- Returns the audio volume of a player control.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::setVolume(int volume)
-
- Sets the audio \a volume of a player control.
-
- The volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume).
-*/
-
-/*!
- \fn QPlatformMediaPlayer::volumeChanged(int volume)
-
- Signals the audio \a volume of a player control has changed.
-
- \sa volume()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::isMuted() const
-
- Returns the mute state of a player control.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::setMuted(bool mute)
-
- Sets the \a mute state of a player control.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::mutedChanged(bool mute)
-
- Signals a change in the \a mute status of a player control.
-
- \sa isMuted()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::bufferProgress() const
-
- Returns the buffering progress of the current media. Progress is measured as a number between
- 0 and 1.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::bufferProgressChanged(float filled)
-
- Signal the amount of the local buffer filled as a relative number between 0 and 1.
-
- \sa bufferProgress()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::isAudioAvailable() const
-
- Identifies if there is audio output available for the current media.
-
- Returns true if audio output is available and false otherwise.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::audioAvailableChanged(bool audioAvailable)
-
- Signals that there has been a change in the availability of audio output \a audioAvailable.
-
- \sa isAudioAvailable()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::isVideoAvailable() const
-
- Identifies if there is video output available for the current media.
-
- Returns true if video output is available and false otherwise.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::videoAvailableChanged(bool videoAvailable)
-
- Signal that the availability of visual content has changed to \a videoAvailable.
-
- \sa isVideoAvailable()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::isSeekable() const
-
- Identifies if the current media is seekable.
-
- Returns true if it possible to seek within the current media, and false otherwise.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::seekableChanged(bool seekable)
-
- Signals that the \a seekable state of a player control has changed.
-
- \sa isSeekable()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::availablePlaybackRanges() const
-
- Returns a range of times in milliseconds that can be played back.
-
- Usually for local files this is a continuous interval equal to [0..duration()]
- or an empty time range if seeking is not supported, but for network sources
- it refers to the buffered parts of the media.
-*/
-
-/*!
- \fn qreal QPlatformMediaPlayer::playbackRate() const
-
- Returns the rate of playback.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::setPlaybackRate(qreal rate)
-
- Sets the \a rate of playback.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::media() const
-
- Returns the current media source.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::mediaStream() const
-
- Returns the current media stream. This is only a valid if a stream was passed to setMedia().
-
- \sa setMedia()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::setMedia(const QUrl &media, QIODevice *stream)
-
- Sets the current \a media source. If a \a stream is supplied; data will be read from that
- instead of attempting to resolve the media source. The media source may still be used to
- supply media information such as mime type.
-
- Setting the media to a null QUrl will cause the control to discard all
- information relating to the current media source and to cease all I/O operations related
- to that media.
-
- Qt resource files are never passed as is. If the control supports
- stream playback, a \a stream is supplied, pointing to an opened
- QFile. Otherwise, the resource is copied into a temporary file and \a media contains the
- url to that file.
-
- \sa streamPlaybackSupported()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::mediaChanged(const QUrl& content)
-
- Signals that the current media \a content has changed.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::play()
-
- Starts playback of the current media.
-
- If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState}
- {playing} state.
-
- \sa state()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::pause()
-
- Pauses playback of the current media.
-
- If successful the player control will immediately enter the \l {QMediaPlayer::PausedState}
- {paused} state.
-
- \sa state(), play(), stop()
-*/
-
-/*!
- \fn QPlatformMediaPlayer::stop()
-
- Stops playback of the current media.
-
- If successful the player control will immediately enter the \l {QMediaPlayer::StoppedState}
- {stopped} state.
-*/
-
-/*!
- \fn QPlatformMediaPlayer::error(int error, const QString &errorString)
-
- Signals that an \a error has occurred. The \a errorString provides a more detailed explanation.
-*/
+void *QPlatformMediaPlayer::nativePipeline(QMediaPlayer *player)
+{
+ if (!player)
+ return nullptr;
-/*!
- \fn QPlatformMediaPlayer::playbackRateChanged(qreal rate)
+ auto playerPrivate = player->d_func();
+ if (!playerPrivate || !playerPrivate->control)
+ return nullptr;
- Signal emitted when playback rate changes to \a rate.
-*/
+ return playerPrivate->control->nativePipeline();
+}
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaplayer_p.h b/src/multimedia/platform/qplatformmediaplayer_p.h
index cc9297229..6e3590763 100644
--- a/src/multimedia/platform/qplatformmediaplayer_p.h
+++ b/src/multimedia/platform/qplatformmediaplayer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
@@ -57,6 +21,7 @@
#include <QtMultimedia/qmediametadata.h>
#include <QtCore/qpair.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -72,7 +37,7 @@ public:
virtual qint64 duration() const = 0;
- virtual qint64 position() const = 0;
+ virtual qint64 position() const { return m_position; }
virtual void setPosition(qint64 position) = 0;
virtual float bufferProgress() const = 0;
@@ -111,40 +76,62 @@ public:
virtual int activeTrack(TrackType) { return -1; }
virtual void setActiveTrack(TrackType, int /*streamNumber*/) {}
- void durationChanged(qint64 duration) { player->durationChanged(duration); }
- void positionChanged(qint64 position) { player->positionChanged(position); }
+ void durationChanged(qint64 duration) { emit player->durationChanged(duration); }
+ void positionChanged(qint64 position) {
+ if (m_position == position)
+ return;
+ m_position = position;
+ emit player->positionChanged(position);
+ }
void audioAvailableChanged(bool audioAvailable) {
if (m_audioAvailable == audioAvailable)
return;
m_audioAvailable = audioAvailable;
- player->hasAudioChanged(audioAvailable);
+ emit player->hasAudioChanged(audioAvailable);
}
void videoAvailableChanged(bool videoAvailable) {
if (m_videoAvailable == videoAvailable)
return;
m_videoAvailable = videoAvailable;
- player->hasVideoChanged(videoAvailable);
+ emit player->hasVideoChanged(videoAvailable);
}
void seekableChanged(bool seekable) {
if (m_seekable == seekable)
return;
m_seekable = seekable;
- player->seekableChanged(seekable);
+ emit player->seekableChanged(seekable);
}
- void playbackRateChanged(qreal rate) { player->playbackRateChanged(rate); }
- void bufferProgressChanged(float progress) { player->bufferProgressChanged(progress); }
- void metaDataChanged() { player->metaDataChanged(); }
- void tracksChanged() { player->tracksChanged(); }
- void activeTracksChanged() { player->activeTracksChanged(); }
+ void playbackRateChanged(qreal rate) { emit player->playbackRateChanged(rate); }
+ void bufferProgressChanged(float progress) { emit player->bufferProgressChanged(progress); }
+ void metaDataChanged() { emit player->metaDataChanged(); }
+ void tracksChanged() { emit player->tracksChanged(); }
+ void activeTracksChanged() { emit player->activeTracksChanged(); }
void stateChanged(QMediaPlayer::PlaybackState newState);
void mediaStatusChanged(QMediaPlayer::MediaStatus status);
void error(int error, const QString &errorString);
+ void resetCurrentLoop() { m_currentLoop = 0; }
+ bool doLoop() {
+ return isSeekable() && (m_loops < 0 || ++m_currentLoop < m_loops);
+ }
+ int loops() { return m_loops; }
+ virtual void setLoops(int loops)
+ {
+ if (m_loops == loops)
+ return;
+ m_loops = loops;
+ 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)
- : player(parent)
- {}
+ explicit QPlatformMediaPlayer(QMediaPlayer *parent = nullptr);
+
private:
QMediaPlayer *player = nullptr;
QMediaPlayer::MediaStatus m_status = QMediaPlayer::NoMedia;
@@ -152,6 +139,9 @@ private:
bool m_seekable = false;
bool m_videoAvailable = false;
bool m_audioAvailable = false;
+ int m_loops = 1;
+ int m_currentLoop = 0;
+ qint64 m_position = 0;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaplugin.cpp b/src/multimedia/platform/qplatformmediaplugin.cpp
new file mode 100644
index 000000000..7828fa08e
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaplugin.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2022 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 "qplatformmediaplugin_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPlatformMediaPlugin::QPlatformMediaPlugin(QObject *parent) : QObject(parent) { }
+
+QPlatformMediaPlugin::~QPlatformMediaPlugin() = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformmediaplugin_p.cpp"
diff --git a/src/multimedia/platform/qplatformmediaplugin_p.h b/src/multimedia/platform/qplatformmediaplugin_p.h
new file mode 100644
index 000000000..4c8b9e458
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaplugin_p.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 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.
+//
+
+#ifndef QPLATFORMMEDIAPLUGIN_P_H
+#define QPLATFORMMEDIAPLUGIN_P_H
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformMediaIntegration;
+
+#define QPlatformMediaPlugin_iid "org.qt-project.Qt.QPlatformMediaPlugin"
+
+class Q_MULTIMEDIA_EXPORT QPlatformMediaPlugin : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QPlatformMediaPlugin(QObject *parent = nullptr);
+ ~QPlatformMediaPlugin() override;
+
+ virtual QPlatformMediaIntegration *create(const QString &key) = 0;
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMMEDIAPLUGIN_P_H
diff --git a/src/multimedia/platform/qplatformmediarecorder.cpp b/src/multimedia/platform/qplatformmediarecorder.cpp
new file mode 100644
index 000000000..ba9ea0165
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediarecorder.cpp
@@ -0,0 +1,75 @@
+// 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 "qplatformmediarecorder_p.h"
+#include "qstandardpaths.h"
+#include "qmediastoragelocation_p.h"
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+QPlatformMediaRecorder::QPlatformMediaRecorder(QMediaRecorder *parent)
+ : q(parent)
+{
+}
+
+void QPlatformMediaRecorder::pause()
+{
+ error(QMediaRecorder::FormatError, QMediaRecorder::tr("Pause not supported"));
+}
+
+void QPlatformMediaRecorder::resume()
+{
+ error(QMediaRecorder::FormatError, QMediaRecorder::tr("Resume not supported"));
+}
+
+void QPlatformMediaRecorder::stateChanged(QMediaRecorder::RecorderState state)
+{
+ if (m_state == state)
+ return;
+ m_state = state;
+ emit q->recorderStateChanged(state);
+}
+
+void QPlatformMediaRecorder::durationChanged(qint64 duration)
+{
+ if (m_duration == duration)
+ return;
+ m_duration = duration;
+ emit q->durationChanged(duration);
+}
+
+void QPlatformMediaRecorder::actualLocationChanged(const QUrl &location)
+{
+ if (m_actualLocation == location)
+ return;
+ m_actualLocation = location;
+ emit q->actualLocationChanged(location);
+}
+
+void QPlatformMediaRecorder::error(QMediaRecorder::Error error, const QString &errorString)
+{
+ m_error.setAndNotify(error, errorString, *q);
+}
+
+void QPlatformMediaRecorder::metaDataChanged()
+{
+ emit q->metaDataChanged();
+}
+
+QString QPlatformMediaRecorder::findActualLocation(const QMediaEncoderSettings &settings) const
+{
+ const auto audioOnly = settings.videoCodec() == QMediaFormat::VideoCodec::Unspecified;
+
+ const auto primaryLocation =
+ audioOnly ? QStandardPaths::MusicLocation : QStandardPaths::MoviesLocation;
+ const QString suffix = settings.mimeType().preferredSuffix();
+ const QString location = QMediaStorageLocation::generateFileName(
+ outputLocation().toString(QUrl::PreferLocalFile), primaryLocation, suffix);
+
+ Q_ASSERT(!location.isEmpty());
+
+ return location;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaencoder_p.h b/src/multimedia/platform/qplatformmediarecorder_p.h
index 354998b5c..6e88dc187 100644
--- a/src/multimedia/platform/qplatformmediaencoder_p.h
+++ b/src/multimedia/platform/qplatformmediarecorder_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
@@ -48,16 +12,20 @@
// We mean it.
//
-#ifndef QPLATFORMMEDIAENCODER_H
-#define QPLATFORMMEDIAENCODER_H
+#ifndef QPLATFORMMEDIARECORDER_H
+#define QPLATFORMMEDIARECORDER_H
#include <QtCore/qurl.h>
#include <QtCore/qsize.h>
#include <QtCore/qmimetype.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qiodevice.h>
#include <QtMultimedia/qmediarecorder.h>
#include <QtMultimedia/qmediametadata.h>
#include <QtMultimedia/qmediaformat.h>
+#include <QtMultimedia/private/qerrorinfo_p.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -132,10 +100,10 @@ public:
{ return !operator==(other); }
};
-class Q_MULTIMEDIA_EXPORT QPlatformMediaEncoder
+class Q_MULTIMEDIA_EXPORT QPlatformMediaRecorder
{
public:
- virtual ~QPlatformMediaEncoder() {}
+ virtual ~QPlatformMediaRecorder() {}
virtual bool isLocationWritable(const QUrl &location) const = 0;
@@ -145,13 +113,13 @@ public:
virtual void resume();
virtual void stop() = 0;
- virtual qint64 duration() const = 0;
+ virtual qint64 duration() const { return m_duration; }
virtual void setMetaData(const QMediaMetaData &) {}
virtual QMediaMetaData metaData() const { return {}; }
- QMediaRecorder::Error error() const { return m_error;}
- QString errorString() const { return m_errorString; }
+ QMediaRecorder::Error error() const { return m_error.code(); }
+ QString errorString() const { return m_error.description(); }
QUrl outputLocation() const { return m_outputLocation; }
virtual void setOutputLocation(const QUrl &location) { m_outputLocation = location; }
@@ -159,8 +127,11 @@ public:
void clearActualLocation() { m_actualLocation.clear(); }
void clearError() { error(QMediaRecorder::NoError, QString()); }
+ QIODevice *outputDevice() const { return m_outputDevice; }
+ void setOutputDevice(QIODevice *device) { m_outputDevice = device; }
+
protected:
- explicit QPlatformMediaEncoder(QMediaRecorder *parent);
+ explicit QPlatformMediaRecorder(QMediaRecorder *parent);
void stateChanged(QMediaRecorder::RecorderState state);
void durationChanged(qint64 position);
@@ -168,12 +139,17 @@ protected:
void error(QMediaRecorder::Error error, const QString &errorString);
void metaDataChanged();
+ QMediaRecorder *mediaRecorder() { return q; }
+
+ QString findActualLocation(const QMediaEncoderSettings &settings) const;
+
private:
QMediaRecorder *q = nullptr;
- QMediaRecorder::Error m_error = QMediaRecorder::NoError;
- QString m_errorString;
+ QErrorInfo<QMediaRecorder::Error> m_error;
QUrl m_actualLocation;
QUrl m_outputLocation;
+ QPointer<QIODevice> m_outputDevice;
+ qint64 m_duration = 0;
QMediaRecorder::RecorderState m_state = QMediaRecorder::StoppedState;
};
diff --git a/src/multimedia/platform/qplatformsurfacecapture.cpp b/src/multimedia/platform/qplatformsurfacecapture.cpp
new file mode 100644
index 000000000..a56f48b62
--- /dev/null
+++ b/src/multimedia/platform/qplatformsurfacecapture.cpp
@@ -0,0 +1,83 @@
+// Copyright (C) 2022 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 "platform/qplatformsurfacecapture_p.h"
+#include "qvideoframe.h"
+#include "qguiapplication.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+QPlatformSurfaceCapture::QPlatformSurfaceCapture(Source initialSource) : m_source(initialSource)
+{
+ Q_ASSERT(std::visit([](auto source) { return source == decltype(source){}; }, initialSource));
+ qRegisterMetaType<QVideoFrame>();
+}
+
+void QPlatformSurfaceCapture::setActive(bool active)
+{
+ if (m_active == active)
+ return;
+
+ if (!setActiveInternal(active))
+ return;
+
+ m_active = active;
+ emit activeChanged(active);
+}
+
+bool QPlatformSurfaceCapture::isActive() const
+{
+ return m_active;
+}
+
+void QPlatformSurfaceCapture::setSource(Source source)
+{
+ Q_ASSERT(source.index() == m_source.index());
+
+ if (m_source == source)
+ return;
+
+ if (m_active)
+ setActiveInternal(false);
+
+ m_source = source;
+
+ if (m_active && !setActiveInternal(true)) {
+ m_active = false;
+ emit activeChanged(false);
+ }
+
+ std::visit([this](auto source) { emit sourceChanged(source); }, m_source);
+}
+
+QPlatformSurfaceCapture::Error QPlatformSurfaceCapture::error() const
+{
+ return m_error.code();
+}
+
+QString QPlatformSurfaceCapture::errorString() const
+{
+ return m_error.description();
+}
+
+void QPlatformSurfaceCapture::updateError(Error error, const QString &errorString)
+{
+ m_error.setAndNotify(error, errorString, *this);
+}
+
+bool QPlatformSurfaceCapture::checkScreenWithError(ScreenSource &screen)
+{
+ if (!screen)
+ screen = QGuiApplication::primaryScreen();
+
+ if (screen)
+ return true;
+
+ updateError(NotFound, QLatin1String("No screens found"));
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformsurfacecapture_p.cpp"
diff --git a/src/multimedia/platform/qplatformsurfacecapture_p.h b/src/multimedia/platform/qplatformsurfacecapture_p.h
new file mode 100644
index 000000000..42fbda474
--- /dev/null
+++ b/src/multimedia/platform/qplatformsurfacecapture_p.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2022 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 QPLATFORMSURFACECAPTURE_H
+#define QPLATFORMSURFACECAPTURE_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 "qplatformvideosource_p.h"
+#include "qscreen.h"
+#include "qcapturablewindow.h"
+#include "qpointer.h"
+#include "private/qerrorinfo_p.h"
+
+#include <optional>
+#include <variant>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFrame;
+
+class Q_MULTIMEDIA_EXPORT QPlatformSurfaceCapture : public QPlatformVideoSource
+{
+ Q_OBJECT
+
+public:
+ enum Error {
+ NoError = 0,
+ InternalError = 1,
+ CapturingNotSupported = 2,
+ CaptureFailed = 4,
+ NotFound = 5,
+ };
+
+ using ScreenSource = QPointer<QScreen>;
+ using WindowSource = QCapturableWindow;
+
+ using Source = std::variant<ScreenSource, WindowSource>;
+
+ explicit QPlatformSurfaceCapture(Source initialSource);
+
+ void setActive(bool active) override;
+ bool isActive() const override;
+
+ void setSource(Source source);
+
+ template<typename Type>
+ Type source() const {
+ return *q_check_ptr(std::get_if<Type>(&m_source));
+ }
+
+ Source source() const { return m_source; }
+
+ Error error() const;
+ QString errorString() const;
+
+protected:
+ virtual bool setActiveInternal(bool) = 0;
+
+ bool checkScreenWithError(ScreenSource &screen);
+
+public Q_SLOTS:
+ void updateError(Error error, const QString &errorString);
+
+Q_SIGNALS:
+ void sourceChanged(WindowSource);
+ void sourceChanged(ScreenSource);
+ void errorChanged();
+ void errorOccurred(Error error, QString errorString);
+
+private:
+ QErrorInfo<Error> m_error;
+ Source m_source;
+ bool m_active = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMSURFACECAPTURE_H
diff --git a/src/multimedia/platform/qplatformvideodevices.cpp b/src/multimedia/platform/qplatformvideodevices.cpp
new file mode 100644
index 000000000..bcf664cd2
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideodevices.cpp
@@ -0,0 +1,12 @@
+// Copyright (C) 2022 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 "qplatformvideodevices_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPlatformVideoDevices::~QPlatformVideoDevices() = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformvideodevices_p.cpp"
diff --git a/src/multimedia/platform/qplatformvideodevices_p.h b/src/multimedia/platform/qplatformvideodevices_p.h
new file mode 100644
index 000000000..008322be2
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideodevices_p.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2022 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 QPLATFORMVIDEODEVICES_H
+#define QPLATFORMVIDEODEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtmultimediaglobal_p.h>
+#include <qmediarecorder.h>
+#include <qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformMediaIntegration;
+
+class Q_MULTIMEDIA_EXPORT QPlatformVideoDevices : public QObject
+{
+ Q_OBJECT
+public:
+ QPlatformVideoDevices(QPlatformMediaIntegration *integration)
+ : m_integration(integration)
+ {}
+
+ ~QPlatformVideoDevices() override;
+
+ virtual QList<QCameraDevice> videoDevices() const = 0;
+
+Q_SIGNALS:
+ void videoInputsChanged();
+
+protected:
+ QPlatformMediaIntegration *m_integration = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/platform/qplatformvideosink.cpp b/src/multimedia/platform/qplatformvideosink.cpp
index d3e5e24b2..abf82af0f 100644
--- a/src/multimedia/platform/qplatformvideosink.cpp
+++ b/src/multimedia/platform/qplatformvideosink.cpp
@@ -1,99 +1,77 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qplatformvideosink_p.h"
+#include "qmultimediautils_p.h"
QT_BEGIN_NAMESPACE
-/*!
- \class QPlatformVideoSink
- \obsolete
+QPlatformVideoSink::QPlatformVideoSink(QVideoSink *parent) : QObject(parent), m_sink(parent) { }
- \inmodule QtMultimedia
+QPlatformVideoSink::~QPlatformVideoSink() = default;
- \ingroup multimedia_control
- \brief The QPlatformVideoSink class provides a media control for rendering video to a window.
-
- QPlatformVideoSink is one of a number of possible video output controls.
-
- \sa QVideoWidget
-*/
-
-/*!
- Constructs a new video window control with the given \a parent.
-*/
-QPlatformVideoSink::QPlatformVideoSink(QVideoSink *parent)
- : QObject(parent),
- sink(parent)
+QSize QPlatformVideoSink::nativeSize() const
{
+ QMutexLocker locker(&m_mutex);
+ return m_nativeSize;
}
-/*!
- \fn QPlatformVideoSink::setWinId(WId id)
-
- Sets the \a id of the window a video overlay end point renders to.
-*/
-
-/*!
- \fn QPlatformVideoSink::setDisplayRect(const QRect &rect)
- Sets the sub-\a rect of a window where video is displayed.
-*/
-
-/*!
- \fn QPlatformVideoSink::setFullScreen(bool fullScreen)
-
- Sets whether a video overlay is a \a fullScreen overlay.
-*/
+void QPlatformVideoSink::setNativeSize(QSize s)
+{
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_nativeSize == s)
+ return;
+ m_nativeSize = s;
+ }
+ emit m_sink->videoSizeChanged();
+}
-/*!
- \fn QPlatformVideoSink::nativeSize() const
+void QPlatformVideoSink::setVideoFrame(const QVideoFrame &frame)
+{
+ bool sizeChanged = false;
+
+ {
+ QMutexLocker locker(&m_mutex);
+ if (frame == m_currentVideoFrame)
+ return;
+ m_currentVideoFrame = frame;
+ m_currentVideoFrame.setSubtitleText(m_subtitleText);
+ const auto size = qRotatedFrameSize(frame);
+ if (size != m_nativeSize) {
+ m_nativeSize = size;
+ sizeChanged = true;
+ }
+ }
+
+ // emit signals outside the mutex to avoid deadlocks on the user side
+ if (sizeChanged)
+ emit m_sink->videoSizeChanged();
+ emit m_sink->videoFrameChanged(frame);
+}
- Returns a suggested size for the video display based on the resolution and aspect ratio of the
- video.
-*/
+QVideoFrame QPlatformVideoSink::currentVideoFrame() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_currentVideoFrame;
+}
-/*!
- \fn QPlatformVideoSink::setAspectRatioMode(Qt::AspectRatioMode mode)
+void QPlatformVideoSink::setSubtitleText(const QString &subtitleText)
+{
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_subtitleText == subtitleText)
+ return;
+ m_subtitleText = subtitleText;
+ }
+ emit m_sink->subtitleTextChanged(subtitleText);
+}
- Sets the aspect ratio \a mode which determines how video is scaled to the fit the display region
- with respect to its aspect ratio.
-*/
+QString QPlatformVideoSink::subtitleText() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_subtitleText;
+}
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformvideosink_p.h b/src/multimedia/platform/qplatformvideosink_p.h
index 95d1aa085..53eca374f 100644
--- a/src/multimedia/platform/qplatformvideosink_p.h
+++ b/src/multimedia/platform/qplatformvideosink_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMVIDEOSINK_H
#define QPLATFORMVIDEOSINK_H
@@ -60,6 +24,7 @@
#include <qvideosink.h>
#include <qvideoframe.h>
#include <qdebug.h>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -71,6 +36,8 @@ class Q_MULTIMEDIA_EXPORT QPlatformVideoSink : public QObject
Q_OBJECT
public:
+ ~QPlatformVideoSink() override;
+
virtual void setRhi(QRhi * /*rhi*/) {}
virtual void setWinId(WId) {}
@@ -78,54 +45,34 @@ public:
virtual void setFullScreen(bool) {}
virtual void setAspectRatioMode(Qt::AspectRatioMode) {}
- // ### make non virtual, once Windows is ported
- virtual QSize nativeSize() const
- {
- QMutexLocker locker(&mutex);
- return m_nativeSize;
- }
+ QSize nativeSize() const;
virtual void setBrightness(float /*brightness*/) {}
virtual void setContrast(float /*contrast*/) {}
virtual void setHue(float /*hue*/) {}
virtual void setSaturation(float /*saturation*/) {}
- QVideoSink *videoSink() { return sink; }
-
- void setNativeSize(QSize s) {
- QMutexLocker locker(&mutex);
- if (m_nativeSize == s)
- return;
- m_nativeSize = s;
- sink->videoSizeChanged();
- }
- void setVideoFrame(const QVideoFrame &frame) {
- setNativeSize(frame.size());
- m_currentVideoFrame = frame;
- m_currentVideoFrame.setSubtitleText(subtitleText());
- sink->videoFrameChanged(m_currentVideoFrame);
- }
- QVideoFrame currentVideoFrame() const { return m_currentVideoFrame; }
-
- void setSubtitleText(const QString &subtitleText)
- {
- QMutexLocker locker(&mutex);
- if (m_subtitleText == subtitleText)
- return;
- m_subtitleText = subtitleText;
- sink->subtitleTextChanged(subtitleText);
- }
- QString subtitleText() const
- {
- QMutexLocker locker(&mutex);
- return m_subtitleText;
- }
+ QVideoSink *videoSink() { return m_sink; }
+
+ void setNativeSize(QSize s);
+
+ virtual void setVideoFrame(const QVideoFrame &frame);
+
+ QVideoFrame currentVideoFrame() const;
+
+ void setSubtitleText(const QString &subtitleText);
+
+ QString subtitleText() const;
protected:
explicit QPlatformVideoSink(QVideoSink *parent);
- QVideoSink *sink = nullptr;
- mutable QMutex mutex;
+
+Q_SIGNALS:
+ void rhiChanged(QRhi *rhi);
+
private:
+ QVideoSink *m_sink = nullptr;
+ mutable QMutex m_mutex;
QSize m_nativeSize;
QString m_subtitleText;
QVideoFrame m_currentVideoFrame;
diff --git a/src/multimedia/platform/qplatformvideosource.cpp b/src/multimedia/platform/qplatformvideosource.cpp
new file mode 100644
index 000000000..a23ed91ae
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideosource.cpp
@@ -0,0 +1,15 @@
+// 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 "qplatformvideosource_p.h"
+
+QT_BEGIN_NAMESPACE
+
+std::optional<int> QPlatformVideoSource::ffmpegHWPixelFormat() const
+{
+ return {};
+};
+
+QT_END_NAMESPACE
+
+//#include "moc_qplatformvideosource_p.cpp
diff --git a/src/multimedia/platform/qplatformvideosource_p.h b/src/multimedia/platform/qplatformvideosource_p.h
new file mode 100644
index 000000000..3ed76d3e2
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideosource_p.h
@@ -0,0 +1,53 @@
+// 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
+
+#ifndef QPLATFORMVIDEOSOURCE_P_H
+#define QPLATFORMVIDEOSOURCE_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 "qvideoframeformat.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qnativeinterface.h>
+#include <QtCore/private/qglobal_p.h>
+
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFrame;
+class QPlatformMediaCaptureSession;
+
+class Q_MULTIMEDIA_EXPORT QPlatformVideoSource : public QObject
+{
+ Q_OBJECT
+public:
+ using QObject::QObject;
+
+ virtual void setActive(bool active) = 0;
+ virtual bool isActive() const = 0;
+
+ virtual QVideoFrameFormat frameFormat() const = 0;
+
+ virtual std::optional<int> ffmpegHWPixelFormat() const;
+
+ virtual void setCaptureSession(QPlatformMediaCaptureSession *) { }
+
+Q_SIGNALS:
+ void newVideoFrame(const QVideoFrame &);
+ void activeChanged(bool);
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMVIDEOSOURCE_P_H
diff --git a/src/multimedia/platform/wasm/audio/qwasmaudiodevice.cpp b/src/multimedia/platform/wasm/audio/qwasmaudiodevice.cpp
deleted file mode 100644
index 5eb6a3816..000000000
--- a/src/multimedia/platform/wasm/audio/qwasmaudiodevice.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwasmaudiodevice_p.h"
-#include <emscripten.h>
-#include <AL/al.h>
-#include <AL/alc.h>
-
-QT_BEGIN_NAMESPACE
-
-QWasmAudioDevice::QWasmAudioDevice(const char *device, const char *desc, bool isDef, QAudioDevice::Mode mode)
- : QAudioDevicePrivate(device, mode)
-{
- description = QString::fromUtf8(desc);
- isDefault = isDef;
-
- minimumChannelCount = 1;
- maximumChannelCount = 2;
- minimumSampleRate = 1;
- maximumSampleRate = 192'000;
-
- // native openAL formats
- supportedSampleFormats.append(QAudioFormat::UInt8);
- supportedSampleFormats.append(QAudioFormat::Int16);
-
- // Browsers use 32bit floats as native, but emscripten reccomends checking for the exension.
- if (alIsExtensionPresent("AL_EXT_float32"))
- supportedSampleFormats.append(QAudioFormat::Float);
-
- preferredFormat.setChannelCount(2);
-
- preferredFormat.setSampleRate(EM_ASM_INT({
- var AudioContext = window.AudioContext || window.webkitAudioContext;
- var ctx = new AudioContext();
- var sr = ctx.sampleRate;
- ctx.close();
- return sr;
- }));
-
- auto f = QAudioFormat::Float;
-
- if (!supportedSampleFormats.contains(f))
- f = QAudioFormat::Int16;
- preferredFormat.setSampleFormat(f);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/wasm/audio/qwasmaudiodevice_p.h b/src/multimedia/platform/wasm/audio/qwasmaudiodevice_p.h
deleted file mode 100644
index fbe14e6e2..000000000
--- a/src/multimedia/platform/wasm/audio/qwasmaudiodevice_p.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWASMAUDIODEVICEINFO_H
-#define QWASMAUDIODEVICEINFO_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 "qaudiodevice_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QWasmAudioDevice : public QAudioDevicePrivate
-{
-public:
- QWasmAudioDevice(const char *device, const char *description, bool isDefault, QAudioDevice::Mode mode);
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QWASMAUDIODEVICEINFO_H
diff --git a/src/multimedia/platform/wasm/audio/qwasmaudiosink_p.h b/src/multimedia/platform/wasm/audio/qwasmaudiosink_p.h
deleted file mode 100644
index 1c75ec258..000000000
--- a/src/multimedia/platform/wasm/audio/qwasmaudiosink_p.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWASMAUDIOSINK_H
-#define QWASMAUDIOSINK_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qaudiosystem_p.h>
-#include <QTimer>
-#include <QElapsedTimer>
-
-class ALData;
-class QIODevice;
-
-QT_BEGIN_NAMESPACE
-
-class QWasmAudioSink : public QPlatformAudioSink
-{
- Q_OBJECT
-
- QByteArray m_name;
- ALData *aldata = nullptr;
- QTimer m_timer;
- QIODevice *m_device = nullptr;
- QAudioFormat m_format;
- QAudio::Error m_error = QAudio::NoError;
- bool m_running = false;
- QAudio::State m_state = QAudio::StoppedState;
- int m_bufferSize = 0;
- quint64 m_processed = 0;
- QElapsedTimer m_elapsedTimer;
- int m_bufferFragmentsCount = 10;
- int m_notifyInterval = 0;
- char *m_tmpData = nullptr;
- int m_bufferFragmentSize = 0;
- int m_lastNotified = 0;
- int m_tmpDataOffset = 0;
- int m_bufferFragmentsBusyCount = 0;
- bool m_pullMode;
- qreal m_volume = 1;
-
- void loadALBuffers();
- void unloadALBuffers();
- void nextALBuffers();
-
-private slots:
- void updateState();
- void setError(QAudio::Error);
-
-public:
- QWasmAudioSink(const QByteArray &device);
- ~QWasmAudioSink();
-
-public:
- void start(QIODevice *device) override;
- QIODevice *start() override;
- void start(bool mode);
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- int bytesFree() const override;
- void setBufferSize(int value) override;
- int bufferSize() const override;
- qint64 processedUSecs() const override;
- QAudio::Error error() const override;
- QAudio::State state() const override;
- void setFormat(const QAudioFormat &fmt) override;
- QAudioFormat format() const override;
- void setVolume(qreal volume) override;
- qreal volume() const override;
-
- friend class QWasmAudioSinkDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWASMAUDIOSINK_H
diff --git a/src/multimedia/platform/wasm/audio/qwasmaudiosource_p.h b/src/multimedia/platform/wasm/audio/qwasmaudiosource_p.h
deleted file mode 100644
index aef81d75b..000000000
--- a/src/multimedia/platform/wasm/audio/qwasmaudiosource_p.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWASMAUDIOSOURCE_H
-#define QWASMAUDIOSOURCE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qaudiosystem_p.h>
-#include <QTimer>
-#include <QElapsedTimer>
-
-QT_BEGIN_NAMESPACE
-
-class ALData;
-
-class QWasmAudioSource : public QPlatformAudioSource
-{
- Q_OBJECT
-
- QByteArray m_name;
- ALData *aldata = nullptr;
- QTimer m_timer;
- QIODevice *m_device = nullptr;
- QAudioFormat m_format;
- qreal m_volume = 1;
- int m_bufferSize;
- bool m_running = false;
- bool m_suspended = false;
- QAudio::Error m_error;
- bool m_pullMode;
- char *m_tmpData = nullptr;
- QElapsedTimer m_elapsedTimer;
- int m_notifyInterval = 0;
- quint64 m_processed = 0;
-
- void writeBuffer();
-public:
- QWasmAudioSource(const QByteArray &device);
-
-public:
- void start(QIODevice *device) override;
- QIODevice *start() override;
- void start(bool mode);
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- int bytesReady() const override;
- void setBufferSize(int value) override;
- int bufferSize() const override;
- qint64 processedUSecs() const override;
- QAudio::Error error() const override;
- QAudio::State state() const override;
- void setFormat(const QAudioFormat &fmt) override;
- QAudioFormat format() const override;
- void setVolume(qreal volume) override;
- qreal volume() const override;
-
- friend class QWasmAudioSourceDevice;
- void setError(const QAudio::Error &error);
-};
-
-QT_END_NAMESPACE
-
-#endif // QWASMAUDIOSOURCE_H
diff --git a/src/multimedia/platform/wasm/qwasmmediadevices.cpp b/src/multimedia/platform/wasm/qwasmmediadevices.cpp
deleted file mode 100644
index c21533943..000000000
--- a/src/multimedia/platform/wasm/qwasmmediadevices.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwasmmediadevices_p.h"
-#include "qcameradevice_p.h"
-
-#include "audio/qwasmaudiosource_p.h"
-#include "audio/qwasmaudiosink_p.h"
-#include "audio/qwasmaudiodevice_p.h"
-#include <AL/al.h>
-#include <AL/alc.h>
-
-QT_BEGIN_NAMESPACE
-
-QWasmMediaDevices::QWasmMediaDevices()
- : QPlatformMediaDevices()
-{
- auto capture = alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
- // present even if there is no capture device
- if (capture)
- m_ins.append((new QWasmAudioDevice(capture, "WebAssembly audio capture device", true,
- QAudioDevice::Input))->create());
-
- auto playback = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
- // present even if there is no playback device
- if (playback)
- m_outs.append((new QWasmAudioDevice(playback, "WebAssembly audio playback device", true,
- QAudioDevice::Output))->create());
-}
-
-QList<QAudioDevice> QWasmMediaDevices::audioInputs() const
-{
- return m_ins;
-}
-
-QList<QAudioDevice> QWasmMediaDevices::audioOutputs() const
-{
- return m_outs;
-}
-
-QList<QCameraDevice> QWasmMediaDevices::videoInputs() const
-{
- return {};
-}
-
-QPlatformAudioSource *QWasmMediaDevices::createAudioSource(const QAudioDevice &deviceInfo)
-{
- return new QWasmAudioSource(deviceInfo.id());
-}
-
-QPlatformAudioSink *QWasmMediaDevices::createAudioSink(const QAudioDevice &deviceInfo)
-{
- return new QWasmAudioSink(deviceInfo.id());
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/wasm/qwasmmediadevices_p.h b/src/multimedia/platform/wasm/qwasmmediadevices_p.h
deleted file mode 100644
index 63fa05476..000000000
--- a/src/multimedia/platform/wasm/qwasmmediadevices_p.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWASMMEDIADEVICES_H
-#define QWASMMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <qset.h>
-#include <qaudio.h>
-#include <qaudiodevice.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWasmAudioEngine;
-
-class QWasmMediaDevices : public QPlatformMediaDevices
-{
-public:
- QWasmMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) override;
-
-private:
- QList<QAudioDevice> m_outs;
- QList<QAudioDevice> m_ins;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/wasm/qwasmmediaintegration.cpp b/src/multimedia/platform/wasm/qwasmmediaintegration.cpp
deleted file mode 100644
index 30ee3cca9..000000000
--- a/src/multimedia/platform/wasm/qwasmmediaintegration.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwasmmediaintegration_p.h"
-#include "qwasmmediadevices_p.h"
-#include <QLoggingCategory>
-
-#include <private/qplatformmediaformatinfo_p.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(qtWasmMediaPlugin, "qt.multimedia.wasm")
-
-QWasmMediaIntegration::QWasmMediaIntegration()
-{
-
-}
-
-QWasmMediaIntegration::~QWasmMediaIntegration()
-{
- delete m_devices;
- delete m_formatInfo;
-}
-
-QPlatformMediaFormatInfo *QWasmMediaIntegration::formatInfo()
-{
- if (!m_formatInfo)
- m_formatInfo = new QPlatformMediaFormatInfo();
- return m_formatInfo;
-}
-
-QPlatformMediaDevices *QWasmMediaIntegration::devices()
-{
- if (!m_devices)
- m_devices = new QWasmMediaDevices();
- return m_devices;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/wasm/qwasmmediaintegration_p.h b/src/multimedia/platform/wasm/qwasmmediaintegration_p.h
deleted file mode 100644
index 1251dc9f5..000000000
--- a/src/multimedia/platform/wasm/qwasmmediaintegration_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWASMMEDIAINTEGRATION_H
-#define QWASMMEDIAINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWasmMediaDevices;
-
-class QWasmMediaIntegration : public QPlatformMediaIntegration
-{
-public:
- QWasmMediaIntegration();
- ~QWasmMediaIntegration();
-
- QPlatformMediaFormatInfo *formatInfo() override;
-
- QWasmMediaDevices *m_devices = nullptr;
- QPlatformMediaFormatInfo *m_formatInfo = nullptr;
-
- QPlatformMediaDevices *devices() override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWASMMEDIAINTEGRATION_H
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudiodevice_p.h b/src/multimedia/platform/windows/audio/qwindowsaudiodevice_p.h
deleted file mode 100644
index 7d55a5820..000000000
--- a/src/multimedia/platform/windows/audio/qwindowsaudiodevice_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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 QWINDOWSAUDIODEVICEINFO_H
-#define QWINDOWSAUDIODEVICEINFO_H
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qdebug.h>
-
-#include <QtMultimedia/qaudiodevice.h>
-#include <private/qaudiosystem_p.h>
-#include <private/qaudiodevice_p.h>
-
-
-QT_BEGIN_NAMESPACE
-
-const unsigned int MAX_SAMPLE_RATES = 5;
-const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 };
-
-class QWindowsAudioDeviceInfo : public QAudioDevicePrivate
-{
-public:
- QWindowsAudioDeviceInfo(QByteArray dev, int waveID, const QString &description, QAudioDevice::Mode mode);
- ~QWindowsAudioDeviceInfo();
-
- bool open();
- void close();
-
- bool testSettings(const QAudioFormat& format) const;
-
- int waveId() const { return devId; }
-private:
- quint32 devId;
-};
-
-
-
-QT_END_NAMESPACE
-
-
-#endif // QWINDOWSAUDIODEVICEINFO_H
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudiosink.cpp b/src/multimedia/platform/windows/audio/qwindowsaudiosink.cpp
deleted file mode 100644
index 8cc4d33cf..000000000
--- a/src/multimedia/platform/windows/audio/qwindowsaudiosink.cpp
+++ /dev/null
@@ -1,608 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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.
-//
-// INTERNAL USE ONLY: Do NOT use for any other purpose.
-//
-
-#include "qwindowsaudiosink_p.h"
-#include "qwindowsaudiodevice_p.h"
-#include "qwindowsaudioutils_p.h"
-#include <QtEndian>
-#include <QtCore/QDataStream>
-#include <QtCore/qtimer.h>
-#include <private/qaudiohelpers_p.h>
-
-#include <qloggingcategory.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(qLcAudioOutput, "qt.multimedia.audiooutput")
-
-QWindowsAudioSink::QWindowsAudioSink(int deviceId)
-{
- bytesAvailable = 0;
- buffer_size = 0;
- period_size = 0;
- m_deviceId = deviceId;
- totalTimeValue = 0;
- errorState = QAudio::NoError;
- deviceState = QAudio::StoppedState;
- audioSource = 0;
- pullMode = true;
- volumeCache = qreal(1.0);
- blocks_count = 5;
-}
-
-QWindowsAudioSink::~QWindowsAudioSink()
-{
- close();
-}
-
-void CALLBACK QWindowsAudioSink::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg,
- DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
-{
- Q_UNUSED(dwParam1);
- Q_UNUSED(dwParam2);
- Q_UNUSED(hWaveOut);
-
- QWindowsAudioSink* qAudio;
- qAudio = (QWindowsAudioSink*)(dwInstance);
- if(!qAudio)
- return;
-
- QMutexLocker locker(&qAudio->mutex);
-
- switch(uMsg) {
- case WOM_OPEN:
- qAudio->feedback();
- break;
- case WOM_CLOSE:
- return;
- case WOM_DONE:
- if(qAudio->buffer_size == 0 || qAudio->period_size == 0) {
- return;
- }
- qAudio->waveFreeBlockCount++;
- if (qAudio->waveFreeBlockCount >= qAudio->blocks_count)
- qAudio->waveFreeBlockCount = qAudio->blocks_count;
-
- qAudio->feedback();
- break;
- default:
- return;
- }
-}
-
-WAVEHDR* QWindowsAudioSink::allocateBlocks(int size, int count)
-{
- int i;
- unsigned char* buffer;
- WAVEHDR* blocks;
- DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count;
-
- if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
- totalBufferSize)) == 0) {
- qWarning("QAudioSink: Memory allocation error");
- return 0;
- }
- blocks = (WAVEHDR*)buffer;
- buffer += sizeof(WAVEHDR)*count;
- for(i = 0; i < count; i++) {
- blocks[i].dwBufferLength = size;
- blocks[i].lpData = (LPSTR)buffer;
- buffer += size;
- }
- return blocks;
-}
-
-void QWindowsAudioSink::freeBlocks(WAVEHDR* blockArray)
-{
- WAVEHDR* blocks = blockArray;
- for (int i = 0; i < blocks_count; ++i) {
- waveOutUnprepareHeader(hWaveOut,blocks, sizeof(WAVEHDR));
- blocks++;
- }
- HeapFree(GetProcessHeap(), 0, blockArray);
-}
-
-QAudioFormat QWindowsAudioSink::format() const
-{
- return settings;
-}
-
-void QWindowsAudioSink::setFormat(const QAudioFormat& fmt)
-{
- if (deviceState == QAudio::StoppedState)
- settings = fmt;
-}
-
-void QWindowsAudioSink::start(QIODevice* device)
-{
- qCDebug(qLcAudioOutput) << "start(ioDevice)";
- if(deviceState != QAudio::StoppedState)
- close();
-
- if(!pullMode && audioSource)
- delete audioSource;
-
- pullMode = true;
- audioSource = device;
-
- deviceState = QAudio::ActiveState;
-
- if(!open())
- return;
-
- emit stateChanged(deviceState);
-}
-
-QIODevice* QWindowsAudioSink::start()
-{
- qCDebug(qLcAudioOutput) << "start()";
- if(deviceState != QAudio::StoppedState)
- close();
-
- if(!pullMode && audioSource)
- delete audioSource;
-
- pullMode = false;
- audioSource = new OutputPrivate(this);
- audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
-
- deviceState = QAudio::IdleState;
-
- if(!open())
- return 0;
-
- emit stateChanged(deviceState);
-
- return audioSource;
-}
-
-void QWindowsAudioSink::stop()
-{
- qCDebug(qLcAudioOutput) << "stop()";
- if(deviceState == QAudio::StoppedState)
- return;
- close();
- if(!pullMode && audioSource) {
- delete audioSource;
- audioSource = 0;
- }
- emit stateChanged(deviceState);
-}
-
-bool QWindowsAudioSink::open()
-{
- qCDebug(qLcAudioOutput) << "open()";
-
- period_size = 0;
-
- if (!qt_convertFormat(settings, &wfx)) {
- qWarning("QAudioSink: open error, invalid format.");
- } else if (buffer_size == 0) {
- // Default buffer size, 200ms, default period size is 40ms
- buffer_size
- = (settings.sampleRate()
- * settings.bytesPerFrame()
- + 39) / 5;
- period_size = buffer_size / 5;
- } else {
- period_size = buffer_size / 5;
- }
-
- // Make even size of wave block to prevent crackling
- // due to waveOutWrite() does not like odd buffer length
- period_size &= ~1;
-
- if (period_size == 0) {
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- return false;
- }
-
- const int periods = buffer_size / period_size;
- bool ok = false;
- static int wave_buffers = qEnvironmentVariableIntValue("QT_WAVE_BUFFERS", &ok);
- if (wave_buffers < periods) {
- if (ok)
- qWarning("Number of WAVE buffers (QT_WAVE_BUFFERS=%d) cannot be less than %d.", wave_buffers, periods);
- wave_buffers = periods;
- }
-
- blocks_count = wave_buffers;
- waveBlocks = allocateBlocks(period_size, blocks_count);
-
- mutex.lock();
- waveFreeBlockCount = blocks_count;
- mutex.unlock();
-
- waveCurrentBlock = 0;
-
- if (audioBuffer == nullptr)
- audioBuffer = new char[blocks_count * period_size];
-
- elapsedTimeOffset = 0;
-
- if (waveOutOpen(&hWaveOut, UINT_PTR(m_deviceId), &wfx.Format,
- (DWORD_PTR)&waveOutProc,
- (DWORD_PTR) this,
- CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- qWarning("QAudioSink: open error");
- return false;
- }
-
- totalTimeValue = 0;
- elapsedTimeOffset = 0;
-
- errorState = QAudio::NoError;
- if(pullMode) {
- deviceState = QAudio::ActiveState;
- QTimer::singleShot(10, this, SLOT(feedback()));
- } else
- deviceState = QAudio::IdleState;
-
- return true;
-}
-
-void QWindowsAudioSink::pauseAndSleep()
-{
- waveOutPause(hWaveOut);
- int bitrate = settings.sampleRate() * settings.bytesPerFrame();
- // Time of written data.
- int delay = (buffer_size - bytesFree()) * 1000 / bitrate;
- Sleep(delay + 10);
-}
-
-void QWindowsAudioSink::close()
-{
- qCDebug(qLcAudioOutput) << "close()";
- if(deviceState == QAudio::StoppedState)
- return;
-
- // Pause playback before reset to avoid uneeded crackling at the end.
- pauseAndSleep();
- QMutexLocker locker(&mutex);
- deviceState = QAudio::StoppedState;
- errorState = QAudio::NoError;
- locker.unlock();
- waveOutReset(hWaveOut);
-
- freeBlocks(waveBlocks);
- waveOutClose(hWaveOut);
- locker.relock();
- delete [] audioBuffer;
- audioBuffer = nullptr;
- buffer_size = 0;
- qCDebug(qLcAudioOutput) << "end close()";
-}
-
-qsizetype QWindowsAudioSink::bytesFree() const
-{
- int buf;
- QMutexLocker locker(&mutex);
- buf = waveFreeBlockCount*period_size;
-
- return buf;
-}
-
-void QWindowsAudioSink::setBufferSize(qsizetype value)
-{
- if(deviceState == QAudio::StoppedState)
- buffer_size = value;
-}
-
-qsizetype QWindowsAudioSink::bufferSize() const
-{
- return buffer_size;
-}
-
-qint64 QWindowsAudioSink::processedUSecs() const
-{
- if (deviceState == QAudio::StoppedState)
- return 0;
- qint64 result = qint64(1000000) * totalTimeValue /
- settings.bytesPerFrame() / settings.sampleRate();
-
- return result;
-}
-
-qint64 QWindowsAudioSink::write(const char *data, qint64 len)
-{
- qCDebug(qLcAudioOutput) << "write()" << len << deviceState << period_size;
-
- // Write out some audio data
- if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
- return 0;
-
- WAVEHDR* current;
- qint64 written = 0;
- current = &waveBlocks[waveCurrentBlock];
- while(len > 0) {
- mutex.lock();
- if(waveFreeBlockCount==0) {
- mutex.unlock();
- break;
- }
- mutex.unlock();
-
- if(current->dwFlags & WHDR_PREPARED)
- waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
-
- qint64 remain;
- if(len < period_size)
- remain = len;
- else
- remain = period_size;
-
- if (volumeCache < qreal(1.0))
- QAudioHelperInternal::qMultiplySamples(volumeCache, settings, data, current->lpData, remain);
- else
- memcpy(current->lpData, data, remain);
-
- len -= remain;
- data += remain;
- current->dwBufferLength = remain;
- written += remain;
- waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
- waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
-
- mutex.lock();
- waveFreeBlockCount--;
- qCDebug(qLcAudioOutput) << "write out" << current->dwBufferLength << "waveFreeBlockCount" << waveFreeBlockCount;
- mutex.unlock();
-
- totalTimeValue += current->dwBufferLength;
- waveCurrentBlock++;
- waveCurrentBlock %= blocks_count;
- current = &waveBlocks[waveCurrentBlock];
- current->dwUser = 0;
- errorState = QAudio::NoError;
- if (deviceState != QAudio::ActiveState) {
- deviceState = QAudio::ActiveState;
- emit stateChanged(deviceState);
- }
- }
- return written;
-}
-
-void QWindowsAudioSink::resume()
-{
- qCDebug(qLcAudioOutput) << "resume()";
- if(deviceState == QAudio::SuspendedState) {
- deviceState = pullMode ? QAudio::ActiveState : QAudio::IdleState;
- errorState = QAudio::NoError;
- waveOutRestart(hWaveOut);
- QTimer::singleShot(10, this, SLOT(feedback()));
- emit stateChanged(deviceState);
- }
-}
-
-void QWindowsAudioSink::suspend()
-{
- qCDebug(qLcAudioOutput) << "suspend()";
- if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState) {
- pauseAndSleep();
- deviceState = QAudio::SuspendedState;
- errorState = QAudio::NoError;
- emit stateChanged(deviceState);
- }
-}
-
-void QWindowsAudioSink::feedback()
-{
- qCDebug(qLcAudioOutput) << "feedback()";
- bytesAvailable = waveFreeBlockCount * period_size;
-
- if (deviceState != QAudio::StoppedState && deviceState != QAudio::SuspendedState) {
- if (bytesAvailable >= period_size) {
- qCDebug(qLcAudioOutput) << " ->invoke()";
- QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection);
- }
- }
-}
-
-bool QWindowsAudioSink::deviceReady()
-{
- qCDebug(qLcAudioOutput) << ">>>> deviceReady() state=" << deviceState << pullMode;
-
- if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState)
- return false;
-
- if(pullMode) {
- qCDebug(qLcAudioOutput) << "deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
- bool startup = false;
- if(totalTimeValue == 0)
- startup = true;
-
- bool full=false;
-
- mutex.lock();
- if (waveFreeBlockCount == 0)
- full = true;
- mutex.unlock();
-
- if (full) {
- qCDebug(qLcAudioOutput) << "Skipping data as unable to write";
- return true;
- }
-
- if(startup)
- waveOutPause(hWaveOut);
- int input = bytesAvailable;
- int l = audioSource->read(audioBuffer,input);
- if(l > 0) {
- int out = write(audioBuffer, l);
- if(out > 0) {
- if (deviceState != QAudio::ActiveState) {
- deviceState = QAudio::ActiveState;
- emit stateChanged(deviceState);
- }
- }
- if ( out < l) {
- // Didn't write all data
- audioSource->seek(audioSource->pos()-(l-out));
- }
- qCDebug(qLcAudioOutput) << "wrote" << out << "bytes out of" << l << "read";
-
- if (startup)
- waveOutRestart(hWaveOut);
- } else if(l == 0) {
- bytesAvailable = bytesFree();
-
- int check = 0;
-
- mutex.lock();
- check = waveFreeBlockCount;
- mutex.unlock();
-
- if (check == blocks_count) {
- if (deviceState != QAudio::IdleState) {
- errorState = QAudio::UnderrunError;
- deviceState = QAudio::IdleState;
- emit stateChanged(deviceState);
- }
- }
-
- } else if(l < 0) {
- bytesAvailable = bytesFree();
- if (errorState != QAudio::IOError)
- errorState = QAudio::IOError;
- }
- } else {
- int buffered;
-
- mutex.lock();
- buffered = waveFreeBlockCount;
- mutex.unlock();
-
- if (buffered >= blocks_count && deviceState == QAudio::ActiveState) {
- if (deviceState != QAudio::IdleState) {
- errorState = QAudio::UnderrunError;
- deviceState = QAudio::IdleState;
- emit stateChanged(deviceState);
- }
- }
- }
- qCDebug(qLcAudioOutput) << "<<<< end deviceReady() state=" << deviceState;
-
- return true;
-}
-
-QAudio::Error QWindowsAudioSink::error() const
-{
- return errorState;
-}
-
-QAudio::State QWindowsAudioSink::state() const
-{
- return deviceState;
-}
-
-void QWindowsAudioSink::setVolume(qreal v)
-{
- if (qFuzzyCompare(volumeCache, v))
- return;
-
- volumeCache = qBound(qreal(0), v, qreal(1));
-}
-
-qreal QWindowsAudioSink::volume() const
-{
- return volumeCache;
-}
-
-void QWindowsAudioSink::reset()
-{
- stop();
-}
-
-OutputPrivate::OutputPrivate(QWindowsAudioSink* audio)
-{
- audioDevice = qobject_cast<QWindowsAudioSink*>(audio);
-}
-
-OutputPrivate::~OutputPrivate() {}
-
-qint64 OutputPrivate::readData( char* data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- return 0;
-}
-
-qint64 OutputPrivate::writeData(const char* data, qint64 len)
-{
- int retry = 0;
- qint64 written = 0;
-
- if((audioDevice->deviceState == QAudio::ActiveState)
- ||(audioDevice->deviceState == QAudio::IdleState)) {
- qint64 l = len;
- while(written < l) {
- int chunk = audioDevice->write(data+written,(l-written));
- if(chunk <= 0)
- retry++;
- else
- written+=chunk;
-
- if(retry > 10)
- return written;
- }
- audioDevice->deviceState = QAudio::ActiveState;
- }
- return written;
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qwindowsaudiosink_p.cpp"
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudiosink_p.h b/src/multimedia/platform/windows/audio/qwindowsaudiosink_p.h
deleted file mode 100644
index d865011b5..000000000
--- a/src/multimedia/platform/windows/audio/qwindowsaudiosink_p.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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 QWINDOWSAUDIOOUTPUT_H
-#define QWINDOWSAUDIOOUTPUT_H
-
-#include "qwindowsaudioutils_p.h"
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmutex.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qaudiodevice.h>
-#include <private/qaudiosystem_p.h>
-
-// For compat with 4.6
-#if !defined(QT_WIN_CALLBACK)
-# if defined(Q_CC_MINGW)
-# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer))
-# else
-# define QT_WIN_CALLBACK CALLBACK
-# endif
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsAudioSink : public QPlatformAudioSink
-{
- Q_OBJECT
-public:
- QWindowsAudioSink(int deviceId);
- ~QWindowsAudioSink();
-
- qint64 write( const char *data, qint64 len );
-
- void setFormat(const QAudioFormat& fmt);
- QAudioFormat format() const;
- QIODevice* start();
- void start(QIODevice* device);
- void stop();
- void reset();
- void suspend();
- void resume();
- qsizetype bytesFree() const;
- void setBufferSize(qsizetype value);
- qsizetype bufferSize() const;
- qint64 processedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
- void setVolume(qreal);
- qreal volume() const;
-
- QIODevice* audioSource;
- QAudioFormat settings;
- QAudio::Error errorState;
- QAudio::State deviceState;
-
-private slots:
- void feedback();
- bool deviceReady();
-
-private:
- void pauseAndSleep();
- int m_deviceId;
- int bytesAvailable;
- qint64 elapsedTimeOffset;
- qint32 buffer_size;
- qint32 period_size;
- qint32 blocks_count;
- qint64 totalTimeValue;
- bool pullMode;
- qreal volumeCache;
- static void QT_WIN_CALLBACK waveOutProc( HWAVEOUT hWaveOut, UINT uMsg,
- DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 );
-
- mutable QMutex mutex;
-
- WAVEHDR* allocateBlocks(int size, int count);
- void freeBlocks(WAVEHDR* blockArray);
- bool open();
- void close();
-
- WAVEFORMATEXTENSIBLE wfx;
- HWAVEOUT hWaveOut;
- WAVEHDR* waveBlocks;
- int waveFreeBlockCount = 0;
- int waveCurrentBlock = 0;
- char *audioBuffer = nullptr;
-};
-
-class OutputPrivate : public QIODevice
-{
- Q_OBJECT
-public:
- OutputPrivate(QWindowsAudioSink* audio);
- ~OutputPrivate();
-
- qint64 readData( char* data, qint64 len);
- qint64 writeData(const char* data, qint64 len);
-
-private:
- QWindowsAudioSink *audioDevice;
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QWINDOWSAUDIOOUTPUT_H
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudiosource.cpp b/src/multimedia/platform/windows/audio/qwindowsaudiosource.cpp
deleted file mode 100644
index 9eb6e98fa..000000000
--- a/src/multimedia/platform/windows/audio/qwindowsaudiosource.cpp
+++ /dev/null
@@ -1,698 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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.
-//
-// INTERNAL USE ONLY: Do NOT use for any other purpose.
-//
-
-
-#include "qwindowsaudiosource_p.h"
-
-#include <QtCore/QDataStream>
-#include <QtCore/qtimer.h>
-
-QT_BEGIN_NAMESPACE
-
-//#define DEBUG_AUDIO 1
-
-QWindowsAudioSource::QWindowsAudioSource(int deviceId)
-{
- bytesAvailable = 0;
- buffer_size = 0;
- period_size = 0;
- m_deviceId = deviceId;
- totalTimeValue = 0;
- errorState = QAudio::NoError;
- deviceState = QAudio::StoppedState;
- audioSource = 0;
- pullMode = true;
- resuming = false;
- finished = false;
- waveBlockOffset = 0;
-
- mixerID = 0;
- cachedVolume = -1.0f;
- memset(&mixerLineControls, 0, sizeof(mixerLineControls));
-}
-
-QWindowsAudioSource::~QWindowsAudioSource()
-{
- stop();
-}
-
-void QT_WIN_CALLBACK QWindowsAudioSource::waveInProc( HWAVEIN hWaveIn, UINT uMsg,
- DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
-{
- Q_UNUSED(dwParam1);
- Q_UNUSED(dwParam2);
- Q_UNUSED(hWaveIn);
-
- QWindowsAudioSource* qAudio;
- qAudio = (QWindowsAudioSource*)(dwInstance);
- if(!qAudio)
- return;
-
- QMutexLocker locker(&qAudio->mutex);
-
- switch(uMsg) {
- case WIM_OPEN:
- break;
- case WIM_DATA:
- if(qAudio->waveFreeBlockCount > 0)
- qAudio->waveFreeBlockCount--;
- qAudio->feedback();
- break;
- case WIM_CLOSE:
- qAudio->finished = true;
- break;
- default:
- return;
- }
-}
-
-WAVEHDR* QWindowsAudioSource::allocateBlocks(int size, int count)
-{
- int i;
- unsigned char* buffer;
- WAVEHDR* blocks;
- DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count;
-
- if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
- totalBufferSize)) == 0) {
- qWarning("QAudioSource: Memory allocation error");
- return 0;
- }
- blocks = (WAVEHDR*)buffer;
- buffer += sizeof(WAVEHDR)*count;
- for(i = 0; i < count; i++) {
- blocks[i].dwBufferLength = size;
- blocks[i].lpData = (LPSTR)buffer;
- blocks[i].dwBytesRecorded=0;
- blocks[i].dwUser = 0L;
- blocks[i].dwFlags = 0L;
- blocks[i].dwLoops = 0L;
- result = waveInPrepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR));
- if(result != MMSYSERR_NOERROR) {
- qWarning("QAudioSource: Can't prepare block %d",i);
- return 0;
- }
- buffer += size;
- }
- return blocks;
-}
-
-void QWindowsAudioSource::freeBlocks(WAVEHDR* blockArray)
-{
- WAVEHDR* blocks = blockArray;
-
- int count = buffer_size/period_size;
-
- for(int i = 0; i < count; i++) {
- waveInUnprepareHeader(hWaveIn,blocks, sizeof(WAVEHDR));
- blocks++;
- }
- HeapFree(GetProcessHeap(), 0, blockArray);
-}
-
-QAudio::Error QWindowsAudioSource::error() const
-{
- return errorState;
-}
-
-QAudio::State QWindowsAudioSource::state() const
-{
- return deviceState;
-}
-
-#ifndef DRVM_MAPPER_CONSOLEVOICECOM_GET
- #ifndef DRVM_MAPPER
- #define DRVM_MAPPER 0x2000
- #endif
- #ifndef DRVM_MAPPER_STATUS
- #define DRVM_MAPPER_STATUS (DRVM_MAPPER+0)
- #endif
- #define DRVM_USER 0x4000
- #define DRVM_MAPPER_RECONFIGURE (DRVM_MAPPER+1)
- #define DRVM_MAPPER_PREFERRED_GET (DRVM_MAPPER+21)
- #define DRVM_MAPPER_CONSOLEVOICECOM_GET (DRVM_MAPPER+23)
-#endif
-
-void QWindowsAudioSource::setVolume(qreal volume)
-{
- cachedVolume = volume;
- for (DWORD i = 0; i < mixerLineControls.cControls; i++) {
-
- MIXERCONTROLDETAILS controlDetails;
- controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
- controlDetails.dwControlID = mixerLineControls.pamxctrl[i].dwControlID;
- controlDetails.cChannels = 1;
-
- if ((mixerLineControls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_FADER) ||
- (mixerLineControls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)) {
- MIXERCONTROLDETAILS_UNSIGNED controlDetailsUnsigned;
- controlDetailsUnsigned.dwValue = qBound(DWORD(0), DWORD(65535.0 * volume + 0.5), DWORD(65535));
- controlDetails.cMultipleItems = 0;
- controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
- controlDetails.paDetails = &controlDetailsUnsigned;
- mixerSetControlDetails(mixerID, &controlDetails, MIXER_SETCONTROLDETAILSF_VALUE);
- }
- }
-}
-
-qreal QWindowsAudioSource::volume() const
-{
- for (DWORD i = 0; i < mixerLineControls.cControls; i++) {
- if ((mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_FADER) &&
- (mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_VOLUME)) {
- continue;
- }
-
- MIXERCONTROLDETAILS controlDetails;
- controlDetails.cbStruct = sizeof(controlDetails);
- controlDetails.dwControlID = mixerLineControls.pamxctrl[i].dwControlID;
- controlDetails.cChannels = 1;
- controlDetails.cMultipleItems = 0;
- controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
- MIXERCONTROLDETAILS_UNSIGNED detailsUnsigned;
- controlDetails.paDetails = &detailsUnsigned;
- memset(controlDetails.paDetails, 0, controlDetails.cbDetails);
-
- MMRESULT result = mixerGetControlDetails(mixerID, &controlDetails, MIXER_GETCONTROLDETAILSF_VALUE);
- if (result != MMSYSERR_NOERROR)
- continue;
- if (controlDetails.cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED))
- continue;
- return detailsUnsigned.dwValue / 65535.0;
- }
-
- return qFuzzyCompare(cachedVolume, qreal(-1.0f)) ? 1.0f : cachedVolume;
-}
-
-void QWindowsAudioSource::setFormat(const QAudioFormat& fmt)
-{
- if (deviceState == QAudio::StoppedState)
- settings = fmt;
-}
-
-QAudioFormat QWindowsAudioSource::format() const
-{
- return settings;
-}
-
-void QWindowsAudioSource::start(QIODevice* device)
-{
- if(deviceState != QAudio::StoppedState)
- close();
-
- if(!pullMode && audioSource)
- delete audioSource;
-
- pullMode = true;
- audioSource = device;
-
- deviceState = QAudio::ActiveState;
-
- if(!open())
- return;
-
- emit stateChanged(deviceState);
-}
-
-QIODevice* QWindowsAudioSource::start()
-{
- if(deviceState != QAudio::StoppedState)
- close();
-
- if(!pullMode && audioSource)
- delete audioSource;
-
- pullMode = false;
- audioSource = new InputPrivate(this);
- audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
-
- deviceState = QAudio::IdleState;
-
- if(!open())
- return 0;
-
- emit stateChanged(deviceState);
-
- return audioSource;
-}
-
-void QWindowsAudioSource::stop()
-{
- if(deviceState == QAudio::StoppedState)
- return;
-
- close();
- emit stateChanged(deviceState);
-}
-
-bool QWindowsAudioSource::open()
-{
-#ifdef DEBUG_AUDIO
- QTime now(QTime::currentTime());
- qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
-#endif
- header = 0;
-
- period_size = 0;
-
- if (!qt_convertFormat(settings, &wfx)) {
- qWarning("QAudioSource: open error, invalid format.");
- } else if (buffer_size == 0) {
- buffer_size
- = (settings.sampleRate()
- * settings.channelCount()
- * settings.bytesPerSample()
- + 39) / 5;
- period_size = buffer_size / 5;
- } else {
- period_size = buffer_size / 5;
- }
-
- if (period_size == 0) {
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- return false;
- }
-
- elapsedTimeOffset = 0;
-
- if (waveInOpen(&hWaveIn, UINT_PTR(m_deviceId), &wfx.Format,
- (DWORD_PTR)&waveInProc,
- (DWORD_PTR) this,
- CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- qWarning("QAudioSource: failed to open audio device");
- return false;
- }
- waveBlocks = allocateBlocks(period_size, buffer_size/period_size);
- waveBlockOffset = 0;
-
- if(waveBlocks == 0) {
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- qWarning("QAudioSource: failed to allocate blocks. open failed");
- return false;
- }
-
- mutex.lock();
- waveFreeBlockCount = buffer_size/period_size;
- mutex.unlock();
-
- for(int i=0; i<buffer_size/period_size; i++) {
- result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
- if(result != MMSYSERR_NOERROR) {
- qWarning("QAudioSource: failed to setup block %d,err=%d",i,result);
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- return false;
- }
- }
- result = waveInStart(hWaveIn);
- if(result) {
- qWarning("QAudioSource: failed to start audio input");
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- return false;
- }
- elapsedTimeOffset = 0;
- totalTimeValue = 0;
- errorState = QAudio::NoError;
- initMixer();
- return true;
-}
-
-void QWindowsAudioSource::close()
-{
- if(deviceState == QAudio::StoppedState)
- return;
-
- deviceState = QAudio::StoppedState;
- waveInReset(hWaveIn);
-
- mutex.lock();
- for (int i=0; i<waveFreeBlockCount; i++)
- waveInUnprepareHeader(hWaveIn,&waveBlocks[i],sizeof(WAVEHDR));
- freeBlocks(waveBlocks);
- mutex.unlock();
-
- waveInClose(hWaveIn);
- closeMixer();
-
- int count = 0;
- while(!finished && count < 500) {
- count++;
- Sleep(10);
- }
-}
-
-void QWindowsAudioSource::initMixer()
-{
- // Get the Mixer ID from the Sound Device ID
- UINT mixerIntID = 0;
- if (mixerGetID(reinterpret_cast<HMIXEROBJ>(hWaveIn),
- &mixerIntID, MIXER_OBJECTF_HWAVEIN) != MMSYSERR_NOERROR)
- return;
- mixerID = reinterpret_cast<HMIXEROBJ>(quintptr(mixerIntID));
-
- // Get the Destination (Recording) Line Information
- MIXERLINE mixerLine;
- mixerLine.cbStruct = sizeof(MIXERLINE);
- mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
- if (mixerGetLineInfo(mixerID, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR)
- return;
-
- // Set all the Destination (Recording) Line Controls
- if (mixerLine.cControls > 0) {
- mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
- mixerLineControls.dwLineID = mixerLine.dwLineID;
- mixerLineControls.cControls = mixerLine.cControls;
- mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
- mixerLineControls.pamxctrl = new MIXERCONTROL[mixerLineControls.cControls];
- if (mixerGetLineControls(mixerID, &mixerLineControls, MIXER_GETLINECONTROLSF_ALL) != MMSYSERR_NOERROR)
- closeMixer();
- else if (!qFuzzyCompare(cachedVolume, qreal(-1.0f)))
- setVolume(cachedVolume);
- }
-}
-
-void QWindowsAudioSource::closeMixer()
-{
- delete[] mixerLineControls.pamxctrl;
- memset(&mixerLineControls, 0, sizeof(mixerLineControls));
-}
-
-qsizetype QWindowsAudioSource::bytesReady() const
-{
- if (period_size == 0 || buffer_size == 0)
- return 0;
- if (deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState)
- return 0;
-
- int buf = ((buffer_size/period_size)-waveFreeBlockCount)*period_size;
- if(buf < 0)
- buf = 0;
- return buf;
-}
-
-qint64 QWindowsAudioSource::read(char* data, qint64 len)
-{
- bool done = false;
-
- char* p = data;
- qint64 l = 0;
- qint64 written = 0;
- while(!done) {
- // Read in some audio data
- if(waveBlocks[header].dwBytesRecorded > 0 && waveBlocks[header].dwFlags & WHDR_DONE) {
- if(pullMode) {
- l = audioSource->write(waveBlocks[header].lpData + waveBlockOffset,
- waveBlocks[header].dwBytesRecorded - waveBlockOffset);
-#ifdef DEBUG_AUDIO
- qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l;
-#endif
- if(l < 0) {
- // error
- qWarning("QAudioSource: IOError");
- errorState = QAudio::IOError;
-
- } else if(l == 0) {
- // cant write to IODevice
- qWarning("QAudioSource: IOError, can't write to QIODevice");
- errorState = QAudio::IOError;
-
- } else {
- totalTimeValue += l;
- errorState = QAudio::NoError;
- if (deviceState != QAudio::ActiveState) {
- deviceState = QAudio::ActiveState;
- emit stateChanged(deviceState);
- }
- resuming = false;
- }
- } else {
- l = qMin<qint64>(len, waveBlocks[header].dwBytesRecorded - waveBlockOffset);
- // push mode
- memcpy(p, waveBlocks[header].lpData + waveBlockOffset, l);
-
- len -= l;
-
-#ifdef DEBUG_AUDIO
- qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l;
-#endif
- totalTimeValue += l;
- errorState = QAudio::NoError;
- if (deviceState != QAudio::ActiveState) {
- deviceState = QAudio::ActiveState;
- emit stateChanged(deviceState);
- }
- resuming = false;
- }
- } else {
- //no data, not ready yet, next time
- break;
- }
-
- if (l < waveBlocks[header].dwBytesRecorded - waveBlockOffset) {
- waveBlockOffset += l;
- done = true;
- } else {
- waveBlockOffset = 0;
-
- waveInUnprepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
-
- mutex.lock();
- waveFreeBlockCount++;
- mutex.unlock();
-
- waveBlocks[header].dwBytesRecorded=0;
- waveBlocks[header].dwFlags = 0L;
- result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
- if(result != MMSYSERR_NOERROR) {
- result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
- qWarning("QAudioSource: failed to prepare block %d,err=%d",header,result);
- errorState = QAudio::IOError;
-
- mutex.lock();
- waveFreeBlockCount--;
- mutex.unlock();
-
- return 0;
- }
- result = waveInAddBuffer(hWaveIn, &waveBlocks[header], sizeof(WAVEHDR));
- if(result != MMSYSERR_NOERROR) {
- qWarning("QAudioSource: failed to setup block %d,err=%d",header,result);
- errorState = QAudio::IOError;
-
- mutex.lock();
- waveFreeBlockCount--;
- mutex.unlock();
-
- return 0;
- }
- header++;
- if(header >= buffer_size/period_size)
- header = 0;
- p+=l;
-
- mutex.lock();
- if(!pullMode) {
- if(len < period_size || waveFreeBlockCount == buffer_size/period_size)
- done = true;
- } else {
- if(waveFreeBlockCount == buffer_size/period_size)
- done = true;
- }
- mutex.unlock();
- }
-
- written+=l;
- }
-#ifdef DEBUG_AUDIO
- qDebug()<<"read in len="<<written;
-#endif
- return written;
-}
-
-void QWindowsAudioSource::resume()
-{
- if (deviceState == QAudio::SuspendedState) {
- deviceState = QAudio::ActiveState;
- for(int i=0; i<buffer_size/period_size; i++) {
- result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
- if(result != MMSYSERR_NOERROR) {
- qWarning("QAudioSource: failed to setup block %d,err=%d",i,result);
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- return;
- }
- }
-
- mutex.lock();
- waveFreeBlockCount = buffer_size/period_size;
- mutex.unlock();
-
- header = 0;
- resuming = true;
- waveBlockOffset = 0;
- waveInStart(hWaveIn);
- QTimer::singleShot(20,this,SLOT(feedback()));
- emit stateChanged(deviceState);
- }
-}
-
-void QWindowsAudioSource::setBufferSize(qsizetype value)
-{
- buffer_size = value;
-}
-
-qsizetype QWindowsAudioSource::bufferSize() const
-{
- return buffer_size;
-}
-
-qint64 QWindowsAudioSource::processedUSecs() const
-{
- if (deviceState == QAudio::StoppedState)
- return 0;
- qint64 result = qint64(1000000) * totalTimeValue /
- settings.bytesPerFrame() / settings.sampleRate();
-
- return result;
-}
-
-void QWindowsAudioSource::suspend()
-{
- if(deviceState == QAudio::ActiveState) {
- deviceState = QAudio::SuspendedState;
- waveInReset(hWaveIn);
- emit stateChanged(deviceState);
- }
-}
-
-void QWindowsAudioSource::feedback()
-{
-#ifdef DEBUG_AUDIO
- QTime now(QTime::currentTime());
- qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback() INPUT "<<this;
-#endif
- if(deviceState != QAudio::StoppedState && deviceState != QAudio::SuspendedState)
- QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection);
-}
-
-bool QWindowsAudioSource::deviceReady()
-{
- bytesAvailable = bytesReady();
-#ifdef DEBUG_AUDIO
- QTime now(QTime::currentTime());
- qDebug()<<now.second()<<"s "<<now.msec()<<"ms :deviceReady() INPUT" << bytesReady();
-#endif
- if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
- return true;
-
- if(pullMode) {
- // reads some audio data and writes it to QIODevice
- read(0, buffer_size);
- } else {
- // emits readyRead() so user will call read() on QIODevice to get some audio data
- InputPrivate* a = qobject_cast<InputPrivate*>(audioSource);
- a->trigger();
- }
-
- return true;
-}
-
-void QWindowsAudioSource::reset()
-{
- stop();
- if (period_size > 0)
- waveFreeBlockCount = buffer_size / period_size;
-}
-
-InputPrivate::InputPrivate(QWindowsAudioSource* audio)
-{
- audioDevice = qobject_cast<QWindowsAudioSource*>(audio);
-}
-
-InputPrivate::~InputPrivate() {}
-
-qint64 InputPrivate::readData( char* data, qint64 len)
-{
- // push mode, user read() called
- if(audioDevice->deviceState != QAudio::ActiveState &&
- audioDevice->deviceState != QAudio::IdleState)
- return 0;
- // Read in some audio data
- return audioDevice->read(data,len);
-}
-
-qint64 InputPrivate::writeData(const char* data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- emit readyRead();
- return 0;
-}
-
-void InputPrivate::trigger()
-{
- emit readyRead();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qwindowsaudiosource_p.cpp"
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudiosource_p.h b/src/multimedia/platform/windows/audio/qwindowsaudiosource_p.h
deleted file mode 100644
index ff68daab6..000000000
--- a/src/multimedia/platform/windows/audio/qwindowsaudiosource_p.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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 QWINDOWSAUDIOINPUT_H
-#define QWINDOWSAUDIOINPUT_H
-
-#include "qwindowsaudioutils_p.h"
-
-#include <QtCore/qfile.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmutex.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qaudiodevice.h>
-#include <private/qaudiosystem_p.h>
-
-
-QT_BEGIN_NAMESPACE
-
-
-// For compat with 4.6
-#if !defined(QT_WIN_CALLBACK)
-# if defined(Q_CC_MINGW)
-# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer))
-# else
-# define QT_WIN_CALLBACK CALLBACK
-# endif
-#endif
-
-class QWindowsAudioSource : public QPlatformAudioSource
-{
- Q_OBJECT
-public:
- QWindowsAudioSource(int deviceId);
- ~QWindowsAudioSource();
-
- qint64 read(char* data, qint64 len);
-
- void setFormat(const QAudioFormat& fmt);
- QAudioFormat format() const;
- QIODevice* start();
- void start(QIODevice* device);
- void stop();
- void reset();
- void suspend();
- void resume();
- qsizetype bytesReady() const;
- void setBufferSize(qsizetype value);
- qsizetype bufferSize() const;
- qint64 processedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
- void setVolume(qreal volume);
- qreal volume() const;
-
- QIODevice* audioSource;
- QAudioFormat settings;
- QAudio::Error errorState;
- QAudio::State deviceState;
-
-private:
- qint32 buffer_size;
- qint32 period_size;
- qint32 header;
- int m_deviceId;
- int bytesAvailable;
- qint64 elapsedTimeOffset;
- qint64 totalTimeValue;
- bool pullMode;
- bool resuming;
- WAVEFORMATEXTENSIBLE wfx;
- HWAVEIN hWaveIn;
- MMRESULT result;
- WAVEHDR* waveBlocks;
- volatile bool finished;
- volatile int waveFreeBlockCount;
- int waveBlockOffset;
-
- QMutex mutex;
- static void QT_WIN_CALLBACK waveInProc( HWAVEIN hWaveIn, UINT uMsg,
- DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 );
-
- WAVEHDR* allocateBlocks(int size, int count);
- void freeBlocks(WAVEHDR* blockArray);
- bool open();
- void close();
-
- void initMixer();
- void closeMixer();
- HMIXEROBJ mixerID;
- MIXERLINECONTROLS mixerLineControls;
- qreal cachedVolume;
-
-private slots:
- void feedback();
- bool deviceReady();
-
-signals:
- void processMore();
-};
-
-class InputPrivate : public QIODevice
-{
- Q_OBJECT
-public:
- InputPrivate(QWindowsAudioSource* audio);
- ~InputPrivate();
-
- qint64 readData( char* data, qint64 len);
- qint64 writeData(const char* data, qint64 len);
-
- void trigger();
-private:
- QWindowsAudioSource *audioDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudioutils.cpp b/src/multimedia/platform/windows/audio/qwindowsaudioutils.cpp
deleted file mode 100644
index 69e50a9a6..000000000
--- a/src/multimedia/platform/windows/audio/qwindowsaudioutils.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsaudioutils_p.h"
-
-#ifndef SPEAKER_FRONT_LEFT
- #define SPEAKER_FRONT_LEFT 0x00000001
- #define SPEAKER_FRONT_RIGHT 0x00000002
- #define SPEAKER_FRONT_CENTER 0x00000004
- #define SPEAKER_LOW_FREQUENCY 0x00000008
- #define SPEAKER_BACK_LEFT 0x00000010
- #define SPEAKER_BACK_RIGHT 0x00000020
- #define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
- #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
- #define SPEAKER_BACK_CENTER 0x00000100
- #define SPEAKER_SIDE_LEFT 0x00000200
- #define SPEAKER_SIDE_RIGHT 0x00000400
- #define SPEAKER_TOP_CENTER 0x00000800
- #define SPEAKER_TOP_FRONT_LEFT 0x00001000
- #define SPEAKER_TOP_FRONT_CENTER 0x00002000
- #define SPEAKER_TOP_FRONT_RIGHT 0x00004000
- #define SPEAKER_TOP_BACK_LEFT 0x00008000
- #define SPEAKER_TOP_BACK_CENTER 0x00010000
- #define SPEAKER_TOP_BACK_RIGHT 0x00020000
- #define SPEAKER_RESERVED 0x7FFC0000
- #define SPEAKER_ALL 0x80000000
-#endif
-
-#ifndef WAVE_FORMAT_EXTENSIBLE
- #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
-#endif
-
-#ifndef WAVE_FORMAT_IEEE_FLOAT
- #define WAVE_FORMAT_IEEE_FLOAT 0x0003
-#endif
-
-static const GUID _KSDATAFORMAT_SUBTYPE_PCM = {
- 0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
-
-static const GUID _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {
- 0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
-
-QT_BEGIN_NAMESPACE
-
-bool qt_convertFormat(const QAudioFormat &format, WAVEFORMATEXTENSIBLE *wfx)
-{
- if (!wfx
- || !format.isValid()
- || format.sampleRate() <= 0
- || format.channelCount() <= 0) {
- return false;
- }
-
- wfx->Format.nSamplesPerSec = format.sampleRate();
- wfx->Format.wBitsPerSample = wfx->Samples.wValidBitsPerSample = format.bytesPerSample()*8;
- wfx->Format.nChannels = format.channelCount();
- wfx->Format.nBlockAlign = (wfx->Format.wBitsPerSample / 8) * wfx->Format.nChannels;
- wfx->Format.nAvgBytesPerSec = wfx->Format.nBlockAlign * wfx->Format.nSamplesPerSec;
- wfx->Format.cbSize = 0;
-
- if (format.sampleFormat() == QAudioFormat::Float) {
- wfx->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- wfx->SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
- } else {
- wfx->Format.wFormatTag = WAVE_FORMAT_PCM;
- wfx->SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
- }
-
- if (format.channelCount() > 2) {
- wfx->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- wfx->Format.cbSize = 22;
- wfx->dwChannelMask = 0xFFFFFFFF >> (32 - format.channelCount());
- }
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudioutils_p.h b/src/multimedia/platform/windows/audio/qwindowsaudioutils_p.h
deleted file mode 100644
index 15bd50b2b..000000000
--- a/src/multimedia/platform/windows/audio/qwindowsaudioutils_p.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSAUDIOUTILS_H
-#define QWINDOWSAUDIOUTILS_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 <qaudioformat.h>
-#include <QtCore/qt_windows.h>
-#include <mmsystem.h>
-
-#ifndef _WAVEFORMATEXTENSIBLE_
-
- #define _WAVEFORMATEXTENSIBLE_
- typedef struct
- {
- WAVEFORMATEX Format; // Base WAVEFORMATEX data
- union
- {
- WORD wValidBitsPerSample; // Valid bits in each sample container
- WORD wSamplesPerBlock; // Samples per block of audio data; valid
- // if wBitsPerSample=0 (but rarely used).
- WORD wReserved; // Zero if neither case above applies.
- } Samples;
- DWORD dwChannelMask; // Positions of the audio channels
- GUID SubFormat; // Format identifier GUID
- } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE;
- typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE;
-
-#endif
-
-#if defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR)
-struct IBaseFilter; // Needed for strmif.h from stock MinGW.
-struct _DDPIXELFORMAT;
-typedef struct _DDPIXELFORMAT* LPDDPIXELFORMAT;
-#endif
-
-#include <strmif.h>
-#if !defined(Q_CC_MINGW) || defined(__MINGW64_VERSION_MAJOR)
-# include <uuids.h>
-#else
-
-extern GUID CLSID_AudioInputDeviceCategory;
-extern GUID CLSID_AudioRendererCategory;
-extern GUID IID_ICreateDevEnum;
-extern GUID CLSID_SystemDeviceEnum;
-
-#ifndef __ICreateDevEnum_INTERFACE_DEFINED__
-#define __ICreateDevEnum_INTERFACE_DEFINED__
-
-DECLARE_INTERFACE_(ICreateDevEnum, IUnknown)
-{
- STDMETHOD(CreateClassEnumerator)(REFCLSID clsidDeviceClass,
- IEnumMoniker **ppEnumMoniker,
- DWORD dwFlags) PURE;
-};
-
-#endif // __ICreateDevEnum_INTERFACE_DEFINED__
-
-#ifndef __IErrorLog_INTERFACE_DEFINED__
-#define __IErrorLog_INTERFACE_DEFINED__
-
-DECLARE_INTERFACE_(IErrorLog, IUnknown)
-{
- STDMETHOD(AddError)(THIS_ LPCOLESTR, EXCEPINFO *) PURE;
-};
-
-#endif /* __IErrorLog_INTERFACE_DEFINED__ */
-
-#ifndef __IPropertyBag_INTERFACE_DEFINED__
-#define __IPropertyBag_INTERFACE_DEFINED__
-
-const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
-
-DECLARE_INTERFACE_(IPropertyBag, IUnknown)
-{
- STDMETHOD(Read)(THIS_ LPCOLESTR, VARIANT *, IErrorLog *) PURE;
- STDMETHOD(Write)(THIS_ LPCOLESTR, VARIANT *) PURE;
-};
-
-#endif /* __IPropertyBag_INTERFACE_DEFINED__ */
-
-#endif // defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR)
-
-// For mingw toolchain mmsystem.h only defines half the defines, so add if needed.
-#ifndef WAVE_FORMAT_44M08
-#define WAVE_FORMAT_44M08 0x00000100
-#define WAVE_FORMAT_44S08 0x00000200
-#define WAVE_FORMAT_44M16 0x00000400
-#define WAVE_FORMAT_44S16 0x00000800
-#define WAVE_FORMAT_48M08 0x00001000
-#define WAVE_FORMAT_48S08 0x00002000
-#define WAVE_FORMAT_48M16 0x00004000
-#define WAVE_FORMAT_48S16 0x00008000
-#define WAVE_FORMAT_96M08 0x00010000
-#define WAVE_FORMAT_96S08 0x00020000
-#define WAVE_FORMAT_96M16 0x00040000
-#define WAVE_FORMAT_96S16 0x00080000
-#endif
-
-QT_BEGIN_NAMESPACE
-
-bool qt_convertFormat(const QAudioFormat &format, WAVEFORMATEXTENSIBLE *wfx);
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSAUDIOUTILS_H
diff --git a/src/multimedia/platform/windows/common/mfmetadata.cpp b/src/multimedia/platform/windows/common/mfmetadata.cpp
deleted file mode 100644
index ebc884759..000000000
--- a/src/multimedia/platform/windows/common/mfmetadata.cpp
+++ /dev/null
@@ -1,521 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <qmediametadata.h>
-#include <qdatetime.h>
-#include <qimage.h>
-#include <quuid.h>
-
-#include <mfapi.h>
-#include <mfidl.h>
-#include <propvarutil.h>
-#include <propkey.h>
-
-#include "qwindowsmultimediautils_p.h"
-#include "mfmetadata_p.h"
-
-//#define DEBUG_MEDIAFOUNDATION
-
-static QString nameForGUID(GUID guid)
-{
- // Audio formats
- if (guid == MFAudioFormat_AAC)
- return QStringLiteral("MPEG AAC Audio");
- else if (guid == MFAudioFormat_ADTS)
- return QStringLiteral("MPEG ADTS AAC Audio");
- else if (guid == MFAudioFormat_Dolby_AC3_SPDIF)
- return QStringLiteral("Dolby AC-3 SPDIF");
- else if (guid == MFAudioFormat_DRM)
- return QStringLiteral("DRM");
- else if (guid == MFAudioFormat_DTS)
- return QStringLiteral("Digital Theater Systems Audio (DTS)");
- else if (guid == MFAudioFormat_Float)
- return QStringLiteral("IEEE Float Audio");
- else if (guid == MFAudioFormat_MP3)
- return QStringLiteral("MPEG Audio Layer-3 (MP3)");
- else if (guid == MFAudioFormat_MPEG)
- return QStringLiteral("MPEG-1 Audio");
- else if (guid == MFAudioFormat_MSP1)
- return QStringLiteral("Windows Media Audio Voice");
- else if (guid == MFAudioFormat_PCM)
- return QStringLiteral("Uncompressed PCM Audio");
- else if (guid == MFAudioFormat_WMASPDIF)
- return QStringLiteral("Windows Media Audio 9 SPDIF");
- else if (guid == MFAudioFormat_WMAudioV8)
- return QStringLiteral("Windows Media Audio 8 (WMA2)");
- else if (guid == MFAudioFormat_WMAudioV9)
- return QStringLiteral("Windows Media Audio 9 (WMA3");
- else if (guid == MFAudioFormat_WMAudio_Lossless)
- return QStringLiteral("Windows Media Audio 9 Lossless");
-
- // Video formats
- if (guid == MFVideoFormat_DV25)
- return QStringLiteral("DVCPRO 25 (DV25)");
- else if (guid == MFVideoFormat_DV50)
- return QStringLiteral("DVCPRO 50 (DV50)");
- else if (guid == MFVideoFormat_DVC)
- return QStringLiteral("DVC/DV Video");
- else if (guid == MFVideoFormat_DVH1)
- return QStringLiteral("DVCPRO 100 (DVH1)");
- else if (guid == MFVideoFormat_DVHD)
- return QStringLiteral("HD-DVCR (DVHD)");
- else if (guid == MFVideoFormat_DVSD)
- return QStringLiteral("SDL-DVCR (DVSD)");
- else if (guid == MFVideoFormat_DVSL)
- return QStringLiteral("SD-DVCR (DVSL)");
- else if (guid == MFVideoFormat_H264)
- return QStringLiteral("H.264 Video");
- else if (guid == MFVideoFormat_M4S2)
- return QStringLiteral("MPEG-4 part 2 Video (M4S2)");
- else if (guid == MFVideoFormat_MJPG)
- return QStringLiteral("Motion JPEG (MJPG)");
- else if (guid == MFVideoFormat_MP43)
- return QStringLiteral("Microsoft MPEG 4 version 3 (MP43)");
- else if (guid == MFVideoFormat_MP4S)
- return QStringLiteral("ISO MPEG 4 version 1 (MP4S)");
- else if (guid == MFVideoFormat_MP4V)
- return QStringLiteral("MPEG-4 part 2 Video (MP4V)");
- else if (guid == MFVideoFormat_MPEG2)
- return QStringLiteral("MPEG-2 Video");
- else if (guid == MFVideoFormat_MPG1)
- return QStringLiteral("MPEG-1 Video");
- else if (guid == MFVideoFormat_MSS1)
- return QStringLiteral("Windows Media Screen 1 (MSS1)");
- else if (guid == MFVideoFormat_MSS2)
- return QStringLiteral("Windows Media Video 9 Screen (MSS2)");
- else if (guid == MFVideoFormat_WMV1)
- return QStringLiteral("Windows Media Video 7 (WMV1)");
- else if (guid == MFVideoFormat_WMV2)
- return QStringLiteral("Windows Media Video 8 (WMV2)");
- else if (guid == MFVideoFormat_WMV3)
- return QStringLiteral("Windows Media Video 9 (WMV3)");
- else if (guid == MFVideoFormat_WVC1)
- return QStringLiteral("Windows Media Video VC1 (WVC1)");
-
- else
- return QStringLiteral("Unknown codec");
-}
-
-static QVariant convertValue(const PROPVARIANT& var)
-{
- QVariant value;
- switch (var.vt) {
- case VT_LPWSTR:
- value = QString::fromUtf16(reinterpret_cast<const char16_t *>(var.pwszVal));
- break;
- case VT_UI4:
- value = uint(var.ulVal);
- break;
- case VT_UI8:
- value = qulonglong(var.uhVal.QuadPart);
- break;
- case VT_BOOL:
- value = bool(var.boolVal);
- break;
- case VT_FILETIME:
- SYSTEMTIME t;
- if (!FileTimeToSystemTime(&var.filetime, &t))
- break;
-
- value = QDateTime(QDate(t.wYear, t.wMonth, t.wDay),
- QTime(t.wHour, t.wMinute, t.wSecond, t.wMilliseconds),
- Qt::UTC);
- break;
- case VT_STREAM:
- {
- STATSTG stat;
- if (FAILED(var.pStream->Stat(&stat, STATFLAG_NONAME)))
- break;
- void *data = malloc(stat.cbSize.QuadPart);
- ULONG read = 0;
- if (FAILED(var.pStream->Read(data, stat.cbSize.QuadPart, &read))) {
- free(data);
- break;
- }
- value = QImage::fromData((const uchar*)data, read);
- free(data);
- }
- break;
- case VT_VECTOR | VT_LPWSTR:
- QStringList vList;
- for (ULONG i = 0; i < var.calpwstr.cElems; ++i)
- vList.append(QString::fromUtf16(reinterpret_cast<const char16_t *>(var.calpwstr.pElems[i])));
- value = vList;
- break;
- }
- return value;
-}
-
-static QVariant metaDataValue(IPropertyStore *content, const PROPERTYKEY &key)
-{
- QVariant value;
-
- PROPVARIANT var;
- PropVariantInit(&var);
- HRESULT hr = S_FALSE;
- if (content)
- hr = content->GetValue(key, &var);
-
- if (SUCCEEDED(hr)) {
- value = convertValue(var);
-
- // some metadata needs to be reformatted
- if (value.isValid() && content) {
- if (key == PKEY_Media_ClassPrimaryID /*QMediaMetaData::MediaType*/) {
- QString v = value.toString();
- if (v == QLatin1String("{D1607DBC-E323-4BE2-86A1-48A42A28441E}"))
- value = QStringLiteral("Music");
- else if (v == QLatin1String("{DB9830BD-3AB3-4FAB-8A37-1A995F7FF74B}"))
- value = QStringLiteral("Video");
- else if (v == QLatin1String("{01CD0F29-DA4E-4157-897B-6275D50C4F11}"))
- value = QStringLiteral("Audio");
- else if (v == QLatin1String("{FCF24A76-9A57-4036-990D-E35DD8B244E1}"))
- value = QStringLiteral("Other");
- } else if (key == PKEY_Media_Duration) {
- // duration is provided in 100-nanosecond units, convert to milliseconds
- value = (value.toLongLong() + 10000) / 10000;
- } else if (key == PKEY_Video_Compression) {
- value = int(QWindowsMultimediaUtils::codecForVideoFormat(value.toUuid()));
- } else if (key == PKEY_Audio_Format) {
- value = int(QWindowsMultimediaUtils::codecForAudioFormat(value.toUuid()));
- } else if (key == PKEY_Video_FrameHeight /*Resolution*/) {
- QSize res;
- res.setHeight(value.toUInt());
- if (content && SUCCEEDED(content->GetValue(PKEY_Video_FrameWidth, &var)))
- res.setWidth(convertValue(var).toUInt());
- value = res;
- } else if (key == PKEY_Video_Orientation) {
- uint orientation = 0;
- if (content && SUCCEEDED(content->GetValue(PKEY_Video_Orientation, &var)))
- orientation = convertValue(var).toUInt();
- value = orientation;
- } else if (key == PKEY_Video_FrameRate) {
- value = value.toReal() / 1000.f;
- }
- }
- }
-
- PropVariantClear(&var);
- return value;
-}
-
-QMediaMetaData MFMetaData::fromNative(IMFMediaSource* mediaSource)
-{
- QMediaMetaData metaData;
-
- IPropertyStore *content = nullptr;
- if (!SUCCEEDED(MFGetService(mediaSource, MF_PROPERTY_HANDLER_SERVICE, IID_PPV_ARGS(&content))))
- return metaData;
-
- Q_ASSERT(content);
- DWORD cProps;
- if (SUCCEEDED(content->GetCount(&cProps))) {
- for (DWORD i = 0; i < cProps; i++)
- {
- PROPERTYKEY key;
- if (FAILED(content->GetAt(i, &key)))
- continue;
- QMediaMetaData::Key mediaKey;
- if (key == PKEY_Author) {
- mediaKey = QMediaMetaData::Author;
- } else if (key == PKEY_Title) {
- mediaKey = QMediaMetaData::Title;
-// } else if (key == PKEY_Media_SubTitle) {
-// mediaKey = QMediaMetaData::SubTitle;
-// } else if (key == PKEY_ParentalRating) {
-// mediaKey = QMediaMetaData::ParentalRating;
- } else if (key == PKEY_Media_EncodingSettings) {
- mediaKey = QMediaMetaData::Description;
- } else if (key == PKEY_Copyright) {
- mediaKey = QMediaMetaData::Copyright;
- } else if (key == PKEY_Comment) {
- mediaKey = QMediaMetaData::Comment;
- } else if (key == PKEY_Media_ProviderStyle) {
- mediaKey = QMediaMetaData::Genre;
- } else if (key == PKEY_Media_DateEncoded) {
- mediaKey = QMediaMetaData::Date;
-// } else if (key == PKEY_Rating) {
-// mediaKey = QMediaMetaData::UserRating;
-// } else if (key == PKEY_Keywords) {
-// mediaKey = QMediaMetaData::Keywords;
- } else if (key == PKEY_Language) {
- mediaKey = QMediaMetaData::Language;
- } else if (key == PKEY_Media_Publisher) {
- mediaKey = QMediaMetaData::Publisher;
- } else if (key == PKEY_Media_ClassPrimaryID) {
- mediaKey = QMediaMetaData::MediaType;
- } else if (key == PKEY_Media_Duration) {
- mediaKey = QMediaMetaData::Duration;
- } else if (key == PKEY_Audio_EncodingBitrate) {
- mediaKey = QMediaMetaData::AudioBitRate;
- } else if (key == PKEY_Audio_Format) {
- mediaKey = QMediaMetaData::AudioCodec;
-// } else if (key == PKEY_Media_AverageLevel) {
-// mediaKey = QMediaMetaData::AverageLevel;
-// } else if (key == PKEY_Audio_ChannelCount) {
-// mediaKey = QMediaMetaData::ChannelCount;
-// } else if (key == PKEY_Audio_PeakValue) {
-// mediaKey = QMediaMetaData::PeakValue;
-// } else if (key == PKEY_Audio_SampleRate) {
-// mediaKey = QMediaMetaData::SampleRate;
- } else if (key == PKEY_Music_AlbumTitle) {
- mediaKey = QMediaMetaData::AlbumTitle;
- } else if (key == PKEY_Music_AlbumArtist) {
- mediaKey = QMediaMetaData::AlbumArtist;
- } else if (key == PKEY_Music_Artist) {
- mediaKey = QMediaMetaData::ContributingArtist;
- } else if (key == PKEY_Music_Composer) {
- mediaKey = QMediaMetaData::Composer;
-// } else if (key == PKEY_Music_Conductor) {
-// mediaKey = QMediaMetaData::Conductor;
-// } else if (key == PKEY_Music_Lyrics) {
-// mediaKey = QMediaMetaData::Lyrics;
-// } else if (key == PKEY_Music_Mood) {
-// mediaKey = QMediaMetaData::Mood;
- } else if (key == PKEY_Music_TrackNumber) {
- mediaKey = QMediaMetaData::TrackNumber;
- } else if (key == PKEY_Music_Genre) {
- mediaKey = QMediaMetaData::Genre;
- } else if (key == PKEY_ThumbnailStream) {
- mediaKey = QMediaMetaData::ThumbnailImage;
- } else if (key == PKEY_Video_FrameHeight) {
- mediaKey = QMediaMetaData::Resolution;
- } else if (key == PKEY_Video_Orientation) {
- mediaKey = QMediaMetaData::Orientation;
-// } else if (key == PKEY_Video_FrameRate) {
-// mediaKey = QMediaMetaData::VideoFrameRate;
- } else if (key == PKEY_Video_EncodingBitrate) {
- mediaKey = QMediaMetaData::VideoBitRate;
- } else if (key == PKEY_Video_Compression) {
- mediaKey = QMediaMetaData::VideoCodec;
-// } else if (key == PKEY_Video_Director) {
-// mediaKey = QMediaMetaData::Director;
-// } else if (key == PKEY_Media_Writer) {
-// mediaKey = QMediaMetaData::Writer;
- } else {
- continue;
- }
- metaData.insert(mediaKey, metaDataValue(content, key));
- }
- }
-
- content->Release();
-
- return metaData;
-}
-
-static REFPROPERTYKEY propertyKeyForMetaDataKey(QMediaMetaData::Key key)
-{
- switch (key) {
- case QMediaMetaData::Key::Title:
- return PKEY_Title;
- case QMediaMetaData::Key::Author:
- return PKEY_Author;
- case QMediaMetaData::Key::Comment:
- return PKEY_Comment;
- case QMediaMetaData::Key::Genre:
- return PKEY_Music_Genre;
- case QMediaMetaData::Key::Copyright:
- return PKEY_Copyright;
- case QMediaMetaData::Key::Publisher:
- return PKEY_Media_Publisher;
- case QMediaMetaData::Key::Url:
- return PKEY_Media_AuthorUrl;
- case QMediaMetaData::Key::AlbumTitle:
- return PKEY_Music_AlbumTitle;
- case QMediaMetaData::Key::AlbumArtist:
- return PKEY_Music_AlbumArtist;
- case QMediaMetaData::Key::TrackNumber:
- return PKEY_Music_TrackNumber;
- case QMediaMetaData::Key::Date:
- return PKEY_Media_DateEncoded;
- case QMediaMetaData::Key::Composer:
- return PKEY_Music_Composer;
- case QMediaMetaData::Key::Duration:
- return PKEY_Media_Duration;
- case QMediaMetaData::Key::Language:
- return PKEY_Language;
- case QMediaMetaData::Key::Description:
- return PKEY_Media_EncodingSettings;
- case QMediaMetaData::Key::AudioBitRate:
- return PKEY_Audio_EncodingBitrate;
- case QMediaMetaData::Key::ContributingArtist:
- return PKEY_Music_Artist;
- case QMediaMetaData::Key::ThumbnailImage:
- return PKEY_ThumbnailStream;
- case QMediaMetaData::Key::Orientation:
- return PKEY_Video_Orientation;
- case QMediaMetaData::Key::VideoFrameRate:
- return PKEY_Video_FrameRate;
- case QMediaMetaData::Key::VideoBitRate:
- return PKEY_Video_EncodingBitrate;
- case QMediaMetaData::MediaType:
- return PKEY_Media_ClassPrimaryID;
- default:
- return PKEY_Null;
- }
-}
-
-static void setStringProperty(IPropertyStore *content, REFPROPERTYKEY key, const QString &value)
-{
- PROPVARIANT propValue = {};
- if (SUCCEEDED(InitPropVariantFromString(reinterpret_cast<LPCWSTR>(value.utf16()), &propValue))) {
- if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
- content->SetValue(key, propValue);
- PropVariantClear(&propValue);
- }
-}
-
-static void setUInt32Property(IPropertyStore *content, REFPROPERTYKEY key, quint32 value)
-{
- PROPVARIANT propValue = {};
- if (SUCCEEDED(InitPropVariantFromUInt32(ULONG(value), &propValue))) {
- if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
- content->SetValue(key, propValue);
- PropVariantClear(&propValue);
- }
-}
-
-static void setUInt64Property(IPropertyStore *content, REFPROPERTYKEY key, quint64 value)
-{
- PROPVARIANT propValue = {};
- if (SUCCEEDED(InitPropVariantFromUInt64(ULONGLONG(value), &propValue))) {
- if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
- content->SetValue(key, propValue);
- PropVariantClear(&propValue);
- }
-}
-
-static void setFileTimeProperty(IPropertyStore *content, REFPROPERTYKEY key, const FILETIME *ft)
-{
- PROPVARIANT propValue = {};
- if (SUCCEEDED(InitPropVariantFromFileTime(ft, &propValue))) {
- if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
- content->SetValue(key, propValue);
- PropVariantClear(&propValue);
- }
-}
-
-void MFMetaData::toNative(const QMediaMetaData &metaData, IPropertyStore *content)
-{
- if (content) {
-
- for (const auto &key : metaData.keys()) {
-
- QVariant value = metaData.value(key);
-
- if (key == QMediaMetaData::Key::MediaType) {
-
- QString strValue = metaData.stringValue(key);
- QString v;
-
- // Sets property to one of the MediaClassPrimaryID values defined by Microsoft:
- // https://docs.microsoft.com/en-us/windows/win32/wmformat/wm-mediaprimaryid
- if (strValue == QLatin1String("Music"))
- v = QLatin1String("{D1607DBC-E323-4BE2-86A1-48A42A28441E}");
- else if (strValue == QLatin1String("Video"))
- v = QLatin1String("{DB9830BD-3AB3-4FAB-8A37-1A995F7FF74B}");
- else if (strValue == QLatin1String("Audio"))
- v = QLatin1String("{01CD0F29-DA4E-4157-897B-6275D50C4F11}");
- else
- v = QLatin1String("{FCF24A76-9A57-4036-990D-E35DD8B244E1}");
-
- setStringProperty(content, PKEY_Media_ClassPrimaryID, v);
-
- } else if (key == QMediaMetaData::Key::Duration) {
-
- setUInt64Property(content, PKEY_Media_Duration, value.toULongLong() * 10000);
-
- } else if (key == QMediaMetaData::Key::Resolution) {
-
- QSize res = value.toSize();
- setUInt32Property(content, PKEY_Video_FrameWidth, quint32(res.width()));
- setUInt32Property(content, PKEY_Video_FrameHeight, quint32(res.height()));
-
- } else if (key == QMediaMetaData::Key::Orientation) {
-
- setUInt32Property(content, PKEY_Video_Orientation, value.toUInt());
-
- } else if (key == QMediaMetaData::Key::VideoFrameRate) {
-
- qreal fps = value.toReal();
- setUInt32Property(content, PKEY_Video_FrameRate, quint32(fps * 1000));
-
- } else if (key == QMediaMetaData::Key::TrackNumber) {
-
- setUInt32Property(content, PKEY_Music_TrackNumber, value.toUInt());
-
- } else if (key == QMediaMetaData::Key::AudioBitRate) {
-
- setUInt32Property(content, PKEY_Audio_EncodingBitrate, value.toUInt());
-
- } else if (key == QMediaMetaData::Key::VideoBitRate) {
-
- setUInt32Property(content, PKEY_Video_EncodingBitrate, value.toUInt());
-
- } else if (key == QMediaMetaData::Key::Date) {
-
- // Convert QDateTime to FILETIME by converting to 100-nsecs since
- // 01/01/1970 UTC and adding the difference from 1601 to 1970.
- ULARGE_INTEGER t = {};
- t.QuadPart = ULONGLONG(value.toDateTime().toUTC().toMSecsSinceEpoch() * 10000
- + 116444736000000000LL);
-
- FILETIME ft = {};
- ft.dwHighDateTime = t.HighPart;
- ft.dwLowDateTime = t.LowPart;
-
- setFileTimeProperty(content, PKEY_Media_DateEncoded, &ft);
-
- } else {
-
- // By default use as string and let PSCoerceToCanonicalValue()
- // do validation and type conversion.
- REFPROPERTYKEY propKey = propertyKeyForMetaDataKey(key);
-
- if (propKey != PKEY_Null) {
- QString strValue = metaData.stringValue(key);
- if (!strValue.isEmpty())
- setStringProperty(content, propKey, strValue);
- }
- }
- }
- }
-}
-
diff --git a/src/multimedia/platform/windows/common/mfmetadata_p.h b/src/multimedia/platform/windows/common/mfmetadata_p.h
deleted file mode 100644
index d1846e9c5..000000000
--- a/src/multimedia/platform/windows/common/mfmetadata_p.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFMETADATACONTROL_H
-#define MFMETADATACONTROL_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 <qmediametadata.h>
-#include "Mfidl.h"
-
-QT_USE_NAMESPACE
-
-class MFMetaData
-{
-public:
- static QMediaMetaData fromNative(IMFMediaSource* mediaSource);
- static void toNative(const QMediaMetaData &metaData, IPropertyStore *content);
-};
-
-#endif
diff --git a/src/multimedia/platform/windows/common/qwindowsiupointer_p.h b/src/multimedia/platform/windows/common/qwindowsiupointer_p.h
deleted file mode 100644
index a5c08ccc9..000000000
--- a/src/multimedia/platform/windows/common/qwindowsiupointer_p.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSIUPOINTER_H
-#define QWINDOWSIUPOINTER_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.
-//
-
-template <class T>
-class QWindowsIUPointer
-{
-public:
- explicit QWindowsIUPointer(T *ptr = nullptr) : m_ptr(ptr) {}
- QWindowsIUPointer(const QWindowsIUPointer<T> &uiPtr) : m_ptr(uiPtr.m_ptr) { if (m_ptr) m_ptr->AddRef(); }
- QWindowsIUPointer(QWindowsIUPointer<T> &&uiPtr) : m_ptr(uiPtr.m_ptr) { uiPtr.m_ptr = nullptr; }
- ~QWindowsIUPointer() { if (m_ptr) m_ptr->Release(); }
-
- QWindowsIUPointer& operator=(const QWindowsIUPointer<T> &rhs) {
- if (m_ptr)
- m_ptr->Release();
- m_ptr = rhs.m_ptr;
- m_ptr->AddRef();
- return *this;
- }
-
- QWindowsIUPointer& operator=(QWindowsIUPointer<T> &&rhs) noexcept {
- if (m_ptr)
- m_ptr->Release();
- m_ptr = rhs.m_ptr;
- rhs.m_ptr = nullptr;
- return *this;
- }
-
- explicit operator bool() const { return m_ptr != nullptr; }
- operator T*() const { return m_ptr; }
- T* operator->() const { return m_ptr; }
-
- T** address() { Q_ASSERT(m_ptr == nullptr); return &m_ptr; }
- void reset(T* ptr = nullptr) { if (m_ptr) m_ptr->Release(); m_ptr = ptr; }
-
-private:
- T* m_ptr;
-};
-
-#endif
diff --git a/src/multimedia/platform/windows/common/qwindowsmultimediautils_p.h b/src/multimedia/platform/windows/common/qwindowsmultimediautils_p.h
deleted file mode 100644
index 100059cf0..000000000
--- a/src/multimedia/platform/windows/common/qwindowsmultimediautils_p.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSMULTIMEDIATUTILS_P_H
-#define QWINDOWSMULTIMEDIATUTILS_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 <private/qtmultimediaglobal_p.h>
-#include <private/qplatformmediaformatinfo_p.h>
-#include <qvideoframeformat.h>
-#include <guiddef.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QWindowsMultimediaUtils {
-
- QVideoFrameFormat::PixelFormat pixelFormatFromMediaSubtype(const GUID &subtype);
-
- GUID videoFormatForCodec(QMediaFormat::VideoCodec codec);
-
- QMediaFormat::VideoCodec codecForVideoFormat(GUID format);
-
- GUID audioFormatForCodec(QMediaFormat::AudioCodec codec);
-
- QMediaFormat::AudioCodec codecForAudioFormat(GUID format);
-
- GUID containerForVideoFileFormat(QMediaFormat::FileFormat format);
-
- GUID containerForAudioFileFormat(QMediaFormat::FileFormat format);
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/windows/decoder/mfaudiodecodercontrol.cpp b/src/multimedia/platform/windows/decoder/mfaudiodecodercontrol.cpp
deleted file mode 100644
index de1311835..000000000
--- a/src/multimedia/platform/windows/decoder/mfaudiodecodercontrol.cpp
+++ /dev/null
@@ -1,454 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "Wmcodecdsp.h"
-#include "mfaudiodecodercontrol_p.h"
-
-MFAudioDecoderControl::MFAudioDecoderControl(QAudioDecoder *parent)
- : QPlatformAudioDecoder(parent)
- , m_decoderSourceReader(new MFDecoderSourceReader)
- , m_sourceResolver(new SourceResolver)
- , m_resampler(0)
- , m_device(0)
- , m_mfInputStreamID(0)
- , m_mfOutputStreamID(0)
- , m_bufferReady(false)
- , m_duration(-1)
- , m_position(-1)
- , m_loadingSource(false)
- , m_mfOutputType(0)
- , m_convertSample(0)
- , m_sourceReady(false)
- , m_resamplerDirty(false)
-{
- CoCreateInstance(CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)(&m_resampler));
- if (!m_resampler) {
- qCritical("MFAudioDecoderControl: Failed to create resampler(CLSID_CResamplerMediaObject)!");
- return;
- }
- m_resampler->AddInputStreams(1, &m_mfInputStreamID);
-
- connect(m_sourceResolver, SIGNAL(mediaSourceReady()), this, SLOT(handleMediaSourceReady()));
- connect(m_sourceResolver, SIGNAL(error(long)), this, SLOT(handleMediaSourceError(long)));
- connect(m_decoderSourceReader, SIGNAL(finished()), this, SLOT(handleSourceFinished()));
-
- QAudioFormat defaultFormat;
- setAudioFormat(defaultFormat);
-}
-
-MFAudioDecoderControl::~MFAudioDecoderControl()
-{
- if (m_mfOutputType)
- m_mfOutputType->Release();
- m_decoderSourceReader->shutdown();
- m_decoderSourceReader->Release();
- m_sourceResolver->Release();
- if (m_resampler)
- m_resampler->Release();
-}
-
-QUrl MFAudioDecoderControl::source() const
-{
- return m_source;
-}
-
-void MFAudioDecoderControl::onSourceCleared()
-{
- bool positionDirty = false;
- bool durationDirty = false;
- if (m_position != -1) {
- m_position = -1;
- positionDirty = true;
- }
- if (m_duration != -1) {
- m_duration = -1;
- durationDirty = true;
- }
- if (positionDirty)
- positionChanged(m_position);
- if (durationDirty)
- durationChanged(m_duration);
-}
-
-void MFAudioDecoderControl::setSource(const QUrl &fileName)
-{
- if (!m_device && m_source == fileName)
- return;
- m_sourceReady = false;
- m_sourceResolver->cancel();
- m_decoderSourceReader->setSource(nullptr, m_audioFormat);
- m_device = 0;
- m_source = fileName;
- if (!m_source.isEmpty()) {
- m_sourceResolver->shutdown();
- m_sourceResolver->load(m_source, 0);
- m_loadingSource = true;
- } else {
- onSourceCleared();
- }
- sourceChanged();
-}
-
-QIODevice* MFAudioDecoderControl::sourceDevice() const
-{
- return m_device;
-}
-
-void MFAudioDecoderControl::setSourceDevice(QIODevice *device)
-{
- if (m_device == device && m_source.isEmpty())
- return;
- m_sourceReady = false;
- m_sourceResolver->cancel();
- m_decoderSourceReader->setSource(nullptr, m_audioFormat);
- m_source.clear();
- m_device = device;
- if (m_device) {
- m_sourceResolver->shutdown();
- m_sourceResolver->load(QUrl(), m_device);
- m_loadingSource = true;
- } else {
- onSourceCleared();
- }
- sourceChanged();
-}
-
-void MFAudioDecoderControl::updateResamplerOutputType()
-{
- m_resamplerDirty = false;
- if (m_audioFormat == m_sourceOutputFormat)
- return;
- HRESULT hr = m_resampler->SetOutputType(m_mfOutputStreamID, m_mfOutputType, 0);
- if (SUCCEEDED(hr)) {
- MFT_OUTPUT_STREAM_INFO streamInfo;
- m_resampler->GetOutputStreamInfo(m_mfOutputStreamID, &streamInfo);
- if ((streamInfo.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) == 0) {
- //if resampler does not allocate output sample memory, we do it here
- if (m_convertSample) {
- m_convertSample->Release();
- m_convertSample = 0;
- }
- if (SUCCEEDED(MFCreateSample(&m_convertSample))) {
- IMFMediaBuffer *mbuf = 0;;
- if (SUCCEEDED(MFCreateMemoryBuffer(streamInfo.cbSize, &mbuf))) {
- m_convertSample->AddBuffer(mbuf);
- mbuf->Release();
- }
- }
- }
- } else {
- qWarning() << "MFAudioDecoderControl: failed to SetOutputType of resampler" << hr;
- }
-}
-
-void MFAudioDecoderControl::handleMediaSourceReady()
-{
- m_loadingSource = false;
- m_sourceReady = true;
- IMFMediaType *mediaType = m_decoderSourceReader->setSource(m_sourceResolver->mediaSource(), m_audioFormat);
- m_sourceOutputFormat = QAudioFormat();
-
- if (mediaType) {
- m_sourceOutputFormat = m_audioFormat;
-
- UINT32 val = 0;
- if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) {
- m_sourceOutputFormat.setChannelCount(int(val));
- }
- if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) {
- m_sourceOutputFormat.setSampleRate(int(val));
- }
- UINT32 bitsPerSample = 0;
- mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample);
-
- GUID subType;
- if (SUCCEEDED(mediaType->GetGUID(MF_MT_SUBTYPE, &subType))) {
- if (subType == MFAudioFormat_Float) {
- m_sourceOutputFormat.setSampleFormat(QAudioFormat::Float);
- } else if (bitsPerSample == 8) {
- m_sourceOutputFormat.setSampleFormat(QAudioFormat::UInt8);
- } else if (bitsPerSample == 16) {
- m_sourceOutputFormat.setSampleFormat(QAudioFormat::Int16);
- } else if (bitsPerSample == 32){
- m_sourceOutputFormat.setSampleFormat(QAudioFormat::Int32);
- }
- }
-
- if (!m_audioFormat.isValid())
- setResamplerOutputFormat(m_sourceOutputFormat);
- else {
- setResamplerOutputFormat(m_audioFormat);
- }
- }
-
- if (m_sourceResolver->mediaSource()) {
- if (mediaType && m_resampler) {
- HRESULT hr = S_OK;
- hr = m_resampler->SetInputType(m_mfInputStreamID, mediaType, 0);
- if (SUCCEEDED(hr)) {
- updateResamplerOutputType();
- } else {
- qWarning() << "MFAudioDecoderControl: failed to SetInputType of resampler" << hr;
- }
- }
- IMFPresentationDescriptor *pd;
- if (SUCCEEDED(m_sourceResolver->mediaSource()->CreatePresentationDescriptor(&pd))) {
- UINT64 duration = 0;
- pd->GetUINT64(MF_PD_DURATION, &duration);
- pd->Release();
- duration /= 10000;
- if (m_duration != qint64(duration)) {
- m_duration = qint64(duration);
- durationChanged(m_duration);
- }
- }
- if (isDecoding()) {
- activatePipeline();
- }
- } else if (isDecoding()) {
- setIsDecoding(false);
- }
-}
-
-void MFAudioDecoderControl::setResamplerOutputFormat(const QAudioFormat &format)
-{
- if (format.isValid()) {
- IMFMediaType *mediaType = 0;
- MFCreateMediaType(&mediaType);
- mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
- if (format.sampleFormat() == QAudioFormat::Float) {
- mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
- } else {
- mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
- }
-
- mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, UINT32(format.channelCount()));
- mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, UINT32(format.sampleRate()));
- UINT32 alignmentBlock = UINT32(format.bytesPerFrame());
- mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, alignmentBlock);
- UINT32 avgBytesPerSec = UINT32(format.sampleRate() * format.bytesPerFrame());
- mediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, avgBytesPerSec);
- mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, UINT32(format.bytesPerSample()*8));
- mediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
-
- if (m_mfOutputType)
- m_mfOutputType->Release();
- m_mfOutputType = mediaType;
- } else {
- if (m_mfOutputType)
- m_mfOutputType->Release();
- m_mfOutputType = NULL;
- }
-
- if (m_sourceReady && !isDecoding()) {
- updateResamplerOutputType();
- } else {
- m_resamplerDirty = true;
- }
-}
-
-void MFAudioDecoderControl::handleMediaSourceError(long hr)
-{
- Q_UNUSED(hr);
- m_loadingSource = false;
- m_decoderSourceReader->setSource(nullptr, m_audioFormat);
- setIsDecoding(false);
-}
-
-void MFAudioDecoderControl::activatePipeline()
-{
- Q_ASSERT(!m_bufferReady);
- setIsDecoding(true);
- connect(m_decoderSourceReader, SIGNAL(sampleAdded()), this, SLOT(handleSampleAdded()));
- if (m_resamplerDirty) {
- updateResamplerOutputType();
- }
- m_decoderSourceReader->reset();
- m_decoderSourceReader->readNextSample();
- if (m_position != -1) {
- m_position = -1;
- positionChanged(-1);
- }
-}
-
-void MFAudioDecoderControl::start()
-{
- if (isDecoding())
- return;
-
- if (m_loadingSource) {
- //deferred starting
- setIsDecoding(true);
- return;
- }
-
- if (!m_decoderSourceReader->mediaSource())
- return;
- activatePipeline();
-}
-
-void MFAudioDecoderControl::stop()
-{
- if (!isDecoding())
- return;
- disconnect(m_decoderSourceReader, SIGNAL(sampleAdded()), this, SLOT(handleSampleAdded()));
- if (m_bufferReady) {
- m_bufferReady = false;
- emit bufferAvailableChanged(m_bufferReady);
- }
- setIsDecoding(false);
-}
-
-void MFAudioDecoderControl::handleSampleAdded()
-{
- QList<IMFSample*> samples = m_decoderSourceReader->takeSamples();
- Q_ASSERT(samples.count() > 0);
- Q_ASSERT(!m_bufferReady);
- Q_ASSERT(m_resampler);
- LONGLONG sampleStartTime = 0;
- IMFSample *firstSample = samples.first();
- firstSample->GetSampleTime(&sampleStartTime);
- QByteArray abuf;
- QAudioFormat bufferFormat;
- if (!m_audioFormat.isValid()) {
- bufferFormat = m_sourceOutputFormat;
- //no need for resampling
- for (IMFSample *s : qAsConst(samples)) {
- IMFMediaBuffer *buffer;
- s->ConvertToContiguousBuffer(&buffer);
- DWORD bufLen = 0;
- BYTE *buf = 0;
- if (SUCCEEDED(buffer->Lock(&buf, NULL, &bufLen))) {
- abuf.push_back(QByteArray(reinterpret_cast<char*>(buf), bufLen));
- buffer->Unlock();
- }
- buffer->Release();
- LONGLONG sampleTime = 0, sampleDuration = 0;
- s->GetSampleTime(&sampleTime);
- s->GetSampleDuration(&sampleDuration);
- m_position = qint64(sampleTime + sampleDuration) / 10000;
- s->Release();
- }
- } else {
- bufferFormat = m_audioFormat;
- for (IMFSample *s : qAsConst(samples)) {
- HRESULT hr = m_resampler->ProcessInput(m_mfInputStreamID, s, 0);
- if (SUCCEEDED(hr)) {
- MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
- outputDataBuffer.dwStreamID = m_mfOutputStreamID;
- while (true) {
- outputDataBuffer.pEvents = 0;
- outputDataBuffer.dwStatus = 0;
- outputDataBuffer.pSample = m_convertSample;
- DWORD status = 0;
- if (SUCCEEDED(m_resampler->ProcessOutput(0, 1, &outputDataBuffer, &status))) {
- IMFMediaBuffer *buffer;
- outputDataBuffer.pSample->ConvertToContiguousBuffer(&buffer);
- DWORD bufLen = 0;
- BYTE *buf = 0;
- if (SUCCEEDED(buffer->Lock(&buf, NULL, &bufLen))) {
- abuf.push_back(QByteArray(reinterpret_cast<char*>(buf), bufLen));
- buffer->Unlock();
- }
- buffer->Release();
- } else {
- break;
- }
- }
- }
- LONGLONG sampleTime = 0, sampleDuration = 0;
- s->GetSampleTime(&sampleTime);
- s->GetSampleDuration(&sampleDuration);
- m_position = qint64(sampleTime + sampleDuration) / 10000;
- s->Release();
- }
- }
- // WMF uses 100-nanosecond units, QAudioDecoder uses milliseconds, QAudioBuffer uses microseconds...
- m_cachedAudioBuffer = QAudioBuffer(abuf, bufferFormat, qint64(sampleStartTime / 10));
- m_bufferReady = true;
- emit positionChanged(m_position);
- emit bufferAvailableChanged(m_bufferReady);
- emit bufferReady();
-}
-
-void MFAudioDecoderControl::handleSourceFinished()
-{
- stop();
- emit finished();
-}
-
-QAudioFormat MFAudioDecoderControl::audioFormat() const
-{
- return m_audioFormat;
-}
-
-void MFAudioDecoderControl::setAudioFormat(const QAudioFormat &format)
-{
- if (m_audioFormat == format || !m_resampler)
- return;
- m_audioFormat = format;
- setResamplerOutputFormat(format);
- emit formatChanged(m_audioFormat);
-}
-
-QAudioBuffer MFAudioDecoderControl::read()
-{
- if (!m_bufferReady)
- return QAudioBuffer();
- QAudioBuffer buffer = m_cachedAudioBuffer;
- m_bufferReady = false;
- emit bufferAvailableChanged(m_bufferReady);
- m_decoderSourceReader->readNextSample();
- return buffer;
-}
-
-bool MFAudioDecoderControl::bufferAvailable() const
-{
- return m_bufferReady;
-}
-
-qint64 MFAudioDecoderControl::position() const
-{
- return m_position;
-}
-
-qint64 MFAudioDecoderControl::duration() const
-{
- return m_duration;
-}
diff --git a/src/multimedia/platform/windows/decoder/mfaudiodecodercontrol_p.h b/src/multimedia/platform/windows/decoder/mfaudiodecodercontrol_p.h
deleted file mode 100644
index 6efdbb346..000000000
--- a/src/multimedia/platform/windows/decoder/mfaudiodecodercontrol_p.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFAUDIODECODERCONTROL_H
-#define MFAUDIODECODERCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "private/qplatformaudiodecoder_p.h"
-#include "mfdecodersourcereader_p.h"
-#include "private/sourceresolver_p.h"
-
-QT_USE_NAMESPACE
-
-class MFAudioDecoderControl : public QPlatformAudioDecoder
-{
- Q_OBJECT
-public:
- MFAudioDecoderControl(QAudioDecoder *parent);
- ~MFAudioDecoderControl();
-
- QUrl source() const;
- void setSource(const QUrl &fileName);
-
- QIODevice* sourceDevice() const;
- void setSourceDevice(QIODevice *device);
-
- void start();
- void stop();
-
- QAudioFormat audioFormat() const override;
- void setAudioFormat(const QAudioFormat &format) override;
-
- QAudioBuffer read();
- bool bufferAvailable() const;
-
- qint64 position() const;
- qint64 duration() const;
-
-private Q_SLOTS:
- void handleMediaSourceReady();
- void handleMediaSourceError(long hr);
- void handleSampleAdded();
- void handleSourceFinished();
-
-private:
- void updateResamplerOutputType();
- void activatePipeline();
- void onSourceCleared();
- void setResamplerOutputFormat(const QAudioFormat &format);
-
- MFDecoderSourceReader *m_decoderSourceReader;
- SourceResolver *m_sourceResolver;
- IMFTransform *m_resampler;
- QUrl m_source;
- QIODevice *m_device;
- QAudioFormat m_audioFormat;
- DWORD m_mfInputStreamID;
- DWORD m_mfOutputStreamID;
- bool m_bufferReady;
- QAudioBuffer m_cachedAudioBuffer;
- qint64 m_duration;
- qint64 m_position;
- bool m_loadingSource;
- IMFMediaType *m_mfOutputType;
- IMFSample *m_convertSample;
- QAudioFormat m_sourceOutputFormat;
- bool m_sourceReady;
- bool m_resamplerDirty;
-};
-
-#endif//MFAUDIODECODERCONTROL_H
diff --git a/src/multimedia/platform/windows/decoder/mfdecodersourcereader.cpp b/src/multimedia/platform/windows/decoder/mfdecodersourcereader.cpp
deleted file mode 100644
index 381c60dc5..000000000
--- a/src/multimedia/platform/windows/decoder/mfdecodersourcereader.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mfdecodersourcereader_p.h"
-
-MFDecoderSourceReader::MFDecoderSourceReader(QObject *parent)
- : m_cRef(1)
- , m_sourceReader(0)
- , m_source(0)
-{
- Q_UNUSED(parent);
-}
-
-void MFDecoderSourceReader::shutdown()
-{
- if (m_source) {
- m_source->Release();
- m_source = NULL;
- }
- if (m_sourceReader) {
- m_sourceReader->Release();
- m_sourceReader = NULL;
- }
-}
-
-IMFMediaSource* MFDecoderSourceReader::mediaSource()
-{
- return m_source;
-}
-
-IMFMediaType* MFDecoderSourceReader::setSource(IMFMediaSource *source, const QAudioFormat &audioFormat)
-{
- IMFMediaType *mediaType = NULL;
- if (m_source == source)
- return mediaType;
- if (m_source) {
- m_source->Release();
- m_source = NULL;
- }
- if (m_sourceReader) {
- m_sourceReader->Release();
- m_sourceReader = NULL;
- }
- if (!source)
- return mediaType;
- IMFAttributes *attr = NULL;
- MFCreateAttributes(&attr, 1);
- if (SUCCEEDED(attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this))) {
- if (SUCCEEDED(MFCreateSourceReaderFromMediaSource(source, attr, &m_sourceReader))) {
- m_source = source;
- m_source->AddRef();
- m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_ALL_STREAMS), FALSE);
- m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
- IMFMediaType *pPartialType = NULL;
- MFCreateMediaType(&pPartialType);
- pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
-
- if (audioFormat.sampleFormat() == QAudioFormat::Float) {
- pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
- } else {
- pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
- }
-
- m_sourceReader->SetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), NULL, pPartialType);
- pPartialType->Release();
- m_sourceReader->GetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), &mediaType);
- // Ensure the stream is selected.
- m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
- }
- attr->Release();
- }
- return mediaType;
-}
-
-void MFDecoderSourceReader::reset()
-{
- if (!m_sourceReader)
- return;
- PROPVARIANT vPos;
- PropVariantInit(&vPos);
- vPos.vt = VT_I8;
- vPos.uhVal.QuadPart = 0;
- m_sourceReader->SetCurrentPosition(GUID_NULL, vPos);
-}
-
-void MFDecoderSourceReader::readNextSample()
-{
- if (!m_sourceReader)
- return;
- m_sourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, NULL, NULL, NULL);
-}
-
-QList<IMFSample*> MFDecoderSourceReader::takeSamples() //internal samples will be cleared after this
-{
- QList<IMFSample*> samples;
- m_samplesMutex.lock();
- samples = m_cachedSamples;
- m_cachedSamples.clear();
- m_samplesMutex.unlock();
- return samples;
-}
-
-//from IUnknown
-STDMETHODIMP MFDecoderSourceReader::QueryInterface(REFIID riid, LPVOID *ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFSourceReaderCallback) {
- *ppvObject = static_cast<IMFSourceReaderCallback*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) MFDecoderSourceReader::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) MFDecoderSourceReader::Release(void)
-{
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0) {
- this->deleteLater();
- }
- return cRef;
-}
-
-//from IMFSourceReaderCallback
-STDMETHODIMP MFDecoderSourceReader::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex,
- DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample)
-{
- Q_UNUSED(hrStatus);
- Q_UNUSED(dwStreamIndex);
- Q_UNUSED(llTimestamp);
- if (pSample) {
- pSample->AddRef();
- m_samplesMutex.lock();
- m_cachedSamples.push_back(pSample);
- m_samplesMutex.unlock();
- emit sampleAdded();
- } else if ((dwStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM) == MF_SOURCE_READERF_ENDOFSTREAM) {
- emit finished();
- }
- return S_OK;
-}
-
-STDMETHODIMP MFDecoderSourceReader::OnFlush(DWORD)
-{
- return S_OK;
-}
-
-STDMETHODIMP MFDecoderSourceReader::OnEvent(DWORD, IMFMediaEvent*)
-{
- return S_OK;
-}
diff --git a/src/multimedia/platform/windows/decoder/mfdecodersourcereader_p.h b/src/multimedia/platform/windows/decoder/mfdecodersourcereader_p.h
deleted file mode 100644
index 7d63f5368..000000000
--- a/src/multimedia/platform/windows/decoder/mfdecodersourcereader_p.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFDECODERSOURCEREADER_H
-#define MFDECODERSOURCEREADER_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 <mfapi.h>
-#include <mfidl.h>
-#include <Mfreadwrite.h>
-
-#include <QtCore/qobject.h>
-#include <QtCore/qmutex.h>
-#include "qaudioformat.h"
-
-QT_USE_NAMESPACE
-
-class MFDecoderSourceReader : public QObject, public IMFSourceReaderCallback
-{
- Q_OBJECT
-public:
- MFDecoderSourceReader(QObject *parent = 0);
- void shutdown();
-
- IMFMediaSource* mediaSource();
- IMFMediaType* setSource(IMFMediaSource *source, const QAudioFormat &audioFormat);
-
- void reset();
- void readNextSample();
- QList<IMFSample*> takeSamples(); //internal samples will be cleared after this
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
- STDMETHODIMP_(ULONG) AddRef(void);
- STDMETHODIMP_(ULONG) Release(void);
-
- //from IMFSourceReaderCallback
- STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex,
- DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample);
- STDMETHODIMP OnFlush(DWORD dwStreamIndex);
- STDMETHODIMP OnEvent(DWORD dwStreamIndex, IMFMediaEvent *pEvent);
-
-Q_SIGNALS:
- void sampleAdded();
- void finished();
-
-private:
- long m_cRef;
- QList<IMFSample*> m_cachedSamples;
- QMutex m_samplesMutex;
-
- IMFSourceReader *m_sourceReader;
- IMFMediaSource *m_source;
-};
-#endif//MFDECODERSOURCEREADER_H
diff --git a/src/multimedia/platform/windows/evr/evrcustompresenter.cpp b/src/multimedia/platform/windows/evr/evrcustompresenter.cpp
deleted file mode 100644
index 086fb57d4..000000000
--- a/src/multimedia/platform/windows/evr/evrcustompresenter.cpp
+++ /dev/null
@@ -1,2005 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "evrcustompresenter_p.h"
-
-#include "evrd3dpresentengine_p.h"
-#include "evrhelpers_p.h"
-#include <private/qwindowsmultimediautils_p.h>
-#include <private/qplatformvideosink_p.h>
-
-#include <QtGui/private/qrhi_p.h>
-
-#include <QtCore/qmutex.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qrect.h>
-#include <qthread.h>
-#include <qcoreapplication.h>
-#include <qmath.h>
-#include <QtCore/qdebug.h>
-
-#include <mutex>
-
-#include <float.h>
-#include <evcode.h>
-
-QT_BEGIN_NAMESPACE
-
-const static MFRatio g_DefaultFrameRate = { 30, 1 };
-static const DWORD SCHEDULER_TIMEOUT = 5000;
-static const MFTIME ONE_SECOND = 10000000;
-static const LONG ONE_MSEC = 1000;
-
-// Function declarations.
-static HRESULT setDesiredSampleTime(IMFSample *sample, const LONGLONG& hnsSampleTime, const LONGLONG& hnsDuration);
-static HRESULT clearDesiredSampleTime(IMFSample *sample);
-static HRESULT setMixerSourceRect(IMFTransform *mixer, const MFVideoNormalizedRect& nrcSource);
-static QVideoFrameFormat::PixelFormat pixelFormatFromMediaType(IMFMediaType *type);
-
-static inline LONG MFTimeToMsec(const LONGLONG& time)
-{
- return (LONG)(time / (ONE_SECOND / ONE_MSEC));
-}
-
-bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter)
-{
- if (!evr || !presenter)
- return false;
-
- HRESULT result = E_FAIL;
-
- IMFVideoRenderer *renderer = NULL;
- if (SUCCEEDED(evr->QueryInterface(IID_PPV_ARGS(&renderer)))) {
- result = renderer->InitializeRenderer(NULL, presenter);
- renderer->Release();
- }
-
- return result == S_OK;
-}
-
-class PresentSampleEvent : public QEvent
-{
-public:
- PresentSampleEvent(IMFSample *sample)
- : QEvent(QEvent::Type(EVRCustomPresenter::PresentSample))
- , m_sample(sample)
- {
- if (m_sample)
- m_sample->AddRef();
- }
-
- ~PresentSampleEvent() override
- {
- if (m_sample)
- m_sample->Release();
- }
-
- IMFSample *sample() const { return m_sample; }
-
-private:
- IMFSample *m_sample;
-};
-
-Scheduler::Scheduler(EVRCustomPresenter *presenter)
- : m_presenter(presenter)
- , m_clock(NULL)
- , m_threadID(0)
- , m_schedulerThread(0)
- , m_threadReadyEvent(0)
- , m_flushEvent(0)
- , m_playbackRate(1.0f)
- , m_perFrameInterval(0)
- , m_perFrame_1_4th(0)
- , m_lastSampleTime(0)
-{
-}
-
-Scheduler::~Scheduler()
-{
- qt_evr_safe_release(&m_clock);
- for (int i = 0; i < m_scheduledSamples.size(); ++i)
- m_scheduledSamples[i]->Release();
- m_scheduledSamples.clear();
-}
-
-void Scheduler::setFrameRate(const MFRatio& fps)
-{
- UINT64 AvgTimePerFrame = 0;
-
- // Convert to a duration.
- MFFrameRateToAverageTimePerFrame(fps.Numerator, fps.Denominator, &AvgTimePerFrame);
-
- m_perFrameInterval = (MFTIME)AvgTimePerFrame;
-
- // Calculate 1/4th of this value, because we use it frequently.
- m_perFrame_1_4th = m_perFrameInterval / 4;
-}
-
-HRESULT Scheduler::startScheduler(IMFClock *clock)
-{
- if (m_schedulerThread)
- return E_UNEXPECTED;
-
- HRESULT hr = S_OK;
- DWORD dwID = 0;
- HANDLE hObjects[2];
- DWORD dwWait = 0;
-
- if (m_clock)
- m_clock->Release();
- m_clock = clock;
- if (m_clock)
- m_clock->AddRef();
-
- // Set a high the timer resolution (ie, short timer period).
- timeBeginPeriod(1);
-
- // Create an event to wait for the thread to start.
- m_threadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!m_threadReadyEvent) {
- hr = HRESULT_FROM_WIN32(GetLastError());
- goto done;
- }
-
- // Create an event to wait for flush commands to complete.
- m_flushEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!m_flushEvent) {
- hr = HRESULT_FROM_WIN32(GetLastError());
- goto done;
- }
-
- // Create the scheduler thread.
- m_schedulerThread = CreateThread(NULL, 0, schedulerThreadProc, (LPVOID)this, 0, &dwID);
- if (!m_schedulerThread) {
- hr = HRESULT_FROM_WIN32(GetLastError());
- goto done;
- }
-
- // Wait for the thread to signal the "thread ready" event.
- hObjects[0] = m_threadReadyEvent;
- hObjects[1] = m_schedulerThread;
- dwWait = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE); // Wait for EITHER of these handles.
- if (WAIT_OBJECT_0 != dwWait) {
- // The thread terminated early for some reason. This is an error condition.
- CloseHandle(m_schedulerThread);
- m_schedulerThread = NULL;
-
- hr = E_UNEXPECTED;
- goto done;
- }
-
- m_threadID = dwID;
-
-done:
- // Regardless success/failure, we are done using the "thread ready" event.
- if (m_threadReadyEvent) {
- CloseHandle(m_threadReadyEvent);
- m_threadReadyEvent = NULL;
- }
- return hr;
-}
-
-HRESULT Scheduler::stopScheduler()
-{
- if (!m_schedulerThread)
- return S_OK;
-
- // Ask the scheduler thread to exit.
- PostThreadMessage(m_threadID, Terminate, 0, 0);
-
- // Wait for the thread to exit.
- WaitForSingleObject(m_schedulerThread, INFINITE);
-
- // Close handles.
- CloseHandle(m_schedulerThread);
- m_schedulerThread = NULL;
-
- CloseHandle(m_flushEvent);
- m_flushEvent = NULL;
-
- // Discard samples.
- m_mutex.lock();
- for (int i = 0; i < m_scheduledSamples.size(); ++i)
- m_scheduledSamples[i]->Release();
- m_scheduledSamples.clear();
- m_mutex.unlock();
-
- // Restore the timer resolution.
- timeEndPeriod(1);
-
- return S_OK;
-}
-
-HRESULT Scheduler::flush()
-{
- if (m_schedulerThread) {
- // Ask the scheduler thread to flush.
- PostThreadMessage(m_threadID, Flush, 0 , 0);
-
- // Wait for the scheduler thread to signal the flush event,
- // OR for the thread to terminate.
- HANDLE objects[] = { m_flushEvent, m_schedulerThread };
-
- WaitForMultipleObjects(ARRAYSIZE(objects), objects, FALSE, SCHEDULER_TIMEOUT);
- }
-
- return S_OK;
-}
-
-bool Scheduler::areSamplesScheduled()
-{
- QMutexLocker locker(&m_mutex);
- return m_scheduledSamples.count() > 0;
-}
-
-HRESULT Scheduler::scheduleSample(IMFSample *sample, bool presentNow)
-{
- if (!m_schedulerThread)
- return MF_E_NOT_INITIALIZED;
-
- HRESULT hr = S_OK;
- DWORD dwExitCode = 0;
-
- GetExitCodeThread(m_schedulerThread, &dwExitCode);
- if (dwExitCode != STILL_ACTIVE)
- return E_FAIL;
-
- if (presentNow || !m_clock) {
- m_presenter->presentSample(sample);
- } else {
- // Queue the sample and ask the scheduler thread to wake up.
- m_mutex.lock();
- sample->AddRef();
- m_scheduledSamples.enqueue(sample);
- m_mutex.unlock();
-
- if (SUCCEEDED(hr))
- PostThreadMessage(m_threadID, Schedule, 0, 0);
- }
-
- return hr;
-}
-
-HRESULT Scheduler::processSamplesInQueue(LONG *nextSleep)
-{
- HRESULT hr = S_OK;
- LONG wait = 0;
- IMFSample *sample = NULL;
-
- // Process samples until the queue is empty or until the wait time > 0.
- while (!m_scheduledSamples.isEmpty()) {
- m_mutex.lock();
- sample = m_scheduledSamples.dequeue();
- m_mutex.unlock();
-
- // Process the next sample in the queue. If the sample is not ready
- // for presentation. the value returned in wait is > 0, which
- // means the scheduler should sleep for that amount of time.
-
- hr = processSample(sample, &wait);
- qt_evr_safe_release(&sample);
-
- if (FAILED(hr) || wait > 0)
- break;
- }
-
- // If the wait time is zero, it means we stopped because the queue is
- // empty (or an error occurred). Set the wait time to infinite; this will
- // make the scheduler thread sleep until it gets another thread message.
- if (wait == 0)
- wait = INFINITE;
-
- *nextSleep = wait;
- return hr;
-}
-
-HRESULT Scheduler::processSample(IMFSample *sample, LONG *pNextSleep)
-{
- HRESULT hr = S_OK;
-
- LONGLONG hnsPresentationTime = 0;
- LONGLONG hnsTimeNow = 0;
- MFTIME hnsSystemTime = 0;
-
- bool presentNow = true;
- LONG nextSleep = 0;
-
- if (m_clock) {
- // Get the sample's time stamp. It is valid for a sample to
- // have no time stamp.
- hr = sample->GetSampleTime(&hnsPresentationTime);
-
- // Get the clock time. (But if the sample does not have a time stamp,
- // we don't need the clock time.)
- if (SUCCEEDED(hr))
- hr = m_clock->GetCorrelatedTime(0, &hnsTimeNow, &hnsSystemTime);
-
- // Calculate the time until the sample's presentation time.
- // A negative value means the sample is late.
- LONGLONG hnsDelta = hnsPresentationTime - hnsTimeNow;
- if (m_playbackRate < 0) {
- // For reverse playback, the clock runs backward. Therefore, the
- // delta is reversed.
- hnsDelta = - hnsDelta;
- }
-
- if (hnsDelta < - m_perFrame_1_4th) {
- // This sample is late.
- presentNow = true;
- } else if (hnsDelta > (3 * m_perFrame_1_4th)) {
- // This sample is still too early. Go to sleep.
- nextSleep = MFTimeToMsec(hnsDelta - (3 * m_perFrame_1_4th));
-
- // Adjust the sleep time for the clock rate. (The presentation clock runs
- // at m_fRate, but sleeping uses the system clock.)
- if (m_playbackRate != 0)
- nextSleep = (LONG)(nextSleep / qFabs(m_playbackRate));
-
- // Don't present yet.
- presentNow = false;
- }
- }
-
- if (presentNow) {
- m_presenter->presentSample(sample);
- } else {
- // The sample is not ready yet. Return it to the queue.
- m_mutex.lock();
- sample->AddRef();
- m_scheduledSamples.prepend(sample);
- m_mutex.unlock();
- }
-
- *pNextSleep = nextSleep;
-
- return hr;
-}
-
-DWORD WINAPI Scheduler::schedulerThreadProc(LPVOID parameter)
-{
- Scheduler* scheduler = reinterpret_cast<Scheduler*>(parameter);
- if (!scheduler)
- return -1;
- return scheduler->schedulerThreadProcPrivate();
-}
-
-DWORD Scheduler::schedulerThreadProcPrivate()
-{
- HRESULT hr = S_OK;
- MSG msg;
- LONG wait = INFINITE;
- bool exitThread = false;
-
- // Force the system to create a message queue for this thread.
- // (See MSDN documentation for PostThreadMessage.)
- PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
-
- // Signal to the scheduler that the thread is ready.
- SetEvent(m_threadReadyEvent);
-
- while (!exitThread) {
- // Wait for a thread message OR until the wait time expires.
- DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, wait, QS_POSTMESSAGE);
-
- if (result == WAIT_TIMEOUT) {
- // If we timed out, then process the samples in the queue
- hr = processSamplesInQueue(&wait);
- if (FAILED(hr))
- exitThread = true;
- }
-
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- bool processSamples = true;
-
- switch (msg.message) {
- case Terminate:
- exitThread = true;
- break;
- case Flush:
- // Flushing: Clear the sample queue and set the event.
- m_mutex.lock();
- for (int i = 0; i < m_scheduledSamples.size(); ++i)
- m_scheduledSamples[i]->Release();
- m_scheduledSamples.clear();
- m_mutex.unlock();
- wait = INFINITE;
- SetEvent(m_flushEvent);
- break;
- case Schedule:
- // Process as many samples as we can.
- if (processSamples) {
- hr = processSamplesInQueue(&wait);
- if (FAILED(hr))
- exitThread = true;
- processSamples = (wait != (LONG)INFINITE);
- }
- break;
- }
- }
-
- }
-
- return (SUCCEEDED(hr) ? 0 : 1);
-}
-
-
-SamplePool::SamplePool()
- : m_initialized(false)
-{
-}
-
-SamplePool::~SamplePool()
-{
- clear();
-}
-
-HRESULT SamplePool::getSample(IMFSample **sample)
-{
- QMutexLocker locker(&m_mutex);
-
- if (!m_initialized)
- return MF_E_NOT_INITIALIZED;
-
- if (m_videoSampleQueue.isEmpty())
- return MF_E_SAMPLEALLOCATOR_EMPTY;
-
- // Get a sample from the allocated queue.
-
- // It doesn't matter if we pull them from the head or tail of the list,
- // but when we get it back, we want to re-insert it onto the opposite end.
- // (see ReturnSample)
-
- IMFSample *taken = m_videoSampleQueue.takeFirst();
-
- // Give the sample to the caller.
- *sample = taken;
- (*sample)->AddRef();
-
- taken->Release();
-
- return S_OK;
-}
-
-HRESULT SamplePool::returnSample(IMFSample *sample)
-{
- QMutexLocker locker(&m_mutex);
-
- if (!m_initialized)
- return MF_E_NOT_INITIALIZED;
-
- m_videoSampleQueue.append(sample);
- sample->AddRef();
-
- return S_OK;
-}
-
-HRESULT SamplePool::initialize(QList<IMFSample*> &samples)
-{
- QMutexLocker locker(&m_mutex);
-
- if (m_initialized)
- return MF_E_INVALIDREQUEST;
-
- // Move these samples into our allocated queue.
- for (auto sample : qAsConst(samples)) {
- sample->AddRef();
- m_videoSampleQueue.append(sample);
- }
-
- m_initialized = true;
-
- for (auto sample : qAsConst(samples))
- sample->Release();
- samples.clear();
- return S_OK;
-}
-
-HRESULT SamplePool::clear()
-{
- QMutexLocker locker(&m_mutex);
-
- for (auto sample : qAsConst(m_videoSampleQueue))
- sample->Release();
- m_videoSampleQueue.clear();
- m_initialized = false;
-
- return S_OK;
-}
-
-
-EVRCustomPresenter::EVRCustomPresenter(QVideoSink *sink)
- : QObject()
- , m_sampleFreeCB(this, &EVRCustomPresenter::onSampleFree)
- , m_refCount(1)
- , m_renderState(RenderShutdown)
- , m_scheduler(this)
- , m_tokenCounter(0)
- , m_sampleNotify(false)
- , m_repaint(false)
- , m_prerolled(false)
- , m_endStreaming(false)
- , m_playbackRate(1.0f)
- , m_presentEngine(new D3DPresentEngine)
- , m_clock(0)
- , m_mixer(0)
- , m_mediaEventSink(0)
- , m_mediaType(0)
- , m_videoSink(0)
- , m_canRenderToSurface(false)
- , m_positionOffset(0)
-{
- // Initial source rectangle = (0,0,1,1)
- m_sourceRect.top = 0;
- m_sourceRect.left = 0;
- m_sourceRect.bottom = 1;
- m_sourceRect.right = 1;
-
- setSink(sink);
-}
-
-EVRCustomPresenter::~EVRCustomPresenter()
-{
- m_scheduler.flush();
- m_scheduler.stopScheduler();
- m_samplePool.clear();
-
- qt_evr_safe_release(&m_clock);
- qt_evr_safe_release(&m_mixer);
- qt_evr_safe_release(&m_mediaEventSink);
- qt_evr_safe_release(&m_mediaType);
-
- delete m_presentEngine;
-}
-
-HRESULT EVRCustomPresenter::QueryInterface(REFIID riid, void ** ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFGetService) {
- *ppvObject = static_cast<IMFGetService*>(this);
- } else if (riid == IID_IMFTopologyServiceLookupClient) {
- *ppvObject = static_cast<IMFTopologyServiceLookupClient*>(this);
- } else if (riid == IID_IMFVideoDeviceID) {
- *ppvObject = static_cast<IMFVideoDeviceID*>(this);
- } else if (riid == IID_IMFVideoPresenter) {
- *ppvObject = static_cast<IMFVideoPresenter*>(this);
- } else if (riid == IID_IMFRateSupport) {
- *ppvObject = static_cast<IMFRateSupport*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(static_cast<IMFGetService*>(this));
- } else if (riid == IID_IMFClockStateSink) {
- *ppvObject = static_cast<IMFClockStateSink*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-ULONG EVRCustomPresenter::AddRef()
-{
- return InterlockedIncrement(&m_refCount);
-}
-
-ULONG EVRCustomPresenter::Release()
-{
- ULONG uCount = InterlockedDecrement(&m_refCount);
- if (uCount == 0)
- delete this;
- return uCount;
-}
-
-HRESULT EVRCustomPresenter::GetService(REFGUID guidService, REFIID riid, LPVOID *ppvObject)
-{
- HRESULT hr = S_OK;
-
- if (!ppvObject)
- return E_POINTER;
-
- // The only service GUID that we support is MR_VIDEO_RENDER_SERVICE.
- if (guidService != mr_VIDEO_RENDER_SERVICE)
- return MF_E_UNSUPPORTED_SERVICE;
-
- // First try to get the service interface from the D3DPresentEngine object.
- hr = m_presentEngine->getService(guidService, riid, ppvObject);
- if (FAILED(hr))
- // Next, check if this object supports the interface.
- hr = QueryInterface(riid, ppvObject);
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::GetDeviceID(IID* deviceID)
-{
- if (!deviceID)
- return E_POINTER;
-
- *deviceID = iid_IDirect3DDevice9;
-
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::InitServicePointers(IMFTopologyServiceLookup *lookup)
-{
- if (!lookup)
- return E_POINTER;
-
- HRESULT hr = S_OK;
- DWORD objectCount = 0;
-
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- // Do not allow initializing when playing or paused.
- if (isActive())
- return MF_E_INVALIDREQUEST;
-
- qt_evr_safe_release(&m_clock);
- qt_evr_safe_release(&m_mixer);
- qt_evr_safe_release(&m_mediaEventSink);
-
- // Ask for the clock. Optional, because the EVR might not have a clock.
- objectCount = 1;
-
- lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0,
- mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_clock),
- &objectCount
- );
-
- // Ask for the mixer. (Required.)
- objectCount = 1;
-
- hr = lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0,
- mr_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_mixer),
- &objectCount
- );
-
- if (FAILED(hr))
- return hr;
-
- // Make sure that we can work with this mixer.
- hr = configureMixer(m_mixer);
- if (FAILED(hr))
- return hr;
-
- // Ask for the EVR's event-sink interface. (Required.)
- objectCount = 1;
-
- hr = lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0,
- mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_mediaEventSink),
- &objectCount
- );
-
- if (SUCCEEDED(hr))
- m_renderState = RenderStopped;
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::ReleaseServicePointers()
-{
- // Enter the shut-down state.
- m_mutex.lock();
-
- m_renderState = RenderShutdown;
-
- m_mutex.unlock();
-
- // Flush any samples that were scheduled.
- flush();
-
- // Clear the media type and release related resources.
- setMediaType(NULL);
-
- // Release all services that were acquired from InitServicePointers.
- qt_evr_safe_release(&m_clock);
- qt_evr_safe_release(&m_mixer);
- qt_evr_safe_release(&m_mediaEventSink);
-
- return S_OK;
-}
-
-bool EVRCustomPresenter::isValid() const
-{
- return m_presentEngine->isValid() && m_canRenderToSurface;
-}
-
-HRESULT EVRCustomPresenter::ProcessMessage(MFVP_MESSAGE_TYPE message, ULONG_PTR param)
-{
- HRESULT hr = S_OK;
-
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- switch (message) {
- // Flush all pending samples.
- case MFVP_MESSAGE_FLUSH:
- hr = flush();
- break;
-
- // Renegotiate the media type with the mixer.
- case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
- hr = renegotiateMediaType();
- break;
-
- // The mixer received a new input sample.
- case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
- hr = processInputNotify();
- break;
-
- // Streaming is about to start.
- case MFVP_MESSAGE_BEGINSTREAMING:
- hr = beginStreaming();
- break;
-
- // Streaming has ended. (The EVR has stopped.)
- case MFVP_MESSAGE_ENDSTREAMING:
- hr = endStreaming();
- break;
-
- // All input streams have ended.
- case MFVP_MESSAGE_ENDOFSTREAM:
- // Set the EOS flag.
- m_endStreaming = true;
- // Check if it's time to send the EC_COMPLETE event to the EVR.
- hr = checkEndOfStream();
- break;
-
- // Frame-stepping is starting.
- case MFVP_MESSAGE_STEP:
- hr = prepareFrameStep(DWORD(param));
- break;
-
- // Cancels frame-stepping.
- case MFVP_MESSAGE_CANCELSTEP:
- hr = cancelFrameStep();
- break;
-
- default:
- hr = E_INVALIDARG; // Unknown message. This case should never occur.
- break;
- }
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::GetCurrentMediaType(IMFVideoMediaType **mediaType)
-{
- HRESULT hr = S_OK;
-
- if (!mediaType)
- return E_POINTER;
-
- *mediaType = NULL;
-
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- if (!m_mediaType)
- return MF_E_NOT_INITIALIZED;
-
- return m_mediaType->QueryInterface(IID_PPV_ARGS(mediaType));
-}
-
-HRESULT EVRCustomPresenter::OnClockStart(MFTIME, LONGLONG clockStartOffset)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- // We cannot start after shutdown.
- HRESULT hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- // Check if the clock is already active (not stopped).
- if (isActive()) {
- m_renderState = RenderStarted;
-
- // If the clock position changes while the clock is active, it
- // is a seek request. We need to flush all pending samples.
- if (clockStartOffset != PRESENTATION_CURRENT_POSITION)
- flush();
- } else {
- m_renderState = RenderStarted;
-
- // The clock has started from the stopped state.
-
- // Possibly we are in the middle of frame-stepping OR have samples waiting
- // in the frame-step queue. Deal with these two cases first:
- hr = startFrameStep();
- if (FAILED(hr))
- return hr;
- }
-
- // Now try to get new output samples from the mixer.
- processOutputLoop();
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::OnClockRestart(MFTIME)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- HRESULT hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- // The EVR calls OnClockRestart only while paused.
-
- m_renderState = RenderStarted;
-
- // Possibly we are in the middle of frame-stepping OR we have samples waiting
- // in the frame-step queue. Deal with these two cases first:
- hr = startFrameStep();
- if (FAILED(hr))
- return hr;
-
- // Now resume the presentation loop.
- processOutputLoop();
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::OnClockStop(MFTIME)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- HRESULT hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- if (m_renderState != RenderStopped) {
- m_renderState = RenderStopped;
- flush();
-
- // If we are in the middle of frame-stepping, cancel it now.
- if (m_frameStep.state != FrameStepNone)
- cancelFrameStep();
- }
-
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::OnClockPause(MFTIME)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- // We cannot pause the clock after shutdown.
- HRESULT hr = checkShutdown();
-
- if (SUCCEEDED(hr))
- m_renderState = RenderPaused;
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::OnClockSetRate(MFTIME, float rate)
-{
- // Note:
- // The presenter reports its maximum rate through the IMFRateSupport interface.
- // Here, we assume that the EVR honors the maximum rate.
-
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- HRESULT hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- // If the rate is changing from zero (scrubbing) to non-zero, cancel the
- // frame-step operation.
- if ((m_playbackRate == 0.0f) && (rate != 0.0f)) {
- cancelFrameStep();
- for (auto sample : qAsConst(m_frameStep.samples))
- sample->Release();
- m_frameStep.samples.clear();
- }
-
- m_playbackRate = rate;
-
- // Tell the scheduler about the new rate.
- m_scheduler.setClockRate(rate);
-
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::GetSlowestRate(MFRATE_DIRECTION, BOOL, float *rate)
-{
- if (!rate)
- return E_POINTER;
-
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- HRESULT hr = checkShutdown();
-
- if (SUCCEEDED(hr)) {
- // There is no minimum playback rate, so the minimum is zero.
- *rate = 0;
- }
-
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::GetFastestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate)
-{
- if (!rate)
- return E_POINTER;
-
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- float maxRate = 0.0f;
-
- HRESULT hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- // Get the maximum *forward* rate.
- maxRate = getMaxRate(thin);
-
- // For reverse playback, it's the negative of maxRate.
- if (direction == MFRATE_REVERSE)
- maxRate = -maxRate;
-
- *rate = maxRate;
-
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::IsRateSupported(BOOL thin, float rate, float *nearestSupportedRate)
-{
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- float maxRate = 0.0f;
- float nearestRate = rate; // If we support rate, that is the nearest.
-
- HRESULT hr = checkShutdown();
- if (FAILED(hr))
- return hr;
-
- // Find the maximum forward rate.
- // Note: We have no minimum rate (that is, we support anything down to 0).
- maxRate = getMaxRate(thin);
-
- if (qFabs(rate) > maxRate) {
- // The (absolute) requested rate exceeds the maximum rate.
- hr = MF_E_UNSUPPORTED_RATE;
-
- // The nearest supported rate is maxRate.
- nearestRate = maxRate;
- if (rate < 0) {
- // Negative for reverse playback.
- nearestRate = -nearestRate;
- }
- }
-
- // Return the nearest supported rate.
- if (nearestSupportedRate)
- *nearestSupportedRate = nearestRate;
-
- return hr;
-}
-
-void EVRCustomPresenter::supportedFormatsChanged()
-{
- const std::lock_guard<QRecursiveMutex> locker(m_mutex);
-
- m_canRenderToSurface = false;
- m_presentEngine->setHint(D3DPresentEngine::RenderToTexture, false);
-
- // check if we can render to the surface (compatible formats)
- if (m_videoSink) {
- if (m_presentEngine->supportsTextureRendering() && m_videoSink->rhi() && m_videoSink->rhi()->backend() == QRhi::OpenGLES2) {
- m_presentEngine->setHint(D3DPresentEngine::RenderToTexture, true);
- m_canRenderToSurface = true;
- } else {
- for (int f = 0; f < QVideoFrameFormat::NPixelFormats; ++f) {
- // ### set a better preference order
- QVideoFrameFormat::PixelFormat format = QVideoFrameFormat::PixelFormat(f);
- if (SUCCEEDED(m_presentEngine->checkFormat(qt_evr_D3DFormatFromPixelFormat(format)))) {
- m_canRenderToSurface = true;
- break;
- }
- }
- }
- }
-
- // TODO: if media type already set, renegotiate?
-}
-
-void EVRCustomPresenter::setSink(QVideoSink *sink)
-{
- m_mutex.lock();
- m_videoSink = sink;
- m_mutex.unlock();
-
- supportedFormatsChanged();
-}
-
-HRESULT EVRCustomPresenter::configureMixer(IMFTransform *mixer)
-{
- // Set the zoom rectangle (ie, the source clipping rectangle).
- return setMixerSourceRect(mixer, m_sourceRect);
-}
-
-HRESULT EVRCustomPresenter::renegotiateMediaType()
-{
- HRESULT hr = S_OK;
- bool foundMediaType = false;
-
- IMFMediaType *mixerType = NULL;
- IMFMediaType *optimalType = NULL;
-
- if (!m_mixer)
- return MF_E_INVALIDREQUEST;
-
- // Loop through all of the mixer's proposed output types.
- DWORD typeIndex = 0;
- while (!foundMediaType && (hr != MF_E_NO_MORE_TYPES)) {
- qt_evr_safe_release(&mixerType);
- qt_evr_safe_release(&optimalType);
-
- // Step 1. Get the next media type supported by mixer.
- hr = m_mixer->GetOutputAvailableType(0, typeIndex++, &mixerType);
- if (FAILED(hr))
- break;
-
- // From now on, if anything in this loop fails, try the next type,
- // until we succeed or the mixer runs out of types.
-
- // Step 2. Check if we support this media type.
- if (SUCCEEDED(hr))
- hr = isMediaTypeSupported(mixerType);
-
- // Step 3. Adjust the mixer's type to match our requirements.
- if (SUCCEEDED(hr))
- hr = createOptimalVideoType(mixerType, &optimalType);
-
- // Step 4. Check if the mixer will accept this media type.
- if (SUCCEEDED(hr))
- hr = m_mixer->SetOutputType(0, optimalType, MFT_SET_TYPE_TEST_ONLY);
-
- // Step 5. Try to set the media type on ourselves.
- if (SUCCEEDED(hr))
- hr = setMediaType(optimalType);
-
- // Step 6. Set output media type on mixer.
- if (SUCCEEDED(hr)) {
- hr = m_mixer->SetOutputType(0, optimalType, 0);
-
- // If something went wrong, clear the media type.
- if (FAILED(hr))
- setMediaType(NULL);
- }
-
- if (SUCCEEDED(hr))
- foundMediaType = true;
- }
-
- qt_evr_safe_release(&mixerType);
- qt_evr_safe_release(&optimalType);
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::flush()
-{
- m_prerolled = false;
-
- // The scheduler might have samples that are waiting for
- // their presentation time. Tell the scheduler to flush.
-
- // This call blocks until the scheduler threads discards all scheduled samples.
- m_scheduler.flush();
-
- // Flush the frame-step queue.
- for (auto sample : qAsConst(m_frameStep.samples))
- sample->Release();
- m_frameStep.samples.clear();
-
- if (m_renderState == RenderStopped && m_videoSink) {
- // Repaint with black.
- presentSample(NULL);
- }
-
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::processInputNotify()
-{
- HRESULT hr = S_OK;
-
- // Set the flag that says the mixer has a new sample.
- m_sampleNotify = true;
-
- if (!m_mediaType) {
- // We don't have a valid media type yet.
- hr = MF_E_TRANSFORM_TYPE_NOT_SET;
- } else {
- // Try to process an output sample.
- processOutputLoop();
- }
- return hr;
-}
-
-HRESULT EVRCustomPresenter::beginStreaming()
-{
- HRESULT hr = S_OK;
-
- // Start the scheduler thread.
- hr = m_scheduler.startScheduler(m_clock);
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::endStreaming()
-{
- HRESULT hr = S_OK;
-
- // Stop the scheduler thread.
- hr = m_scheduler.stopScheduler();
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::checkEndOfStream()
-{
- if (!m_endStreaming) {
- // The EVR did not send the MFVP_MESSAGE_ENDOFSTREAM message.
- return S_OK;
- }
-
- if (m_sampleNotify) {
- // The mixer still has input.
- return S_OK;
- }
-
- if (m_scheduler.areSamplesScheduled()) {
- // Samples are still scheduled for rendering.
- return S_OK;
- }
-
- // Everything is complete. Now we can tell the EVR that we are done.
- notifyEvent(EC_COMPLETE, (LONG_PTR)S_OK, 0);
- m_endStreaming = false;
-
- stopSurface();
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::prepareFrameStep(DWORD steps)
-{
- HRESULT hr = S_OK;
-
- // Cache the step count.
- m_frameStep.steps += steps;
-
- // Set the frame-step state.
- m_frameStep.state = FrameStepWaitingStart;
-
- // If the clock is are already running, we can start frame-stepping now.
- // Otherwise, we will start when the clock starts.
- if (m_renderState == RenderStarted)
- hr = startFrameStep();
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::startFrameStep()
-{
- HRESULT hr = S_OK;
- IMFSample *sample = NULL;
-
- if (m_frameStep.state == FrameStepWaitingStart) {
- // We have a frame-step request, and are waiting for the clock to start.
- // Set the state to "pending," which means we are waiting for samples.
- m_frameStep.state = FrameStepPending;
-
- // If the frame-step queue already has samples, process them now.
- while (!m_frameStep.samples.isEmpty() && (m_frameStep.state == FrameStepPending)) {
- sample = m_frameStep.samples.takeFirst();
-
- hr = deliverFrameStepSample(sample);
- if (FAILED(hr))
- goto done;
-
- qt_evr_safe_release(&sample);
-
- // We break from this loop when:
- // (a) the frame-step queue is empty, or
- // (b) the frame-step operation is complete.
- }
- } else if (m_frameStep.state == FrameStepNone) {
- // We are not frame stepping. Therefore, if the frame-step queue has samples,
- // we need to process them normally.
- while (!m_frameStep.samples.isEmpty()) {
- sample = m_frameStep.samples.takeFirst();
-
- hr = deliverSample(sample, false);
- if (FAILED(hr))
- goto done;
-
- qt_evr_safe_release(&sample);
- }
- }
-
-done:
- qt_evr_safe_release(&sample);
- return hr;
-}
-
-HRESULT EVRCustomPresenter::completeFrameStep(IMFSample *sample)
-{
- HRESULT hr = S_OK;
- MFTIME sampleTime = 0;
- MFTIME systemTime = 0;
-
- // Update our state.
- m_frameStep.state = FrameStepComplete;
- m_frameStep.sampleNoRef = 0;
-
- // Notify the EVR that the frame-step is complete.
- notifyEvent(EC_STEP_COMPLETE, FALSE, 0); // FALSE = completed (not cancelled)
-
- // If we are scrubbing (rate == 0), also send the "scrub time" event.
- if (isScrubbing()) {
- // Get the time stamp from the sample.
- hr = sample->GetSampleTime(&sampleTime);
- if (FAILED(hr)) {
- // No time stamp. Use the current presentation time.
- if (m_clock)
- m_clock->GetCorrelatedTime(0, &sampleTime, &systemTime);
-
- hr = S_OK; // (Not an error condition.)
- }
-
- notifyEvent(EC_SCRUB_TIME, DWORD(sampleTime), DWORD(((sampleTime) >> 32) & 0xffffffff));
- }
- return hr;
-}
-
-HRESULT EVRCustomPresenter::cancelFrameStep()
-{
- FrameStepState oldState = m_frameStep.state;
-
- m_frameStep.state = FrameStepNone;
- m_frameStep.steps = 0;
- m_frameStep.sampleNoRef = 0;
- // Don't clear the frame-step queue yet, because we might frame step again.
-
- if (oldState > FrameStepNone && oldState < FrameStepComplete) {
- // We were in the middle of frame-stepping when it was cancelled.
- // Notify the EVR.
- notifyEvent(EC_STEP_COMPLETE, TRUE, 0); // TRUE = cancelled
- }
- return S_OK;
-}
-
-HRESULT EVRCustomPresenter::createOptimalVideoType(IMFMediaType *proposedType, IMFMediaType **optimalType)
-{
- HRESULT hr = S_OK;
-
- RECT rcOutput;
- ZeroMemory(&rcOutput, sizeof(rcOutput));
-
- MFVideoArea displayArea;
- ZeroMemory(&displayArea, sizeof(displayArea));
-
- IMFMediaType *mtOptimal = NULL;
-
- UINT64 size;
- int width;
- int height;
-
- // Clone the proposed type.
-
- hr = MFCreateMediaType(&mtOptimal);
- if (FAILED(hr))
- goto done;
-
- hr = proposedType->CopyAllItems(mtOptimal);
- if (FAILED(hr))
- goto done;
-
- // Modify the new type.
-
- hr = proposedType->GetUINT64(MF_MT_FRAME_SIZE, &size);
- width = int(HI32(size));
- height = int(LO32(size));
- rcOutput.left = 0;
- rcOutput.top = 0;
- rcOutput.right = width;
- rcOutput.bottom = height;
-
- // Set the geometric aperture, and disable pan/scan.
- displayArea = qt_evr_makeMFArea(0, 0, rcOutput.right, rcOutput.bottom);
-
- hr = mtOptimal->SetUINT32(MF_MT_PAN_SCAN_ENABLED, FALSE);
- if (FAILED(hr))
- goto done;
-
- hr = mtOptimal->SetBlob(MF_MT_GEOMETRIC_APERTURE, reinterpret_cast<UINT8*>(&displayArea),
- sizeof(displayArea));
- if (FAILED(hr))
- goto done;
-
- // Set the pan/scan aperture and the minimum display aperture. We don't care
- // about them per se, but the mixer will reject the type if these exceed the
- // frame dimentions.
- hr = mtOptimal->SetBlob(MF_MT_PAN_SCAN_APERTURE, reinterpret_cast<UINT8*>(&displayArea),
- sizeof(displayArea));
- if (FAILED(hr))
- goto done;
-
- hr = mtOptimal->SetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, reinterpret_cast<UINT8*>(&displayArea),
- sizeof(displayArea));
- if (FAILED(hr))
- goto done;
-
- // Return the pointer to the caller.
- *optimalType = mtOptimal;
- (*optimalType)->AddRef();
-
-done:
- qt_evr_safe_release(&mtOptimal);
- return hr;
-
-}
-
-HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType)
-{
- // Note: mediaType can be NULL (to clear the type)
-
- // Clearing the media type is allowed in any state (including shutdown).
- if (!mediaType) {
- stopSurface();
- qt_evr_safe_release(&m_mediaType);
- releaseResources();
- return S_OK;
- }
-
- MFRatio fps = { 0, 0 };
- QList<IMFSample*> sampleQueue;
-
- // Cannot set the media type after shutdown.
- HRESULT hr = checkShutdown();
- if (FAILED(hr))
- goto done;
-
- // Check if the new type is actually different.
- // Note: This function safely handles NULL input parameters.
- if (qt_evr_areMediaTypesEqual(m_mediaType, mediaType))
- goto done; // Nothing more to do.
-
- // We're really changing the type. First get rid of the old type.
- qt_evr_safe_release(&m_mediaType);
- releaseResources();
-
- // Initialize the presenter engine with the new media type.
- // The presenter engine allocates the samples.
-
- hr = m_presentEngine->createVideoSamples(mediaType, sampleQueue);
- if (FAILED(hr))
- goto done;
-
- // Mark each sample with our token counter. If this batch of samples becomes
- // invalid, we increment the counter, so that we know they should be discarded.
- for (auto sample : qAsConst(sampleQueue)) {
- hr = sample->SetUINT32(MFSamplePresenter_SampleCounter, m_tokenCounter);
- if (FAILED(hr))
- goto done;
- }
-
- // Add the samples to the sample pool.
- hr = m_samplePool.initialize(sampleQueue);
- if (FAILED(hr))
- goto done;
-
- // Set the frame rate on the scheduler.
- if (SUCCEEDED(qt_evr_getFrameRate(mediaType, &fps)) && (fps.Numerator != 0) && (fps.Denominator != 0)) {
- m_scheduler.setFrameRate(fps);
- } else {
- // NOTE: The mixer's proposed type might not have a frame rate, in which case
- // we'll use an arbitrary default. (Although it's unlikely the video source
- // does not have a frame rate.)
- m_scheduler.setFrameRate(g_DefaultFrameRate);
- }
-
- // Store the media type.
- m_mediaType = mediaType;
- m_mediaType->AddRef();
-
- startSurface();
-
-done:
- if (FAILED(hr))
- releaseResources();
- return hr;
-}
-
-HRESULT EVRCustomPresenter::isMediaTypeSupported(IMFMediaType *proposed)
-{
- D3DFORMAT d3dFormat = D3DFMT_UNKNOWN;
- BOOL compressed = FALSE;
- MFVideoInterlaceMode interlaceMode = MFVideoInterlace_Unknown;
- MFVideoArea videoCropArea;
- UINT32 width = 0, height = 0;
-
- // Validate the format.
- HRESULT hr = qt_evr_getFourCC(proposed, reinterpret_cast<DWORD*>(&d3dFormat));
- if (FAILED(hr))
- return hr;
-
- QVideoFrameFormat::PixelFormat pixelFormat = pixelFormatFromMediaType(proposed);
- if (pixelFormat == QVideoFrameFormat::Format_Invalid)
- return MF_E_INVALIDMEDIATYPE;
-
- // Reject compressed media types.
- hr = proposed->IsCompressedFormat(&compressed);
- if (FAILED(hr))
- return hr;
-
- if (compressed)
- return MF_E_INVALIDMEDIATYPE;
-
- // The D3DPresentEngine checks whether surfaces can be created using this format
- hr = m_presentEngine->checkFormat(d3dFormat);
- if (FAILED(hr))
- return hr;
-
- // Reject interlaced formats.
- hr = proposed->GetUINT32(MF_MT_INTERLACE_MODE, reinterpret_cast<UINT32*>(&interlaceMode));
- if (FAILED(hr))
- return hr;
-
- if (interlaceMode != MFVideoInterlace_Progressive)
- return MF_E_INVALIDMEDIATYPE;
-
- hr = MFGetAttributeSize(proposed, MF_MT_FRAME_SIZE, &width, &height);
- if (FAILED(hr))
- return hr;
-
- // Validate the various apertures (cropping regions) against the frame size.
- // Any of these apertures may be unspecified in the media type, in which case
- // we ignore it. We just want to reject invalid apertures.
-
- if (SUCCEEDED(proposed->GetBlob(MF_MT_PAN_SCAN_APERTURE,
- reinterpret_cast<UINT8*>(&videoCropArea),
- sizeof(videoCropArea), nullptr))) {
- hr = qt_evr_validateVideoArea(videoCropArea, width, height);
- }
- if (SUCCEEDED(proposed->GetBlob(MF_MT_GEOMETRIC_APERTURE,
- reinterpret_cast<UINT8*>(&videoCropArea),
- sizeof(videoCropArea), nullptr))) {
- hr = qt_evr_validateVideoArea(videoCropArea, width, height);
- }
- if (SUCCEEDED(proposed->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
- reinterpret_cast<UINT8*>(&videoCropArea),
- sizeof(videoCropArea), nullptr))) {
- hr = qt_evr_validateVideoArea(videoCropArea, width, height);
- }
- return hr;
-}
-
-void EVRCustomPresenter::processOutputLoop()
-{
- HRESULT hr = S_OK;
-
- // Process as many samples as possible.
- while (hr == S_OK) {
- // If the mixer doesn't have a new input sample, break from the loop.
- if (!m_sampleNotify) {
- hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
- break;
- }
-
- // Try to process a sample.
- hr = processOutput();
-
- // NOTE: ProcessOutput can return S_FALSE to indicate it did not
- // process a sample. If so, break out of the loop.
- }
-
- if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
- // The mixer has run out of input data. Check for end-of-stream.
- checkEndOfStream();
- }
-}
-
-HRESULT EVRCustomPresenter::processOutput()
-{
- HRESULT hr = S_OK;
- DWORD status = 0;
- LONGLONG mixerStartTime = 0, mixerEndTime = 0;
- MFTIME systemTime = 0;
- BOOL repaint = m_repaint; // Temporarily store this state flag.
-
- MFT_OUTPUT_DATA_BUFFER dataBuffer;
- ZeroMemory(&dataBuffer, sizeof(dataBuffer));
-
- IMFSample *sample = NULL;
-
- // If the clock is not running, we present the first sample,
- // and then don't present any more until the clock starts.
-
- if ((m_renderState != RenderStarted) && !m_repaint && m_prerolled)
- return S_FALSE;
-
- // Make sure we have a pointer to the mixer.
- if (!m_mixer)
- return MF_E_INVALIDREQUEST;
-
- // Try to get a free sample from the video sample pool.
- hr = m_samplePool.getSample(&sample);
- if (hr == MF_E_SAMPLEALLOCATOR_EMPTY) // No free samples. Try again when a sample is released.
- return S_FALSE;
- if (FAILED(hr))
- return hr;
-
- // From now on, we have a valid video sample pointer, where the mixer will
- // write the video data.
-
- if (m_repaint) {
- // Repaint request. Ask the mixer for the most recent sample.
- setDesiredSampleTime(sample, m_scheduler.lastSampleTime(), m_scheduler.frameDuration());
-
- m_repaint = false; // OK to clear this flag now.
- } else {
- // Not a repaint request. Clear the desired sample time; the mixer will
- // give us the next frame in the stream.
- clearDesiredSampleTime(sample);
-
- if (m_clock) {
- // Latency: Record the starting time for ProcessOutput.
- m_clock->GetCorrelatedTime(0, &mixerStartTime, &systemTime);
- }
- }
-
- // Now we are ready to get an output sample from the mixer.
- dataBuffer.dwStreamID = 0;
- dataBuffer.pSample = sample;
- dataBuffer.dwStatus = 0;
-
- hr = m_mixer->ProcessOutput(0, 1, &dataBuffer, &status);
-
- if (FAILED(hr)) {
- // Return the sample to the pool.
- HRESULT hr2 = m_samplePool.returnSample(sample);
- if (FAILED(hr2)) {
- hr = hr2;
- goto done;
- }
- // Handle some known error codes from ProcessOutput.
- if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
- // The mixer's format is not set. Negotiate a new format.
- hr = renegotiateMediaType();
- } else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
- // There was a dynamic media type change. Clear our media type.
- setMediaType(NULL);
- } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
- // The mixer needs more input.
- // We have to wait for the mixer to get more input.
- m_sampleNotify = false;
- }
- } else {
- // We got an output sample from the mixer.
-
- if (m_clock && !repaint) {
- // Latency: Record the ending time for the ProcessOutput operation,
- // and notify the EVR of the latency.
-
- m_clock->GetCorrelatedTime(0, &mixerEndTime, &systemTime);
-
- LONGLONG latencyTime = mixerEndTime - mixerStartTime;
- notifyEvent(EC_PROCESSING_LATENCY, reinterpret_cast<LONG_PTR>(&latencyTime), 0);
- }
-
- // Set up notification for when the sample is released.
- hr = trackSample(sample);
- if (FAILED(hr))
- goto done;
-
- // Schedule the sample.
- if ((m_frameStep.state == FrameStepNone) || repaint) {
- hr = deliverSample(sample, repaint);
- if (FAILED(hr))
- goto done;
- } else {
- // We are frame-stepping (and this is not a repaint request).
- hr = deliverFrameStepSample(sample);
- if (FAILED(hr))
- goto done;
- }
-
- m_prerolled = true; // We have presented at least one sample now.
- }
-
-done:
- qt_evr_safe_release(&sample);
-
- // Important: Release any events returned from the ProcessOutput method.
- qt_evr_safe_release(&dataBuffer.pEvents);
- return hr;
-}
-
-HRESULT EVRCustomPresenter::deliverSample(IMFSample *sample, bool repaint)
-{
- // If we are not actively playing, OR we are scrubbing (rate = 0) OR this is a
- // repaint request, then we need to present the sample immediately. Otherwise,
- // schedule it normally.
-
- bool presentNow = ((m_renderState != RenderStarted) || isScrubbing() || repaint);
-
- HRESULT hr = m_scheduler.scheduleSample(sample, presentNow);
-
- if (FAILED(hr)) {
- // Notify the EVR that we have failed during streaming. The EVR will notify the
- // pipeline.
-
- notifyEvent(EC_ERRORABORT, hr, 0);
- }
-
- return hr;
-}
-
-HRESULT EVRCustomPresenter::deliverFrameStepSample(IMFSample *sample)
-{
- HRESULT hr = S_OK;
- IUnknown *unk = NULL;
-
- // For rate 0, discard any sample that ends earlier than the clock time.
- if (isScrubbing() && m_clock && qt_evr_isSampleTimePassed(m_clock, sample)) {
- // Discard this sample.
- } else if (m_frameStep.state >= FrameStepScheduled) {
- // A frame was already submitted. Put this sample on the frame-step queue,
- // in case we are asked to step to the next frame. If frame-stepping is
- // cancelled, this sample will be processed normally.
- sample->AddRef();
- m_frameStep.samples.append(sample);
- } else {
- // We're ready to frame-step.
-
- // Decrement the number of steps.
- if (m_frameStep.steps > 0)
- m_frameStep.steps--;
-
- if (m_frameStep.steps > 0) {
- // This is not the last step. Discard this sample.
- } else if (m_frameStep.state == FrameStepWaitingStart) {
- // This is the right frame, but the clock hasn't started yet. Put the
- // sample on the frame-step queue. When the clock starts, the sample
- // will be processed.
- sample->AddRef();
- m_frameStep.samples.append(sample);
- } else {
- // This is the right frame *and* the clock has started. Deliver this sample.
- hr = deliverSample(sample, false);
- if (FAILED(hr))
- goto done;
-
- // Query for IUnknown so that we can identify the sample later.
- // Per COM rules, an object always returns the same pointer when QI'ed for IUnknown.
- hr = sample->QueryInterface(IID_PPV_ARGS(&unk));
- if (FAILED(hr))
- goto done;
-
- m_frameStep.sampleNoRef = reinterpret_cast<DWORD_PTR>(unk); // No add-ref.
-
- // NOTE: We do not AddRef the IUnknown pointer, because that would prevent the
- // sample from invoking the OnSampleFree callback after the sample is presented.
- // We use this IUnknown pointer purely to identify the sample later; we never
- // attempt to dereference the pointer.
-
- m_frameStep.state = FrameStepScheduled;
- }
- }
-done:
- qt_evr_safe_release(&unk);
- return hr;
-}
-
-HRESULT EVRCustomPresenter::trackSample(IMFSample *sample)
-{
- IMFTrackedSample *tracked = NULL;
-
- HRESULT hr = sample->QueryInterface(IID_PPV_ARGS(&tracked));
-
- if (SUCCEEDED(hr))
- hr = tracked->SetAllocator(&m_sampleFreeCB, NULL);
-
- qt_evr_safe_release(&tracked);
- return hr;
-}
-
-void EVRCustomPresenter::releaseResources()
-{
- // Increment the token counter to indicate that all existing video samples
- // are "stale." As these samples get released, we'll dispose of them.
- //
- // Note: The token counter is required because the samples are shared
- // between more than one thread, and they are returned to the presenter
- // through an asynchronous callback (onSampleFree). Without the token, we
- // might accidentally re-use a stale sample after the ReleaseResources
- // method returns.
-
- m_tokenCounter++;
-
- flush();
-
- m_samplePool.clear();
-
- m_presentEngine->releaseResources();
-}
-
-HRESULT EVRCustomPresenter::onSampleFree(IMFAsyncResult *result)
-{
- IUnknown *object = NULL;
- IMFSample *sample = NULL;
- IUnknown *unk = NULL;
- UINT32 token;
-
- // Get the sample from the async result object.
- HRESULT hr = result->GetObject(&object);
- if (FAILED(hr))
- goto done;
-
- hr = object->QueryInterface(IID_PPV_ARGS(&sample));
- if (FAILED(hr))
- goto done;
-
- // If this sample was submitted for a frame-step, the frame step operation
- // is complete.
-
- if (m_frameStep.state == FrameStepScheduled) {
- // Query the sample for IUnknown and compare it to our cached value.
- hr = sample->QueryInterface(IID_PPV_ARGS(&unk));
- if (FAILED(hr))
- goto done;
-
- if (m_frameStep.sampleNoRef == reinterpret_cast<DWORD_PTR>(unk)) {
- // Notify the EVR.
- hr = completeFrameStep(sample);
- if (FAILED(hr))
- goto done;
- }
-
- // Note: Although object is also an IUnknown pointer, it is not
- // guaranteed to be the exact pointer value returned through
- // QueryInterface. Therefore, the second QueryInterface call is
- // required.
- }
-
- m_mutex.lock();
-
- token = MFGetAttributeUINT32(sample, MFSamplePresenter_SampleCounter, (UINT32)-1);
-
- if (token == m_tokenCounter) {
- // Return the sample to the sample pool.
- hr = m_samplePool.returnSample(sample);
- if (SUCCEEDED(hr)) {
- // A free sample is available. Process more data if possible.
- processOutputLoop();
- }
- }
-
- m_mutex.unlock();
-
-done:
- if (FAILED(hr))
- notifyEvent(EC_ERRORABORT, hr, 0);
- qt_evr_safe_release(&object);
- qt_evr_safe_release(&sample);
- qt_evr_safe_release(&unk);
- return hr;
-}
-
-float EVRCustomPresenter::getMaxRate(bool thin)
-{
- // Non-thinned:
- // If we have a valid frame rate and a monitor refresh rate, the maximum
- // playback rate is equal to the refresh rate. Otherwise, the maximum rate
- // is unbounded (FLT_MAX).
-
- // Thinned: The maximum rate is unbounded.
-
- float maxRate = FLT_MAX;
- MFRatio fps = { 0, 0 };
- UINT monitorRateHz = 0;
-
- if (!thin && m_mediaType) {
- qt_evr_getFrameRate(m_mediaType, &fps);
- monitorRateHz = m_presentEngine->refreshRate();
-
- if (fps.Denominator && fps.Numerator && monitorRateHz) {
- // Max Rate = Refresh Rate / Frame Rate
- maxRate = (float)MulDiv(monitorRateHz, fps.Denominator, fps.Numerator);
- }
- }
-
- return maxRate;
-}
-
-bool EVRCustomPresenter::event(QEvent *e)
-{
- switch (int(e->type())) {
- case StartSurface:
- startSurface();
- return true;
- case StopSurface:
- stopSurface();
- return true;
- case PresentSample:
- presentSample(static_cast<PresentSampleEvent *>(e)->sample());
- return true;
- default:
- break;
- }
- return QObject::event(e);
-}
-
-void EVRCustomPresenter::startSurface()
-{
- if (thread() != QThread::currentThread()) {
- QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StartSurface)));
- return;
- }
-}
-
-void EVRCustomPresenter::stopSurface()
-{
- if (thread() != QThread::currentThread()) {
- QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StopSurface)));
- return;
- }
-}
-
-void EVRCustomPresenter::presentSample(IMFSample *sample)
-{
- if (thread() != QThread::currentThread()) {
- QCoreApplication::postEvent(this, new PresentSampleEvent(sample));
- return;
- }
-
- if (!m_videoSink || !m_presentEngine->videoSurfaceFormat().isValid())
- return;
-
- QVideoFrame frame = m_presentEngine->makeVideoFrame(sample);
-
- // Since start/end times are related to a position when the clock is started,
- // to have times from the beginning, need to adjust it by adding seeked position.
- if (m_positionOffset) {
- if (frame.startTime())
- frame.setStartTime(frame.startTime() + m_positionOffset);
- if (frame.endTime())
- frame.setEndTime(frame.endTime() + m_positionOffset);
- }
-
- m_videoSink->platformVideoSink()->setVideoFrame(frame);
-}
-
-void EVRCustomPresenter::positionChanged(qint64 position)
-{
- m_positionOffset = position * 1000;
-}
-
-HRESULT setDesiredSampleTime(IMFSample *sample, const LONGLONG &sampleTime, const LONGLONG &duration)
-{
- if (!sample)
- return E_POINTER;
-
- HRESULT hr = S_OK;
- IMFDesiredSample *desired = NULL;
-
- hr = sample->QueryInterface(IID_PPV_ARGS(&desired));
- if (SUCCEEDED(hr))
- desired->SetDesiredSampleTimeAndDuration(sampleTime, duration);
-
- qt_evr_safe_release(&desired);
- return hr;
-}
-
-HRESULT clearDesiredSampleTime(IMFSample *sample)
-{
- if (!sample)
- return E_POINTER;
-
- HRESULT hr = S_OK;
-
- IMFDesiredSample *desired = NULL;
- IUnknown *unkSwapChain = NULL;
-
- // We store some custom attributes on the sample, so we need to cache them
- // and reset them.
- //
- // This works around the fact that IMFDesiredSample::Clear() removes all of the
- // attributes from the sample.
-
- UINT32 counter = MFGetAttributeUINT32(sample, MFSamplePresenter_SampleCounter, (UINT32)-1);
-
- hr = sample->QueryInterface(IID_PPV_ARGS(&desired));
- if (SUCCEEDED(hr)) {
- desired->Clear();
-
- hr = sample->SetUINT32(MFSamplePresenter_SampleCounter, counter);
- if (FAILED(hr))
- goto done;
- }
-
-done:
- qt_evr_safe_release(&unkSwapChain);
- qt_evr_safe_release(&desired);
- return hr;
-}
-
-HRESULT setMixerSourceRect(IMFTransform *mixer, const MFVideoNormalizedRect &sourceRect)
-{
- if (!mixer)
- return E_POINTER;
-
- IMFAttributes *attributes = NULL;
-
- HRESULT hr = mixer->GetAttributes(&attributes);
- if (SUCCEEDED(hr)) {
- hr = attributes->SetBlob(video_ZOOM_RECT, reinterpret_cast<const UINT8*>(&sourceRect),
- sizeof(sourceRect));
- attributes->Release();
- }
- return hr;
-}
-
-static QVideoFrameFormat::PixelFormat pixelFormatFromMediaType(IMFMediaType *type)
-{
- GUID majorType;
- if (FAILED(type->GetMajorType(&majorType)))
- return QVideoFrameFormat::Format_Invalid;
- if (majorType != MFMediaType_Video)
- return QVideoFrameFormat::Format_Invalid;
-
- GUID subtype;
- if (FAILED(type->GetGUID(MF_MT_SUBTYPE, &subtype)))
- return QVideoFrameFormat::Format_Invalid;
-
- return QWindowsMultimediaUtils::pixelFormatFromMediaSubtype(subtype);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/evr/evrcustompresenter_p.h b/src/multimedia/platform/windows/evr/evrcustompresenter_p.h
deleted file mode 100644
index 9b34e449f..000000000
--- a/src/multimedia/platform/windows/evr/evrcustompresenter_p.h
+++ /dev/null
@@ -1,387 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef EVRCUSTOMPRESENTER_H
-#define EVRCUSTOMPRESENTER_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>
-#include <qmutex.h>
-#include <qqueue.h>
-#include <qevent.h>
-#include <qvideoframeformat.h>
-#include <qvideosink.h>
-
-#include "evrdefs_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class EVRCustomPresenter;
-class D3DPresentEngine;
-
-template<class T>
-class AsyncCallback : public IMFAsyncCallback
-{
- Q_DISABLE_COPY(AsyncCallback)
-public:
- typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *asyncResult);
-
- AsyncCallback(T *parent, InvokeFn fn) : m_parent(parent), m_invokeFn(fn)
- {
- }
-
- // IUnknown
- STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override
- {
- if (!ppv)
- return E_POINTER;
-
- if (iid == __uuidof(IUnknown)) {
- *ppv = static_cast<IUnknown*>(static_cast<IMFAsyncCallback*>(this));
- } else if (iid == __uuidof(IMFAsyncCallback)) {
- *ppv = static_cast<IMFAsyncCallback*>(this);
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef() override {
- // Delegate to parent class.
- return m_parent->AddRef();
- }
- STDMETHODIMP_(ULONG) Release() override {
- // Delegate to parent class.
- return m_parent->Release();
- }
-
- // IMFAsyncCallback methods
- STDMETHODIMP GetParameters(DWORD*, DWORD*) override
- {
- // Implementation of this method is optional.
- return E_NOTIMPL;
- }
-
- STDMETHODIMP Invoke(IMFAsyncResult* asyncResult) override
- {
- return (m_parent->*m_invokeFn)(asyncResult);
- }
-
- T *m_parent;
- InvokeFn m_invokeFn;
-};
-
-class Scheduler
-{
- Q_DISABLE_COPY(Scheduler)
-public:
- enum ScheduleEvent
- {
- Terminate = WM_USER,
- Schedule = WM_USER + 1,
- Flush = WM_USER + 2
- };
-
- Scheduler(EVRCustomPresenter *presenter);
- ~Scheduler();
-
- void setFrameRate(const MFRatio &fps);
- void setClockRate(float rate) { m_playbackRate = rate; }
-
- const LONGLONG &lastSampleTime() const { return m_lastSampleTime; }
- const LONGLONG &frameDuration() const { return m_perFrameInterval; }
-
- HRESULT startScheduler(IMFClock *clock);
- HRESULT stopScheduler();
-
- HRESULT scheduleSample(IMFSample *sample, bool presentNow);
- HRESULT processSamplesInQueue(LONG *nextSleep);
- HRESULT processSample(IMFSample *sample, LONG *nextSleep);
- HRESULT flush();
-
- bool areSamplesScheduled();
-
- // ThreadProc for the scheduler thread.
- static DWORD WINAPI schedulerThreadProc(LPVOID parameter);
-
-private:
- DWORD schedulerThreadProcPrivate();
-
- EVRCustomPresenter *m_presenter;
-
- QQueue<IMFSample*> m_scheduledSamples; // Samples waiting to be presented.
-
- IMFClock *m_clock; // Presentation clock. Can be NULL.
-
- DWORD m_threadID;
- HANDLE m_schedulerThread;
- HANDLE m_threadReadyEvent;
- HANDLE m_flushEvent;
-
- float m_playbackRate;
- MFTIME m_perFrameInterval; // Duration of each frame.
- LONGLONG m_perFrame_1_4th; // 1/4th of the frame duration.
- MFTIME m_lastSampleTime; // Most recent sample time.
-
- QMutex m_mutex;
-};
-
-class SamplePool
-{
- Q_DISABLE_COPY(SamplePool)
-public:
- SamplePool();
- ~SamplePool();
-
- HRESULT initialize(QList<IMFSample*> &samples);
- HRESULT clear();
-
- HRESULT getSample(IMFSample **sample);
- HRESULT returnSample(IMFSample *sample);
-
-private:
- QMutex m_mutex;
- QList<IMFSample*> m_videoSampleQueue;
- bool m_initialized;
-};
-
-class EVRCustomPresenter
- : public QObject
- , public IMFVideoDeviceID
- , public IMFVideoPresenter // Inherits IMFClockStateSink
- , public IMFRateSupport
- , public IMFGetService
- , public IMFTopologyServiceLookupClient
-{
- Q_DISABLE_COPY(EVRCustomPresenter)
-public:
- // Defines the state of the presenter.
- enum RenderState
- {
- RenderStarted = 1,
- RenderStopped,
- RenderPaused,
- RenderShutdown // Initial state.
- };
-
- // Defines the presenter's state with respect to frame-stepping.
- enum FrameStepState
- {
- FrameStepNone, // Not frame stepping.
- FrameStepWaitingStart, // Frame stepping, but the clock is not started.
- FrameStepPending, // Clock is started. Waiting for samples.
- FrameStepScheduled, // Submitted a sample for rendering.
- FrameStepComplete // Sample was rendered.
- };
-
- enum PresenterEvents
- {
- StartSurface = QEvent::User,
- StopSurface = QEvent::User + 1,
- PresentSample = QEvent::User + 2
- };
-
- EVRCustomPresenter(QVideoSink *sink = 0);
- ~EVRCustomPresenter() override;
-
- bool isValid() const;
-
- // IUnknown methods
- STDMETHODIMP QueryInterface(REFIID riid, void ** ppv) override;
- STDMETHODIMP_(ULONG) AddRef() override;
- STDMETHODIMP_(ULONG) Release() override;
-
- // IMFGetService methods
- STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID *ppvObject) override;
-
- // IMFVideoPresenter methods
- STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE message, ULONG_PTR param) override;
- STDMETHODIMP GetCurrentMediaType(IMFVideoMediaType** mediaType) override;
-
- // IMFClockStateSink methods
- STDMETHODIMP OnClockStart(MFTIME systemTime, LONGLONG clockStartOffset) override;
- STDMETHODIMP OnClockStop(MFTIME systemTime) override;
- STDMETHODIMP OnClockPause(MFTIME systemTime) override;
- STDMETHODIMP OnClockRestart(MFTIME systemTime) override;
- STDMETHODIMP OnClockSetRate(MFTIME systemTime, float rate) override;
-
- // IMFRateSupport methods
- STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate) override;
- STDMETHODIMP GetFastestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate) override;
- STDMETHODIMP IsRateSupported(BOOL thin, float rate, float *nearestSupportedRate) override;
-
- // IMFVideoDeviceID methods
- STDMETHODIMP GetDeviceID(IID* deviceID) override;
-
- // IMFTopologyServiceLookupClient methods
- STDMETHODIMP InitServicePointers(IMFTopologyServiceLookup *lookup) override;
- STDMETHODIMP ReleaseServicePointers() override;
-
- void supportedFormatsChanged();
- void setSink(QVideoSink *sink);
-
- void startSurface();
- void stopSurface();
- void presentSample(IMFSample *sample);
-
- bool event(QEvent *) override;
-
-public Q_SLOTS:
- void positionChanged(qint64 position);
-
-private:
- HRESULT checkShutdown() const
- {
- if (m_renderState == RenderShutdown)
- return MF_E_SHUTDOWN;
- else
- return S_OK;
- }
-
- // The "active" state is started or paused.
- inline bool isActive() const
- {
- return ((m_renderState == RenderStarted) || (m_renderState == RenderPaused));
- }
-
- // Scrubbing occurs when the frame rate is 0.
- inline bool isScrubbing() const { return m_playbackRate == 0.0f; }
-
- // Send an event to the EVR through its IMediaEventSink interface.
- void notifyEvent(long eventCode, LONG_PTR param1, LONG_PTR param2)
- {
- if (m_mediaEventSink)
- m_mediaEventSink->Notify(eventCode, param1, param2);
- }
-
- float getMaxRate(bool thin);
-
- // Mixer operations
- HRESULT configureMixer(IMFTransform *mixer);
-
- // Formats
- HRESULT createOptimalVideoType(IMFMediaType* proposed, IMFMediaType **optimal);
- HRESULT setMediaType(IMFMediaType *mediaType);
- HRESULT isMediaTypeSupported(IMFMediaType *mediaType);
-
- // Message handlers
- HRESULT flush();
- HRESULT renegotiateMediaType();
- HRESULT processInputNotify();
- HRESULT beginStreaming();
- HRESULT endStreaming();
- HRESULT checkEndOfStream();
-
- // Managing samples
- void processOutputLoop();
- HRESULT processOutput();
- HRESULT deliverSample(IMFSample *sample, bool repaint);
- HRESULT trackSample(IMFSample *sample);
- void releaseResources();
-
- // Frame-stepping
- HRESULT prepareFrameStep(DWORD steps);
- HRESULT startFrameStep();
- HRESULT deliverFrameStepSample(IMFSample *sample);
- HRESULT completeFrameStep(IMFSample *sample);
- HRESULT cancelFrameStep();
-
- // Callback when a video sample is released.
- HRESULT onSampleFree(IMFAsyncResult *result);
- AsyncCallback<EVRCustomPresenter> m_sampleFreeCB;
-
- // Holds information related to frame-stepping.
- struct FrameStep
- {
- FrameStepState state = FrameStepNone;
- QList<IMFSample*> samples;
- DWORD steps = 0;
- DWORD_PTR sampleNoRef = 0;
- };
-
- long m_refCount;
-
- RenderState m_renderState;
- FrameStep m_frameStep;
-
- QRecursiveMutex m_mutex;
-
- // Samples and scheduling
- Scheduler m_scheduler; // Manages scheduling of samples.
- SamplePool m_samplePool; // Pool of allocated samples.
- DWORD m_tokenCounter; // Counter. Incremented whenever we create new samples.
-
- // Rendering state
- bool m_sampleNotify; // Did the mixer signal it has an input sample?
- bool m_repaint; // Do we need to repaint the last sample?
- bool m_prerolled; // Have we presented at least one sample?
- bool m_endStreaming; // Did we reach the end of the stream (EOS)?
-
- MFVideoNormalizedRect m_sourceRect;
- float m_playbackRate;
-
- D3DPresentEngine *m_presentEngine; // Rendering engine. (Never null if the constructor succeeds.)
-
- IMFClock *m_clock; // The EVR's clock.
- IMFTransform *m_mixer; // The EVR's mixer.
- IMediaEventSink *m_mediaEventSink; // The EVR's event-sink interface.
- IMFMediaType *m_mediaType; // Output media type
-
- QVideoSink *m_videoSink;
- bool m_canRenderToSurface;
- qint64 m_positionOffset; // Seek position in microseconds.
-};
-
-bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter);
-
-QT_END_NAMESPACE
-
-#endif // EVRCUSTOMPRESENTER_H
diff --git a/src/multimedia/platform/windows/evr/evrd3dpresentengine.cpp b/src/multimedia/platform/windows/evr/evrd3dpresentengine.cpp
deleted file mode 100644
index 89c22d3ae..000000000
--- a/src/multimedia/platform/windows/evr/evrd3dpresentengine.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "evrd3dpresentengine_p.h"
-
-#include "evrhelpers_p.h"
-
-#include <private/qabstractvideobuffer_p.h>
-#include <qvideoframe.h>
-#include <QDebug>
-#include <qthread.h>
-#include <QOffscreenSurface>
-
-static const int PRESENTER_BUFFER_COUNT = 3;
-
-QT_BEGIN_NAMESPACE
-
-class IMFSampleVideoBuffer: public QAbstractVideoBuffer
-{
-public:
- IMFSampleVideoBuffer(D3DPresentEngine *engine, IMFSample *sample, QVideoFrame::HandleType handleType)
- : QAbstractVideoBuffer(handleType)
- , m_sample(sample)
- , m_surface(0)
- , m_mapMode(QVideoFrame::NotMapped)
- {
- if (m_sample) {
- m_sample->AddRef();
-
- IMFMediaBuffer *buffer;
- if (SUCCEEDED(m_sample->GetBufferByIndex(0, &buffer))) {
- MFGetService(buffer,
- mr_BUFFER_SERVICE,
- iid_IDirect3DSurface9,
- reinterpret_cast<void **>(&m_surface));
- buffer->Release();
- }
- }
- }
-
- ~IMFSampleVideoBuffer() override
- {
- if (m_surface) {
- if (m_mapMode != QVideoFrame::NotMapped)
- m_surface->UnlockRect();
- m_surface->Release();
- }
- if (m_sample)
- m_sample->Release();
- }
-
- QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
- MapData map(QVideoFrame::MapMode mode) override;
- void unmap() override;
-
-private:
- IMFSample *m_sample;
- IDirect3DSurface9 *m_surface;
- QVideoFrame::MapMode m_mapMode;
-};
-
-IMFSampleVideoBuffer::MapData IMFSampleVideoBuffer::map(QVideoFrame::MapMode mode)
-{
- if (!m_surface || m_mapMode != QVideoFrame::NotMapped)
- return {};
-
- D3DSURFACE_DESC desc;
- if (FAILED(m_surface->GetDesc(&desc)))
- return {};
-
- D3DLOCKED_RECT rect;
- if (FAILED(m_surface->LockRect(&rect, NULL, mode == QVideoFrame::ReadOnly ? D3DLOCK_READONLY : 0)))
- return {};
-
- m_mapMode = mode;
-
- MapData mapData;
- mapData.nPlanes = 1;
- mapData.bytesPerLine[0] = (int)rect.Pitch;
- mapData.data[0] = reinterpret_cast<uchar *>(rect.pBits);
- mapData.size[0] = (int)(rect.Pitch * desc.Height);
- return mapData;
-}
-
-void IMFSampleVideoBuffer::unmap()
-{
- if (m_mapMode == QVideoFrame::NotMapped)
- return;
-
- m_mapMode = QVideoFrame::NotMapped;
- m_surface->UnlockRect();
-}
-
-D3DPresentEngine::D3DPresentEngine()
- : m_deviceResetToken(0)
- , m_D3D9(0)
- , m_device(0)
- , m_devices(0)
- , m_useTextureRendering(false)
-{
- ZeroMemory(&m_displayMode, sizeof(m_displayMode));
-
- HRESULT hr = initializeD3D();
-
- if (SUCCEEDED(hr)) {
- hr = createD3DDevice();
- if (FAILED(hr))
- qWarning("Failed to create D3D device");
- } else {
- qWarning("Failed to initialize D3D");
- }
-}
-
-D3DPresentEngine::~D3DPresentEngine()
-{
- releaseResources();
-
- qt_evr_safe_release(&m_device);
- qt_evr_safe_release(&m_devices);
- qt_evr_safe_release(&m_D3D9);
-}
-
-HRESULT D3DPresentEngine::initializeD3D()
-{
- HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_D3D9);
-
- if (SUCCEEDED(hr))
- hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, &m_devices);
-
- return hr;
-}
-
-HRESULT D3DPresentEngine::createD3DDevice()
-{
- HRESULT hr = S_OK;
- HWND hwnd = NULL;
- UINT uAdapterID = D3DADAPTER_DEFAULT;
- DWORD vp = 0;
-
- D3DCAPS9 ddCaps;
- ZeroMemory(&ddCaps, sizeof(ddCaps));
-
- IDirect3DDevice9Ex* device = NULL;
-
- if (!m_D3D9 || !m_devices)
- return MF_E_NOT_INITIALIZED;
-
- hwnd = ::GetShellWindow();
-
- D3DPRESENT_PARAMETERS pp;
- ZeroMemory(&pp, sizeof(pp));
-
- pp.BackBufferWidth = 1;
- pp.BackBufferHeight = 1;
- pp.BackBufferFormat = D3DFMT_UNKNOWN;
- pp.BackBufferCount = 1;
- pp.Windowed = TRUE;
- pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
- pp.BackBufferFormat = D3DFMT_UNKNOWN;
- pp.hDeviceWindow = hwnd;
- pp.Flags = D3DPRESENTFLAG_VIDEO;
- pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
-
- hr = m_D3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps);
- if (FAILED(hr))
- goto done;
-
- if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
- vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
- else
- vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
-
- hr = m_D3D9->CreateDeviceEx(
- uAdapterID,
- D3DDEVTYPE_HAL,
- pp.hDeviceWindow,
- vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
- &pp,
- NULL,
- &device
- );
- if (FAILED(hr))
- goto done;
-
- hr = m_D3D9->GetAdapterDisplayMode(uAdapterID, &m_displayMode);
- if (FAILED(hr))
- goto done;
-
- hr = m_devices->ResetDevice(device, m_deviceResetToken);
- if (FAILED(hr))
- goto done;
-
- qt_evr_safe_release(&m_device);
-
- m_device = device;
- m_device->AddRef();
-
-done:
- qt_evr_safe_release(&device);
- return hr;
-}
-
-bool D3DPresentEngine::isValid() const
-{
- return m_device != NULL;
-}
-
-void D3DPresentEngine::releaseResources()
-{
- m_surfaceFormat = QVideoFrameFormat();
-}
-
-HRESULT D3DPresentEngine::getService(REFGUID, REFIID riid, void** ppv)
-{
- HRESULT hr = S_OK;
-
- if (riid == __uuidof(IDirect3DDeviceManager9)) {
- if (m_devices == NULL) {
- hr = MF_E_UNSUPPORTED_SERVICE;
- } else {
- *ppv = m_devices;
- m_devices->AddRef();
- }
- } else {
- hr = MF_E_UNSUPPORTED_SERVICE;
- }
-
- return hr;
-}
-
-HRESULT D3DPresentEngine::checkFormat(D3DFORMAT format)
-{
- if (!m_D3D9 || !m_device)
- return E_FAIL;
-
- HRESULT hr = S_OK;
-
- D3DDISPLAYMODE mode;
- D3DDEVICE_CREATION_PARAMETERS params;
-
- hr = m_device->GetCreationParameters(&params);
- if (FAILED(hr))
- return hr;
-
- UINT uAdapter = params.AdapterOrdinal;
- D3DDEVTYPE type = params.DeviceType;
-
- hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &mode);
- if (FAILED(hr))
- return hr;
-
- hr = m_D3D9->CheckDeviceFormat(uAdapter, type, mode.Format,
- D3DUSAGE_RENDERTARGET,
- D3DRTYPE_SURFACE,
- format);
-
- if (m_useTextureRendering && format != D3DFMT_X8R8G8B8 && format != D3DFMT_A8R8G8B8) {
- // The texture is always in RGB32 so the d3d driver must support conversion from the
- // requested format to RGB32.
- hr = m_D3D9->CheckDeviceFormatConversion(uAdapter, type, format, D3DFMT_X8R8G8B8);
- }
-
- return hr;
-}
-
-bool D3DPresentEngine::supportsTextureRendering() const
-{
- return false;
-}
-
-void D3DPresentEngine::setHint(Hint hint, bool enable)
-{
- if (hint == RenderToTexture)
- m_useTextureRendering = enable && supportsTextureRendering();
-}
-
-HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue)
-{
- if (!format)
- return MF_E_UNEXPECTED;
-
- HRESULT hr = S_OK;
-
- IDirect3DSurface9 *surface = NULL;
- IMFSample *videoSample = NULL;
-
- releaseResources();
-
- UINT32 width = 0, height = 0;
- hr = MFGetAttributeSize(format, MF_MT_FRAME_SIZE, &width, &height);
- if (FAILED(hr))
- return hr;
-
- DWORD d3dFormat = 0;
- hr = qt_evr_getFourCC(format, &d3dFormat);
- if (FAILED(hr))
- return hr;
-
- // Create the video samples.
- for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++) {
- hr = m_device->CreateRenderTarget(width, height,
- (D3DFORMAT)d3dFormat,
- D3DMULTISAMPLE_NONE,
- 0,
- TRUE,
- &surface, NULL);
- if (FAILED(hr))
- goto done;
-
- hr = MFCreateVideoSampleFromSurface(surface, &videoSample);
- if (FAILED(hr))
- goto done;
-
- videoSample->AddRef();
- videoSampleQueue.append(videoSample);
-
- qt_evr_safe_release(&videoSample);
- qt_evr_safe_release(&surface);
- }
-
-done:
- if (SUCCEEDED(hr)) {
- m_surfaceFormat = QVideoFrameFormat(QSize(width, height),
- m_useTextureRendering ? QVideoFrameFormat::Format_BGRX8888
- : qt_evr_pixelFormatFromD3DFormat(d3dFormat));
- } else {
- releaseResources();
- }
-
- qt_evr_safe_release(&videoSample);
- qt_evr_safe_release(&surface);
- return hr;
-}
-
-QVideoFrame D3DPresentEngine::makeVideoFrame(IMFSample *sample)
-{
- if (!sample)
- return QVideoFrame();
-
- QVideoFrame frame(new IMFSampleVideoBuffer(this, sample, (m_useTextureRendering ? QVideoFrame::RhiTextureHandle : QVideoFrame::NoHandle)),
- m_surfaceFormat);
-
- // WMF uses 100-nanosecond units, Qt uses microseconds
- LONGLONG startTime = 0;
- auto hr = sample->GetSampleTime(&startTime);
- if (SUCCEEDED(hr)) {
- frame.setStartTime(startTime * 0.1);
-
- LONGLONG duration = -1;
- if (SUCCEEDED(sample->GetSampleDuration(&duration)))
- frame.setEndTime((startTime + duration) * 0.1);
- }
-
- return frame;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/evr/evrd3dpresentengine_p.h b/src/multimedia/platform/windows/evr/evrd3dpresentengine_p.h
deleted file mode 100644
index 6b8353c53..000000000
--- a/src/multimedia/platform/windows/evr/evrd3dpresentengine_p.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef EVRD3DPRESENTENGINE_H
-#define EVRD3DPRESENTENGINE_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 <QMutex>
-#include <QVideoFrameFormat>
-
-#include <d3d9.h>
-
-struct IDirect3D9Ex;
-struct IDirect3DDevice9Ex;
-struct IDirect3DDeviceManager9;
-struct IDirect3DSurface9;
-struct IDirect3DTexture9;
-struct IMFSample;
-struct IMFMediaType;
-
-QT_BEGIN_NAMESPACE
-class QVideoFrame;
-QT_END_NAMESPACE
-
-// Randomly generated GUIDs
-static const GUID MFSamplePresenter_SampleCounter =
-{ 0xb0bb83cc, 0xf10f, 0x4e2e, { 0xaa, 0x2b, 0x29, 0xea, 0x5e, 0x92, 0xef, 0x85 } };
-
-QT_BEGIN_NAMESPACE
-
-#ifdef MAYBE_ANGLE
-
-class OpenGLResources;
-
-class EGLWrapper
-{
- Q_DISABLE_COPY(EGLWrapper)
-public:
- EGLWrapper();
-
- __eglMustCastToProperFunctionPointerType getProcAddress(const char *procname);
- EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
- EGLBoolean destroySurface(EGLDisplay dpy, EGLSurface surface);
- EGLBoolean bindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
- EGLBoolean releaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-
-private:
- typedef __eglMustCastToProperFunctionPointerType (EGLAPIENTRYP EglGetProcAddress)(const char *procname);
- typedef EGLSurface (EGLAPIENTRYP EglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
- typedef EGLBoolean (EGLAPIENTRYP EglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
- typedef EGLBoolean (EGLAPIENTRYP EglBindTexImage)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
- typedef EGLBoolean (EGLAPIENTRYP EglReleaseTexImage)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-
- EglGetProcAddress m_eglGetProcAddress;
- EglCreatePbufferSurface m_eglCreatePbufferSurface;
- EglDestroySurface m_eglDestroySurface;
- EglBindTexImage m_eglBindTexImage;
- EglReleaseTexImage m_eglReleaseTexImage;
-};
-
-#endif // MAYBE_ANGLE
-
-class D3DPresentEngine
-{
- Q_DISABLE_COPY(D3DPresentEngine)
-public:
- enum Hint
- {
- RenderToTexture
- };
-
- D3DPresentEngine();
- virtual ~D3DPresentEngine();
-
- bool isValid() const;
- void setHint(Hint hint, bool enable = true);
-
- HRESULT getService(REFGUID guidService, REFIID riid, void** ppv);
- HRESULT checkFormat(D3DFORMAT format);
- UINT refreshRate() const { return m_displayMode.RefreshRate; }
-
- bool supportsTextureRendering() const;
- bool isTextureRenderingEnabled() const { return m_useTextureRendering; }
-
- HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue);
- QVideoFrameFormat videoSurfaceFormat() const { return m_surfaceFormat; }
- QVideoFrame makeVideoFrame(IMFSample* sample);
-
- void releaseResources();
-
-private:
- HRESULT initializeD3D();
- HRESULT createD3DDevice();
-
-
- UINT m_deviceResetToken;
- D3DDISPLAYMODE m_displayMode;
-
- IDirect3D9Ex *m_D3D9;
- IDirect3DDevice9Ex *m_device;
- IDirect3DDeviceManager9 *m_devices;
-
- QVideoFrameFormat m_surfaceFormat;
-
- bool m_useTextureRendering;
-
-#ifdef MAYBE_ANGLE
- unsigned int updateTexture(IDirect3DSurface9 *src);
-
- OpenGLResources *m_glResources;
- IDirect3DTexture9 *m_texture;
-#endif
-
- friend class IMFSampleVideoBuffer;
-};
-
-QT_END_NAMESPACE
-
-#endif // EVRD3DPRESENTENGINE_H
diff --git a/src/multimedia/platform/windows/evr/evrdefs.cpp b/src/multimedia/platform/windows/evr/evrdefs.cpp
deleted file mode 100644
index 94370a14a..000000000
--- a/src/multimedia/platform/windows/evr/evrdefs.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "evrdefs_p.h"
-
-const CLSID clsid_EnhancedVideoRenderer = { 0xfa10746c, 0x9b63, 0x4b6c, {0xbc, 0x49, 0xfc, 0x30, 0xe, 0xa5, 0xf2, 0x56} };
-const GUID mr_VIDEO_RENDER_SERVICE = { 0x1092a86c, 0xab1a, 0x459a, {0xa3, 0x36, 0x83, 0x1f, 0xbc, 0x4d, 0x11, 0xff} };
-const GUID mr_VIDEO_MIXER_SERVICE = { 0x73cd2fc, 0x6cf4, 0x40b7, {0x88, 0x59, 0xe8, 0x95, 0x52, 0xc8, 0x41, 0xf8} };
-const GUID mr_BUFFER_SERVICE = { 0xa562248c, 0x9ac6, 0x4ffc, {0x9f, 0xba, 0x3a, 0xf8, 0xf8, 0xad, 0x1a, 0x4d} };
-const GUID video_ZOOM_RECT = { 0x7aaa1638, 0x1b7f, 0x4c93, {0xbd, 0x89, 0x5b, 0x9c, 0x9f, 0xb6, 0xfc, 0xf0} };
-const GUID iid_IDirect3DDevice9 = { 0xd0223b96, 0xbf7a, 0x43fd, {0x92, 0xbd, 0xa4, 0x3b, 0xd, 0x82, 0xb9, 0xeb} };
-const GUID iid_IDirect3DSurface9 = { 0xcfbaf3a, 0x9ff6, 0x429a, {0x99, 0xb3, 0xa2, 0x79, 0x6a, 0xf8, 0xb8, 0x9b} };
diff --git a/src/multimedia/platform/windows/evr/evrdefs_p.h b/src/multimedia/platform/windows/evr/evrdefs_p.h
deleted file mode 100644
index f9df48387..000000000
--- a/src/multimedia/platform/windows/evr/evrdefs_p.h
+++ /dev/null
@@ -1,364 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef EVRDEFS_H
-#define EVRDEFS_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 <d3d9.h>
-#include <evr9.h>
-#include <evr.h>
-#include <dxva2api.h>
-#include <mfapi.h>
-#include <mfidl.h>
-#include <mferror.h>
-
-extern const CLSID clsid_EnhancedVideoRenderer;
-extern const GUID mr_VIDEO_RENDER_SERVICE;
-extern const GUID mr_VIDEO_MIXER_SERVICE;
-extern const GUID mr_BUFFER_SERVICE;
-extern const GUID video_ZOOM_RECT;
-extern const GUID iid_IDirect3DDevice9;
-extern const GUID iid_IDirect3DSurface9;
-
-// The following is required to compile with MinGW
-
-extern "C" {
-HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *pUnkSurface, IMFSample **ppSample);
-HRESULT WINAPI Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex**);
-}
-
-#ifndef PRESENTATION_CURRENT_POSITION
-#define PRESENTATION_CURRENT_POSITION 0x7fffffffffffffff
-#endif
-
-#ifndef MF_E_SHUTDOWN
-#define MF_E_SHUTDOWN ((HRESULT)0xC00D3E85L)
-#endif
-
-#ifndef MF_E_SAMPLEALLOCATOR_EMPTY
-#define MF_E_SAMPLEALLOCATOR_EMPTY ((HRESULT)0xC00D4A3EL)
-#endif
-
-#ifndef MF_E_TRANSFORM_STREAM_CHANGE
-#define MF_E_TRANSFORM_STREAM_CHANGE ((HRESULT)0xC00D6D61L)
-#endif
-
-#ifndef MF_E_TRANSFORM_NEED_MORE_INPUT
-#define MF_E_TRANSFORM_NEED_MORE_INPUT ((HRESULT)0xC00D6D72L)
-#endif
-
-#if defined(__GNUC__) && !defined(_MFVideoNormalizedRect_)
-#define _MFVideoNormalizedRect_
-typedef struct MFVideoNormalizedRect {
- float left;
- float top;
- float right;
- float bottom;
-} MFVideoNormalizedRect;
-#endif
-
-#include <initguid.h>
-
-#ifndef __IMFGetService_INTERFACE_DEFINED__
-#define __IMFGetService_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFGetService, 0xfa993888, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7);
-MIDL_INTERFACE("fa993888-4383-415a-a930-dd472a8cf6f7")
-IMFGetService : public IUnknown
-{
- virtual HRESULT STDMETHODCALLTYPE GetService(REFGUID, REFIID, LPVOID *) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFGetService, 0xfa993888, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7)
-#endif
-#endif // __IMFGetService_INTERFACE_DEFINED__
-
-#ifndef __IMFVideoDisplayControl_INTERFACE_DEFINED__
-#define __IMFVideoDisplayControl_INTERFACE_DEFINED__
-typedef enum MFVideoAspectRatioMode
-{
- MFVideoARMode_None = 0,
- MFVideoARMode_PreservePicture = 0x1,
- MFVideoARMode_PreservePixel = 0x2,
- MFVideoARMode_NonLinearStretch = 0x4,
- MFVideoARMode_Mask = 0x7
-} MFVideoAspectRatioMode;
-
-DEFINE_GUID(IID_IMFVideoDisplayControl, 0xa490b1e4, 0xab84, 0x4d31, 0xa1,0xb2, 0x18,0x1e,0x03,0xb1,0x07,0x7a);
-MIDL_INTERFACE("a490b1e4-ab84-4d31-a1b2-181e03b1077a")
-IMFVideoDisplayControl : public IUnknown
-{
- virtual HRESULT STDMETHODCALLTYPE GetNativeVideoSize(SIZE *, SIZE *) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetIdealVideoSize(SIZE *, SIZE *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetVideoPosition(const MFVideoNormalizedRect *, const LPRECT) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetVideoPosition(MFVideoNormalizedRect *, LPRECT) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetAspectRatioMode(DWORD) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetAspectRatioMode(DWORD *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetVideoWindow(HWND) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetVideoWindow(HWND *) = 0;
- virtual HRESULT STDMETHODCALLTYPE RepaintVideo(void) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCurrentImage(BITMAPINFOHEADER *, BYTE **, DWORD *, LONGLONG *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetBorderColor(COLORREF) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetBorderColor(COLORREF *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetRenderingPrefs(DWORD) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetRenderingPrefs(DWORD *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetFullscreen(BOOL) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFullscreen(BOOL *) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFVideoDisplayControl, 0xa490b1e4, 0xab84, 0x4d31, 0xa1,0xb2, 0x18,0x1e,0x03,0xb1,0x07,0x7a)
-#endif
-#endif // __IMFVideoDisplayControl_INTERFACE_DEFINED__
-
-#ifndef __IMFVideoProcessor_INTERFACE_DEFINED__
-#define __IMFVideoProcessor_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E);
-MIDL_INTERFACE("6AB0000C-FECE-4d1f-A2AC-A9573530656E")
-IMFVideoProcessor : public IUnknown
-{
- virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoProcessorModes(UINT *, GUID **) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorCaps(LPGUID, DXVA2_VideoProcessorCaps *) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorMode(LPGUID) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetVideoProcessorMode(LPGUID) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetProcAmpRange(DWORD, DXVA2_ValueRange *) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFilteringRange(DWORD, DXVA2_ValueRange *) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetBackgroundColor(COLORREF *) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetBackgroundColor(COLORREF) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E)
-#endif
-#endif // __IMFVideoProcessor_INTERFACE_DEFINED__
-
-#ifndef __IMFVideoDeviceID_INTERFACE_DEFINED__
-#define __IMFVideoDeviceID_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFVideoDeviceID, 0xA38D9567, 0x5A9C, 0x4f3c, 0xB2,0x93, 0x8E,0xB4,0x15,0xB2,0x79,0xBA);
-MIDL_INTERFACE("A38D9567-5A9C-4f3c-B293-8EB415B279BA")
-IMFVideoDeviceID : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetDeviceID(IID *pDeviceID) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFVideoDeviceID, 0xA38D9567, 0x5A9C, 0x4f3c, 0xB2,0x93, 0x8E,0xB4,0x15,0xB2,0x79,0xBA)
-#endif
-#endif // __IMFVideoDeviceID_INTERFACE_DEFINED__
-
-#ifndef __IMFClockStateSink_INTERFACE_DEFINED__
-#define __IMFClockStateSink_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFClockStateSink, 0xF6696E82, 0x74F7, 0x4f3d, 0xA1,0x78, 0x8A,0x5E,0x09,0xC3,0x65,0x9F);
-MIDL_INTERFACE("F6696E82-74F7-4f3d-A178-8A5E09C3659F")
-IMFClockStateSink : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) = 0;
- virtual HRESULT STDMETHODCALLTYPE OnClockStop(MFTIME hnsSystemTime) = 0;
- virtual HRESULT STDMETHODCALLTYPE OnClockPause(MFTIME hnsSystemTime) = 0;
- virtual HRESULT STDMETHODCALLTYPE OnClockRestart(MFTIME hnsSystemTime) = 0;
- virtual HRESULT STDMETHODCALLTYPE OnClockSetRate(MFTIME hnsSystemTime, float flRate) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFClockStateSink, 0xF6696E82, 0x74F7, 0x4f3d, 0xA1,0x78, 0x8A,0x5E,0x09,0xC3,0x65,0x9F)
-#endif
-#endif // __IMFClockStateSink_INTERFACE_DEFINED__
-
-#ifndef __IMFVideoPresenter_INTERFACE_DEFINED__
-#define __IMFVideoPresenter_INTERFACE_DEFINED__
-typedef enum MFVP_MESSAGE_TYPE
-{
- MFVP_MESSAGE_FLUSH = 0,
- MFVP_MESSAGE_INVALIDATEMEDIATYPE = 0x1,
- MFVP_MESSAGE_PROCESSINPUTNOTIFY = 0x2,
- MFVP_MESSAGE_BEGINSTREAMING = 0x3,
- MFVP_MESSAGE_ENDSTREAMING = 0x4,
- MFVP_MESSAGE_ENDOFSTREAM = 0x5,
- MFVP_MESSAGE_STEP = 0x6,
- MFVP_MESSAGE_CANCELSTEP = 0x7
-} MFVP_MESSAGE_TYPE;
-
-DEFINE_GUID(IID_IMFVideoPresenter, 0x29AFF080, 0x182A, 0x4a5d, 0xAF,0x3B, 0x44,0x8F,0x3A,0x63,0x46,0xCB);
-MIDL_INTERFACE("29AFF080-182A-4a5d-AF3B-448F3A6346CB")
-IMFVideoPresenter : public IMFClockStateSink
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCurrentMediaType(IMFVideoMediaType **ppMediaType) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFVideoPresenter, 0x29AFF080, 0x182A, 0x4a5d, 0xAF,0x3B, 0x44,0x8F,0x3A,0x63,0x46,0xCB)
-#endif
-#endif // __IMFVideoPresenter_INTERFACE_DEFINED__
-
-#ifndef __IMFRateSupport_INTERFACE_DEFINED__
-#define __IMFRateSupport_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFRateSupport, 0x0a9ccdbc, 0xd797, 0x4563, 0x96,0x67, 0x94,0xec,0x5d,0x79,0x29,0x2d);
-MIDL_INTERFACE("0a9ccdbc-d797-4563-9667-94ec5d79292d")
-IMFRateSupport : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate) = 0;
- virtual HRESULT STDMETHODCALLTYPE IsRateSupported(BOOL fThin, float flRate, float *pflNearestSupportedRate) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFRateSupport, 0x0a9ccdbc, 0xd797, 0x4563, 0x96,0x67, 0x94,0xec,0x5d,0x79,0x29,0x2d)
-#endif
-#endif // __IMFRateSupport_INTERFACE_DEFINED__
-
-#ifndef __IMFTopologyServiceLookup_INTERFACE_DEFINED__
-#define __IMFTopologyServiceLookup_INTERFACE_DEFINED__
-typedef enum _MF_SERVICE_LOOKUP_TYPE
-{
- MF_SERVICE_LOOKUP_UPSTREAM = 0,
- MF_SERVICE_LOOKUP_UPSTREAM_DIRECT = (MF_SERVICE_LOOKUP_UPSTREAM + 1),
- MF_SERVICE_LOOKUP_DOWNSTREAM = (MF_SERVICE_LOOKUP_UPSTREAM_DIRECT + 1),
- MF_SERVICE_LOOKUP_DOWNSTREAM_DIRECT = (MF_SERVICE_LOOKUP_DOWNSTREAM + 1),
- MF_SERVICE_LOOKUP_ALL = (MF_SERVICE_LOOKUP_DOWNSTREAM_DIRECT + 1),
- MF_SERVICE_LOOKUP_GLOBAL = (MF_SERVICE_LOOKUP_ALL + 1)
-} MF_SERVICE_LOOKUP_TYPE;
-
-DEFINE_GUID(IID_IMFTopologyServiceLookup, 0xfa993889, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7);
-MIDL_INTERFACE("fa993889-4383-415a-a930-dd472a8cf6f7")
-IMFTopologyServiceLookup : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE LookupService(MF_SERVICE_LOOKUP_TYPE Type,
- DWORD dwIndex,
- REFGUID guidService,
- REFIID riid,
- LPVOID *ppvObjects,
- DWORD *pnObjects) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFTopologyServiceLookup, 0xfa993889, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7)
-#endif
-#endif // __IMFTopologyServiceLookup_INTERFACE_DEFINED__
-
-#ifndef __IMFTopologyServiceLookupClient_INTERFACE_DEFINED__
-#define __IMFTopologyServiceLookupClient_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFTopologyServiceLookupClient, 0xfa99388a, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7);
-MIDL_INTERFACE("fa99388a-4383-415a-a930-dd472a8cf6f7")
-IMFTopologyServiceLookupClient : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE InitServicePointers(IMFTopologyServiceLookup *pLookup) = 0;
- virtual HRESULT STDMETHODCALLTYPE ReleaseServicePointers(void) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFTopologyServiceLookupClient, 0xfa99388a, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7)
-#endif
-#endif // __IMFTopologyServiceLookupClient_INTERFACE_DEFINED__
-
-#ifndef __IMediaEventSink_INTERFACE_DEFINED__
-#define __IMediaEventSink_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMediaEventSink, 0x56a868a2, 0x0ad4, 0x11ce, 0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70);
-MIDL_INTERFACE("56a868a2-0ad4-11ce-b03a-0020af0ba770")
-IMediaEventSink : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE Notify(long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMediaEventSink, 0x56a868a2, 0x0ad4, 0x11ce, 0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70)
-#endif
-#endif // __IMediaEventSink_INTERFACE_DEFINED__
-
-#ifndef __IMFVideoRenderer_INTERFACE_DEFINED__
-#define __IMFVideoRenderer_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFVideoRenderer, 0xDFDFD197, 0xA9CA, 0x43d8, 0xB3,0x41, 0x6A,0xF3,0x50,0x37,0x92,0xCD);
-MIDL_INTERFACE("DFDFD197-A9CA-43d8-B341-6AF3503792CD")
-IMFVideoRenderer : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE InitializeRenderer(IMFTransform *pVideoMixer,
- IMFVideoPresenter *pVideoPresenter) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFVideoRenderer, 0xDFDFD197, 0xA9CA, 0x43d8, 0xB3,0x41, 0x6A,0xF3,0x50,0x37,0x92,0xCD)
-#endif
-#endif // __IMFVideoRenderer_INTERFACE_DEFINED__
-
-#ifndef __IMFTrackedSample_INTERFACE_DEFINED__
-#define __IMFTrackedSample_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFTrackedSample, 0x245BF8E9, 0x0755, 0x40f7, 0x88,0xA5, 0xAE,0x0F,0x18,0xD5,0x5E,0x17);
-MIDL_INTERFACE("245BF8E9-0755-40f7-88A5-AE0F18D55E17")
-IMFTrackedSample : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE SetAllocator(IMFAsyncCallback *pSampleAllocator, IUnknown *pUnkState) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFTrackedSample, 0x245BF8E9, 0x0755, 0x40f7, 0x88,0xA5, 0xAE,0x0F,0x18,0xD5,0x5E,0x17)
-#endif
-#endif // __IMFTrackedSample_INTERFACE_DEFINED__
-
-#ifndef __IMFDesiredSample_INTERFACE_DEFINED__
-#define __IMFDesiredSample_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IMFDesiredSample, 0x56C294D0, 0x753E, 0x4260, 0x8D,0x61, 0xA3,0xD8,0x82,0x0B,0x1D,0x54);
-MIDL_INTERFACE("56C294D0-753E-4260-8D61-A3D8820B1D54")
-IMFDesiredSample : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetDesiredSampleTimeAndDuration(LONGLONG *phnsSampleTime,
- LONGLONG *phnsSampleDuration) = 0;
- virtual void STDMETHODCALLTYPE SetDesiredSampleTimeAndDuration(LONGLONG hnsSampleTime,
- LONGLONG hnsSampleDuration) = 0;
- virtual void STDMETHODCALLTYPE Clear( void) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IMFDesiredSample, 0x56C294D0, 0x753E, 0x4260, 0x8D,0x61, 0xA3,0xD8,0x82,0x0B,0x1D,0x54)
-#endif
-#endif
-
-#endif // EVRDEFS_H
-
diff --git a/src/multimedia/platform/windows/evr/evrhelpers.cpp b/src/multimedia/platform/windows/evr/evrhelpers.cpp
deleted file mode 100644
index 3f2059585..000000000
--- a/src/multimedia/platform/windows/evr/evrhelpers.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "evrhelpers_p.h"
-
-#ifndef D3DFMT_YV12
-#define D3DFMT_YV12 (D3DFORMAT)MAKEFOURCC ('Y', 'V', '1', '2')
-#endif
-#ifndef D3DFMT_NV12
-#define D3DFMT_NV12 (D3DFORMAT)MAKEFOURCC ('N', 'V', '1', '2')
-#endif
-
-QT_BEGIN_NAMESPACE
-
-HRESULT qt_evr_getFourCC(IMFMediaType *type, DWORD *fourCC)
-{
- if (!fourCC)
- return E_POINTER;
-
- HRESULT hr = S_OK;
- GUID guidSubType = GUID_NULL;
-
- if (SUCCEEDED(hr))
- hr = type->GetGUID(MF_MT_SUBTYPE, &guidSubType);
-
- if (SUCCEEDED(hr))
- *fourCC = guidSubType.Data1;
-
- return hr;
-}
-
-bool qt_evr_areMediaTypesEqual(IMFMediaType *type1, IMFMediaType *type2)
-{
- if (!type1 && !type2)
- return true;
- if (!type1 || !type2)
- return false;
-
- DWORD dwFlags = 0;
- HRESULT hr = type1->IsEqual(type2, &dwFlags);
-
- return (hr == S_OK);
-}
-
-HRESULT qt_evr_validateVideoArea(const MFVideoArea& area, UINT32 width, UINT32 height)
-{
- float fOffsetX = qt_evr_MFOffsetToFloat(area.OffsetX);
- float fOffsetY = qt_evr_MFOffsetToFloat(area.OffsetY);
-
- if ( ((LONG)fOffsetX + area.Area.cx > (LONG)width) ||
- ((LONG)fOffsetY + area.Area.cy > (LONG)height) ) {
- return MF_E_INVALIDMEDIATYPE;
- }
- return S_OK;
-}
-
-bool qt_evr_isSampleTimePassed(IMFClock *clock, IMFSample *sample)
-{
- if (!sample || !clock)
- return false;
-
- HRESULT hr = S_OK;
- MFTIME hnsTimeNow = 0;
- MFTIME hnsSystemTime = 0;
- MFTIME hnsSampleStart = 0;
- MFTIME hnsSampleDuration = 0;
-
- hr = clock->GetCorrelatedTime(0, &hnsTimeNow, &hnsSystemTime);
-
- if (SUCCEEDED(hr))
- hr = sample->GetSampleTime(&hnsSampleStart);
-
- if (SUCCEEDED(hr))
- hr = sample->GetSampleDuration(&hnsSampleDuration);
-
- if (SUCCEEDED(hr)) {
- if (hnsSampleStart + hnsSampleDuration < hnsTimeNow)
- return true;
- }
-
- return false;
-}
-
-QVideoFrameFormat::PixelFormat qt_evr_pixelFormatFromD3DFormat(DWORD format)
-{
- switch (format) {
- case D3DFMT_A8R8G8B8:
- return QVideoFrameFormat::Format_BGRA8888;
- case D3DFMT_X8R8G8B8:
- return QVideoFrameFormat::Format_BGRX8888;
- case D3DFMT_A8:
- return QVideoFrameFormat::Format_Y8;
- case D3DFMT_A8B8G8R8:
- return QVideoFrameFormat::Format_RGBA8888;
- case D3DFMT_X8B8G8R8:
- return QVideoFrameFormat::Format_RGBX8888;
- case D3DFMT_UYVY:
- return QVideoFrameFormat::Format_UYVY;
- case D3DFMT_YUY2:
- return QVideoFrameFormat::Format_YUYV;
- case D3DFMT_NV12:
- return QVideoFrameFormat::Format_NV12;
- case D3DFMT_YV12:
- return QVideoFrameFormat::Format_YV12;
- case D3DFMT_UNKNOWN:
- default:
- return QVideoFrameFormat::Format_Invalid;
- }
-}
-
-D3DFORMAT qt_evr_D3DFormatFromPixelFormat(QVideoFrameFormat::PixelFormat format)
-{
- switch (format) {
- case QVideoFrameFormat::Format_BGRA8888:
- return D3DFMT_A8R8G8B8;
- case QVideoFrameFormat::Format_BGRX8888:
- return D3DFMT_X8R8G8B8;
- case QVideoFrameFormat::Format_Y8:
- return D3DFMT_A8;
- case QVideoFrameFormat::Format_RGBA8888:
- return D3DFMT_A8B8G8R8;
- case QVideoFrameFormat::Format_RGBX8888:
- return D3DFMT_X8B8G8R8;
- case QVideoFrameFormat::Format_UYVY:
- return D3DFMT_UYVY;
- case QVideoFrameFormat::Format_YUYV:
- return D3DFMT_YUY2;
- case QVideoFrameFormat::Format_NV12:
- return D3DFMT_NV12;
- case QVideoFrameFormat::Format_YV12:
- return D3DFMT_YV12;
- case QVideoFrameFormat::Format_Invalid:
- default:
- return D3DFMT_UNKNOWN;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/evr/evrhelpers_p.h b/src/multimedia/platform/windows/evr/evrhelpers_p.h
deleted file mode 100644
index 340658571..000000000
--- a/src/multimedia/platform/windows/evr/evrhelpers_p.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef EVRHELPERS_H
-#define EVRHELPERS_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 "evrdefs_p.h"
-#include <qvideoframe.h>
-
-QT_BEGIN_NAMESPACE
-
-template<class T>
-static inline void qt_evr_safe_release(T **unk)
-{
- if (*unk) {
- (*unk)->Release();
- *unk = NULL;
- }
-}
-
-HRESULT qt_evr_getFourCC(IMFMediaType *type, DWORD *fourCC);
-
-bool qt_evr_areMediaTypesEqual(IMFMediaType *type1, IMFMediaType *type2);
-
-HRESULT qt_evr_validateVideoArea(const MFVideoArea& area, UINT32 width, UINT32 height);
-
-bool qt_evr_isSampleTimePassed(IMFClock *clock, IMFSample *sample);
-
-inline float qt_evr_MFOffsetToFloat(const MFOffset& offset)
-{
- return offset.value + (float(offset.fract) / 65536);
-}
-
-inline MFOffset qt_evr_makeMFOffset(float v)
-{
- MFOffset offset;
- offset.value = short(v);
- offset.fract = WORD(65536 * (v-offset.value));
- return offset;
-}
-
-inline MFVideoArea qt_evr_makeMFArea(float x, float y, DWORD width, DWORD height)
-{
- MFVideoArea area;
- area.OffsetX = qt_evr_makeMFOffset(x);
- area.OffsetY = qt_evr_makeMFOffset(y);
- area.Area.cx = width;
- area.Area.cy = height;
- return area;
-}
-
-inline HRESULT qt_evr_getFrameRate(IMFMediaType *pType, MFRatio *pRatio)
-{
- return MFGetAttributeRatio(pType, MF_MT_FRAME_RATE,
- reinterpret_cast<UINT32*>(&pRatio->Numerator),
- reinterpret_cast<UINT32*>(&pRatio->Denominator));
-}
-
-QVideoFrameFormat::PixelFormat qt_evr_pixelFormatFromD3DFormat(DWORD format);
-D3DFORMAT qt_evr_D3DFormatFromPixelFormat(QVideoFrameFormat::PixelFormat format);
-
-QT_END_NAMESPACE
-
-#endif // EVRHELPERS_H
-
diff --git a/src/multimedia/platform/windows/evr/evrvideowindowcontrol.cpp b/src/multimedia/platform/windows/evr/evrvideowindowcontrol.cpp
deleted file mode 100644
index 18f883289..000000000
--- a/src/multimedia/platform/windows/evr/evrvideowindowcontrol.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "evrvideowindowcontrol_p.h"
-
-EvrVideoWindowControl::EvrVideoWindowControl(QVideoSink *parent)
- : QPlatformVideoSink(parent)
- , m_windowId(0)
- , m_windowColor(RGB(0, 0, 0))
- , m_dirtyValues(0)
- , m_aspectRatioMode(Qt::KeepAspectRatio)
- , m_brightness(0)
- , m_contrast(0)
- , m_hue(0)
- , m_saturation(0)
- , m_fullScreen(false)
- , m_displayControl(0)
- , m_processor(0)
-{
-}
-
-EvrVideoWindowControl::~EvrVideoWindowControl()
-{
- clear();
-}
-
-bool EvrVideoWindowControl::setEvr(IUnknown *evr)
-{
- clear();
-
- if (!evr)
- return true;
-
- IMFGetService *service = NULL;
-
- if (SUCCEEDED(evr->QueryInterface(IID_PPV_ARGS(&service)))
- && SUCCEEDED(service->GetService(mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_displayControl)))) {
-
- service->GetService(mr_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_processor));
-
- setWinId(m_windowId);
- setDisplayRect(m_displayRect);
- setAspectRatioMode(m_aspectRatioMode);
- m_dirtyValues = DXVA2_ProcAmp_Brightness | DXVA2_ProcAmp_Contrast | DXVA2_ProcAmp_Hue | DXVA2_ProcAmp_Saturation;
- applyImageControls();
- }
-
- if (service)
- service->Release();
-
- return m_displayControl != NULL;
-}
-
-void EvrVideoWindowControl::clear()
-{
- if (m_displayControl)
- m_displayControl->Release();
- m_displayControl = NULL;
-
- if (m_processor)
- m_processor->Release();
- m_processor = NULL;
-}
-
-void EvrVideoWindowControl::setWinId(WId id)
-{
- m_windowId = id;
-
- if (m_displayControl)
- m_displayControl->SetVideoWindow(HWND(m_windowId));
-}
-
-void EvrVideoWindowControl::setDisplayRect(const QRect &rect)
-{
- m_displayRect = rect;
-
- if (m_displayControl) {
- RECT displayRect = { rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1 };
- QSize sourceSize = nativeSize();
-
- RECT sourceRect = { 0, 0, sourceSize.width(), sourceSize.height() };
-
- if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
- QSize clippedSize = rect.size();
- clippedSize.scale(sourceRect.right, sourceRect.bottom, Qt::KeepAspectRatio);
-
- sourceRect.left = (sourceRect.right - clippedSize.width()) / 2;
- sourceRect.top = (sourceRect.bottom - clippedSize.height()) / 2;
- sourceRect.right = sourceRect.left + clippedSize.width();
- sourceRect.bottom = sourceRect.top + clippedSize.height();
- }
-
- if (sourceSize.width() > 0 && sourceSize.height() > 0) {
- MFVideoNormalizedRect sourceNormRect;
- sourceNormRect.left = float(sourceRect.left) / float(sourceRect.right);
- sourceNormRect.top = float(sourceRect.top) / float(sourceRect.bottom);
- sourceNormRect.right = float(sourceRect.right) / float(sourceRect.right);
- sourceNormRect.bottom = float(sourceRect.bottom) / float(sourceRect.bottom);
- m_displayControl->SetVideoPosition(&sourceNormRect, &displayRect);
- } else {
- m_displayControl->SetVideoPosition(NULL, &displayRect);
- }
- }
-}
-
-void EvrVideoWindowControl::setFullScreen(bool fullScreen)
-{
- if (m_fullScreen == fullScreen)
- return;
-}
-
-QSize EvrVideoWindowControl::nativeSize() const
-{
- QSize size;
- if (m_displayControl) {
- SIZE sourceSize;
- if (SUCCEEDED(m_displayControl->GetNativeVideoSize(&sourceSize, 0)))
- size = QSize(sourceSize.cx, sourceSize.cy);
- }
- return size;
-}
-
-void EvrVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
-{
- m_aspectRatioMode = mode;
-
- if (m_displayControl) {
- switch (mode) {
- case Qt::IgnoreAspectRatio:
- //comment from MSDN: Do not maintain the aspect ratio of the video. Stretch the video to fit the output rectangle.
- m_displayControl->SetAspectRatioMode(MFVideoARMode_None);
- break;
- case Qt::KeepAspectRatio:
- //comment from MSDN: Preserve the aspect ratio of the video by letterboxing or within the output rectangle.
- m_displayControl->SetAspectRatioMode(MFVideoARMode_PreservePicture);
- break;
- case Qt::KeepAspectRatioByExpanding:
- //for this mode, more adjustment will be done in setDisplayRect
- m_displayControl->SetAspectRatioMode(MFVideoARMode_PreservePicture);
- break;
- default:
- break;
- }
- setDisplayRect(m_displayRect);
- }
-}
-
-void EvrVideoWindowControl::setBrightness(float brightness)
-{
- if (m_brightness == brightness)
- return;
-
- m_brightness = brightness;
-
- m_dirtyValues |= DXVA2_ProcAmp_Brightness;
-
- applyImageControls();
-}
-
-void EvrVideoWindowControl::setContrast(float contrast)
-{
- if (m_contrast == contrast)
- return;
-
- m_contrast = contrast;
-
- m_dirtyValues |= DXVA2_ProcAmp_Contrast;
-
- applyImageControls();
-}
-
-void EvrVideoWindowControl::setHue(float hue)
-{
- if (m_hue == hue)
- return;
-
- m_hue = hue;
-
- m_dirtyValues |= DXVA2_ProcAmp_Hue;
-
- applyImageControls();
-}
-
-void EvrVideoWindowControl::setSaturation(float saturation)
-{
- if (m_saturation == saturation)
- return;
-
- m_saturation = saturation;
-
- m_dirtyValues |= DXVA2_ProcAmp_Saturation;
-
- applyImageControls();
-}
-
-void EvrVideoWindowControl::applyImageControls()
-{
- if (m_processor) {
- DXVA2_ProcAmpValues values;
- if (m_dirtyValues & DXVA2_ProcAmp_Brightness) {
- values.Brightness = scaleProcAmpValue(DXVA2_ProcAmp_Brightness, m_brightness);
- }
- if (m_dirtyValues & DXVA2_ProcAmp_Contrast) {
- values.Contrast = scaleProcAmpValue(DXVA2_ProcAmp_Contrast, m_contrast);
- }
- if (m_dirtyValues & DXVA2_ProcAmp_Hue) {
- values.Hue = scaleProcAmpValue(DXVA2_ProcAmp_Hue, m_hue);
- }
- if (m_dirtyValues & DXVA2_ProcAmp_Saturation) {
- values.Saturation = scaleProcAmpValue(DXVA2_ProcAmp_Saturation, m_saturation);
- }
-
- if (SUCCEEDED(m_processor->SetProcAmpValues(m_dirtyValues, &values))) {
- m_dirtyValues = 0;
- }
- }
-}
-
-DXVA2_Fixed32 EvrVideoWindowControl::scaleProcAmpValue(DWORD prop, float value) const
-{
- float scaledValue = 0.0;
-
- DXVA2_ValueRange range;
- if (SUCCEEDED(m_processor->GetProcAmpRange(prop, &range))) {
- scaledValue = DXVA2FixedToFloat(range.DefaultValue);
- if (value > 0)
- scaledValue += float(value) * (DXVA2FixedToFloat(range.MaxValue) - DXVA2FixedToFloat(range.DefaultValue));
- else if (value < 0)
- scaledValue -= float(value) * (DXVA2FixedToFloat(range.MinValue) - DXVA2FixedToFloat(range.DefaultValue));
- }
-
- return DXVA2FloatToFixed(scaledValue);
-}
diff --git a/src/multimedia/platform/windows/evr/evrvideowindowcontrol_p.h b/src/multimedia/platform/windows/evr/evrvideowindowcontrol_p.h
deleted file mode 100644
index b9fbc271c..000000000
--- a/src/multimedia/platform/windows/evr/evrvideowindowcontrol_p.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef EVRVIDEOWINDOWCONTROL_H
-#define EVRVIDEOWINDOWCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "private/qplatformvideosink_p.h"
-
-#include "evrdefs_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class EvrVideoWindowControl : public QPlatformVideoSink
-{
- Q_OBJECT
-public:
- EvrVideoWindowControl(QVideoSink *parent = 0);
- ~EvrVideoWindowControl() override;
-
- bool setEvr(IUnknown *evr);
-
- void setWinId(WId id) override;
-
- void setDisplayRect(const QRect &rect) override;
-
- void setFullScreen(bool fullScreen) override;
-
- QSize nativeSize() const override;
-
- void setAspectRatioMode(Qt::AspectRatioMode mode) override;
-
- void setBrightness(float brightness) override;
- void setContrast(float contrast) override;
- void setHue(float hue) override;
- void setSaturation(float saturation) override;
-
- void applyImageControls();
-
-private:
- void clear();
- DXVA2_Fixed32 scaleProcAmpValue(DWORD prop, float value) const;
-
- WId m_windowId;
- COLORREF m_windowColor;
- DWORD m_dirtyValues;
- Qt::AspectRatioMode m_aspectRatioMode;
- QRect m_displayRect;
- float m_brightness;
- float m_contrast;
- float m_hue;
- float m_saturation;
- bool m_fullScreen;
-
- IMFVideoDisplayControl *m_displayControl;
- IMFVideoProcessor *m_processor;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowscamera.cpp b/src/multimedia/platform/windows/mediacapture/qwindowscamera.cpp
deleted file mode 100644
index 53e8650f7..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowscamera.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowscamera_p.h"
-
-#include "qwindowsmediadevicesession_p.h"
-#include "qwindowsmediacapture_p.h"
-#include <qcameradevice.h>
-
-QT_BEGIN_NAMESPACE
-
-QWindowsCamera::QWindowsCamera(QCamera *camera)
- : QPlatformCamera(camera)
-{
-}
-
-QWindowsCamera::~QWindowsCamera() = default;
-
-bool QWindowsCamera::isActive() const
-{
- return m_active;
-}
-
-void QWindowsCamera::setActive(bool active)
-{
- if (m_active == active)
- return;
- if (m_cameraDevice.isNull() && active)
- return;
- m_active = active;
- if (m_mediaDeviceSession)
- m_mediaDeviceSession->setActive(active);
-
- emit activeChanged(m_active);
-}
-
-void QWindowsCamera::setCamera(const QCameraDevice &camera)
-{
- if (m_cameraDevice == camera)
- return;
- m_cameraDevice = camera;
- if (m_mediaDeviceSession)
- m_mediaDeviceSession->setActiveCamera(camera);
-}
-
-void QWindowsCamera::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QWindowsMediaCaptureService *captureService = static_cast<QWindowsMediaCaptureService *>(session);
- if (m_captureService == captureService)
- return;
-
- if (m_mediaDeviceSession) {
- m_mediaDeviceSession->disconnect(this);
- m_mediaDeviceSession->setActive(false);
- m_mediaDeviceSession->setCameraFormat({});
- m_mediaDeviceSession->setActiveCamera({});
- }
-
- m_captureService = captureService;
- if (!m_captureService) {
- m_mediaDeviceSession = nullptr;
- return;
- }
-
- m_mediaDeviceSession = m_captureService->session();
- Q_ASSERT(m_mediaDeviceSession);
-
- m_mediaDeviceSession->setActive(false);
- m_mediaDeviceSession->setActiveCamera(m_cameraDevice);
- m_mediaDeviceSession->setCameraFormat(m_cameraFormat);
- m_mediaDeviceSession->setActive(m_active);
-
- connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::activeChanged,
- this, &QWindowsCamera::onActiveChanged);
-}
-
-bool QWindowsCamera::setCameraFormat(const QCameraFormat &format)
-{
- if (!format.isNull() && !m_cameraDevice.videoFormats().contains(format))
- return false;
-
- m_cameraFormat = format.isNull() ? findBestCameraFormat(m_cameraDevice) : format;
-
- if (m_mediaDeviceSession)
- m_mediaDeviceSession->setCameraFormat(m_cameraFormat);
- return true;
-}
-
-void QWindowsCamera::onActiveChanged(bool active)
-{
- if (m_active == active)
- return;
- if (m_cameraDevice.isNull() && active)
- return;
- m_active = active;
- emit activeChanged(m_active);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowscamera_p.h b/src/multimedia/platform/windows/mediacapture/qwindowscamera_p.h
deleted file mode 100644
index 379a2cba3..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowscamera_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSCAMERA_H
-#define QWINDOWSCAMERA_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformcamera_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsMediaCaptureService;
-class QWindowsMediaDeviceSession;
-
-class QWindowsCamera : public QPlatformCamera
-{
- Q_OBJECT
-public:
- explicit QWindowsCamera(QCamera *camera);
- virtual ~QWindowsCamera();
-
- bool isActive() const override;
-
- void setCamera(const QCameraDevice &camera) override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *) override;
-
- bool setCameraFormat(const QCameraFormat &format) override;
-
- void setActive(bool active) override;
-
-private Q_SLOTS:
- void onActiveChanged(bool active);
-
-private:
- QWindowsMediaCaptureService *m_captureService = nullptr;
- QWindowsMediaDeviceSession *m_mediaDeviceSession = nullptr;
- QCameraDevice m_cameraDevice;
- QCameraFormat m_cameraFormat;
- bool m_active = false;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSCAMERA_H
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsimagecapture.cpp b/src/multimedia/platform/windows/mediacapture/qwindowsimagecapture.cpp
deleted file mode 100644
index d61cd6cde..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsimagecapture.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsimagecapture_p.h"
-
-#include "qwindowsmediadevicesession_p.h"
-#include "qwindowsmediacapture_p.h"
-#include "qmediastoragelocation_p.h"
-
-#include <QtConcurrent/qtconcurrentrun.h>
-#include <QtGui/qimagewriter.h>
-
-QT_BEGIN_NAMESPACE
-
-QWindowsImageCapture::QWindowsImageCapture(QImageCapture *parent)
- : QPlatformImageCapture(parent)
-{
-}
-
-QWindowsImageCapture::~QWindowsImageCapture() = default;
-
-bool QWindowsImageCapture::isReadyForCapture() const
-{
- if (!m_mediaDeviceSession)
- return false;
- return !m_capturing && m_mediaDeviceSession->isActive() && !m_mediaDeviceSession->activeCamera().isNull();
-}
-
-int QWindowsImageCapture::capture(const QString &fileName)
-{
- auto ext = writerFormat(m_settings.format());
- auto path = QMediaStorageLocation::generateFileName(fileName, QStandardPaths::PicturesLocation, ext);
- return doCapture(path);
-}
-
-int QWindowsImageCapture::captureToBuffer()
-{
- return doCapture(QString());
-}
-
-int QWindowsImageCapture::doCapture(const QString &fileName)
-{
- if (!isReadyForCapture())
- return -1;
- m_fileName = fileName;
- m_capturing = true;
- return m_captureId;
-}
-
-QImageEncoderSettings QWindowsImageCapture::imageSettings() const
-{
- return m_settings;
-}
-
-void QWindowsImageCapture::setImageSettings(const QImageEncoderSettings &settings)
-{
- m_settings = settings;
-}
-
-void QWindowsImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QWindowsMediaCaptureService *captureService = static_cast<QWindowsMediaCaptureService *>(session);
- if (m_captureService == captureService)
- return;
-
- if (m_mediaDeviceSession)
- disconnect(m_mediaDeviceSession, nullptr, this, nullptr);
-
- m_captureService = captureService;
- if (!m_captureService) {
- m_mediaDeviceSession = nullptr;
- return;
- }
-
- m_mediaDeviceSession = m_captureService->session();
- Q_ASSERT(m_mediaDeviceSession);
-
- connect(m_mediaDeviceSession, SIGNAL(readyForCaptureChanged(bool)),
- this, SIGNAL(readyForCaptureChanged(bool)));
-
- connect(m_mediaDeviceSession, SIGNAL(videoFrameChanged(QVideoFrame)),
- this, SLOT(handleVideoFrameChanged(QVideoFrame)));
-}
-
-void QWindowsImageCapture::handleVideoFrameChanged(const QVideoFrame &frame)
-{
- if (m_capturing) {
-
- QImage image = frame.toImage();
-
- emit imageExposed(m_captureId);
- emit imageAvailable(m_captureId, frame);
- emit imageCaptured(m_captureId, image);
-
- QMediaMetaData metaData = this->metaData();
- metaData.insert(QMediaMetaData::Date, QDateTime::currentDateTime());
- metaData.insert(QMediaMetaData::Resolution, frame.size());
-
- emit imageMetadataAvailable(m_captureId, metaData);
-
- if (!m_fileName.isEmpty()) {
-
- (void)QtConcurrent::run(&QWindowsImageCapture::saveImage, this,
- m_captureId, m_fileName, image, metaData, m_settings);
- }
-
- ++m_captureId;
- m_capturing = false;
- }
-}
-
-void QWindowsImageCapture::saveImage(int captureId, const QString &fileName,
- const QImage &image, const QMediaMetaData &metaData,
- const QImageEncoderSettings &settings)
-{
- QImageWriter imageWriter;
- imageWriter.setFileName(fileName);
-
- QString format = writerFormat(settings.format());
- imageWriter.setFormat(format.toUtf8());
-
- int quality = writerQuality(format, settings.quality());
- if (quality > -1)
- imageWriter.setQuality(quality);
-
- for (auto key : metaData.keys())
- imageWriter.setText(QMediaMetaData::metaDataKeyToString(key),
- metaData.stringValue(key));
-
- imageWriter.write(image);
-
- QMetaObject::invokeMethod(this, "imageSaved", Qt::QueuedConnection,
- Q_ARG(int, captureId), Q_ARG(QString, fileName));
-}
-
-QString QWindowsImageCapture::writerFormat(QImageCapture::FileFormat reqFormat)
-{
- QString format;
-
- switch (reqFormat) {
- case QImageCapture::FileFormat::JPEG:
- format = QLatin1String("jpg");
- break;
- case QImageCapture::FileFormat::PNG:
- format = QLatin1String("png");
- break;
- case QImageCapture::FileFormat::WebP:
- format = QLatin1String("webp");
- break;
- case QImageCapture::FileFormat::Tiff:
- format = QLatin1String("tiff");
- break;
- default:
- format = QLatin1String("jpg");
- }
-
- auto supported = QImageWriter::supportedImageFormats();
- for (const auto &f : supported)
- if (format.compare(QString::fromUtf8(f), Qt::CaseInsensitive) == 0)
- return format;
-
- return QLatin1String("jpg");
-}
-
-int QWindowsImageCapture::writerQuality(const QString &writerFormat,
- QImageCapture::Quality quality)
-{
- if (writerFormat.compare(QLatin1String("jpg"), Qt::CaseInsensitive) == 0 ||
- writerFormat.compare(QLatin1String("jpeg"), Qt::CaseInsensitive) == 0) {
-
- switch (quality) {
- case QImageCapture::Quality::VeryLowQuality:
- return 10;
- case QImageCapture::Quality::LowQuality:
- return 30;
- case QImageCapture::Quality::NormalQuality:
- return 75;
- case QImageCapture::Quality::HighQuality:
- return 90;
- case QImageCapture::Quality::VeryHighQuality:
- return 98;
- default:
- return 75;
- }
- }
- return -1;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsimagecapture_p.h b/src/multimedia/platform/windows/mediacapture/qwindowsimagecapture_p.h
deleted file mode 100644
index 6c3bc8107..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsimagecapture_p.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWindowsImageCapture_H
-#define QWindowsImageCapture_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformimagecapture_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsMediaDeviceSession;
-class QWindowsMediaCaptureService;
-
-class QWindowsImageCapture : public QPlatformImageCapture
-{
- Q_OBJECT
-public:
- explicit QWindowsImageCapture(QImageCapture *parent);
- virtual ~QWindowsImageCapture();
-
- bool isReadyForCapture() const override;
-
- int capture(const QString &fileName) override;
- int captureToBuffer() override;
-
- QImageEncoderSettings imageSettings() const override;
- void setImageSettings(const QImageEncoderSettings &settings) override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
-private Q_SLOTS:
- void handleVideoFrameChanged(const QVideoFrame &frame);
-
-private:
- int doCapture(const QString &fileName);
- void saveImage(int captureId, const QString &fileName,
- const QImage &image, const QMediaMetaData &metaData,
- const QImageEncoderSettings &settings);
- QString writerFormat(QImageCapture::FileFormat reqFormat);
- int writerQuality(const QString &writerFormat,
- QImageCapture::Quality quality);
-
- QWindowsMediaCaptureService *m_captureService = nullptr;
- QWindowsMediaDeviceSession *m_mediaDeviceSession = nullptr;
- QImageEncoderSettings m_settings;
- int m_captureId = 0;
- bool m_capturing = false;
- QString m_fileName;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWindowsImageCapture_H
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediacapture.cpp b/src/multimedia/platform/windows/mediacapture/qwindowsmediacapture.cpp
deleted file mode 100644
index a298039ee..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediacapture.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsmediacapture_p.h"
-
-#include "qwindowsmediaencoder_p.h"
-#include "qwindowscamera_p.h"
-#include "qwindowsmediadevicesession_p.h"
-#include "qwindowsimagecapture_p.h"
-#include "qmediadevices.h"
-#include "qaudiodevice.h"
-#include "qplatformaudioinput_p.h"
-#include "qplatformaudiooutput_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QWindowsMediaCaptureService::QWindowsMediaCaptureService()
-{
- m_mediaDeviceSession = new QWindowsMediaDeviceSession(this);
-}
-
-QWindowsMediaCaptureService::~QWindowsMediaCaptureService()
-{
- delete m_mediaDeviceSession;
-}
-
-QPlatformCamera *QWindowsMediaCaptureService::camera()
-{
- return m_camera;
-}
-
-void QWindowsMediaCaptureService::setCamera(QPlatformCamera *camera)
-{
- QWindowsCamera *control = static_cast<QWindowsCamera*>(camera);
- if (m_camera == control)
- return;
-
- if (m_camera)
- m_camera->setCaptureSession(nullptr);
-
- m_camera = control;
- if (m_camera)
- m_camera->setCaptureSession(this);
- emit cameraChanged();
-}
-
-QPlatformImageCapture *QWindowsMediaCaptureService::imageCapture()
-{
- return m_imageCapture;
-}
-
-void QWindowsMediaCaptureService::setImageCapture(QPlatformImageCapture *imageCapture)
-{
- QWindowsImageCapture *control = static_cast<QWindowsImageCapture *>(imageCapture);
- if (m_imageCapture == control)
- return;
-
- if (m_imageCapture)
- m_imageCapture->setCaptureSession(nullptr);
-
- m_imageCapture = control;
- if (m_imageCapture)
- m_imageCapture->setCaptureSession(this);
- emit imageCaptureChanged();
-}
-
-QPlatformMediaEncoder *QWindowsMediaCaptureService::mediaEncoder()
-{
- return m_encoder;
-}
-
-void QWindowsMediaCaptureService::setMediaEncoder(QPlatformMediaEncoder *encoder)
-{
- QWindowsMediaEncoder *control = static_cast<QWindowsMediaEncoder *>(encoder);
- if (m_encoder == control)
- return;
-
- if (m_encoder)
- m_encoder->setCaptureSession(nullptr);
-
- m_encoder = control;
- if (m_encoder)
- m_encoder->setCaptureSession(this);
- emit encoderChanged();
-}
-
-void QWindowsMediaCaptureService::setAudioInput(QPlatformAudioInput *input)
-{
- m_mediaDeviceSession->setAudioInput(input ? input->q : nullptr);
-}
-
-void QWindowsMediaCaptureService::setAudioOutput(QPlatformAudioOutput *output)
-{
- m_mediaDeviceSession->setAudioOutput(output ? output->q : nullptr);
-}
-
-void QWindowsMediaCaptureService::setVideoPreview(QVideoSink *sink)
-{
- m_mediaDeviceSession->setVideoSink(sink);
-}
-
-QWindowsMediaDeviceSession *QWindowsMediaCaptureService::session() const
-{
- return m_mediaDeviceSession;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediacapture_p.h b/src/multimedia/platform/windows/mediacapture/qwindowsmediacapture_p.h
deleted file mode 100644
index 147fb72ed..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediacapture_p.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QWINDOWSMEDIACAPTURE_H
-#define QWINDOWSMEDIACAPTURE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediacapture_p.h>
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsMediaEncoder;
-class QWindowsCamera;
-class QWindowsMediaDeviceSession;
-class QWindowsImageCapture;
-class QPlatformAudioInput;
-
-class QWindowsMediaCaptureService : public QPlatformMediaCaptureSession
-{
- Q_OBJECT
-
-public:
- QWindowsMediaCaptureService();
- virtual ~QWindowsMediaCaptureService();
-
- QPlatformCamera *camera() override;
- void setCamera(QPlatformCamera *camera) override;
-
- QPlatformImageCapture *imageCapture() override;
- void setImageCapture(QPlatformImageCapture *imageCapture) override;
-
- QPlatformMediaEncoder *mediaEncoder() override;
- void setMediaEncoder(QPlatformMediaEncoder *encoder) override;
-
- void setAudioInput(QPlatformAudioInput *) override;
-
- void setAudioOutput(QPlatformAudioOutput *output) override;
-
- void setVideoPreview(QVideoSink *sink) override;
-
- QWindowsMediaDeviceSession *session() const;
-
-private:
- QWindowsCamera *m_camera = nullptr;
- QWindowsMediaDeviceSession *m_mediaDeviceSession = nullptr;
- QWindowsImageCapture *m_imageCapture = nullptr;
- QWindowsMediaEncoder *m_encoder = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSMEDIAINTERFACE_H
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader.cpp b/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader.cpp
deleted file mode 100644
index 2e338476e..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader.cpp
+++ /dev/null
@@ -1,1054 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsmediadevicereader_p.h"
-
-#include "qwindowsmultimediautils_p.h"
-#include <qvideosink.h>
-#include <qmediadevices.h>
-#include <qaudiodevice.h>
-#include <private/qmemoryvideobuffer_p.h>
-#include <QtCore/qdebug.h>
-
-#include <mmdeviceapi.h>
-
-QT_BEGIN_NAMESPACE
-
-enum { MEDIA_TYPE_INDEX_DEFAULT = 0xffffffff };
-
-QWindowsMediaDeviceReader::QWindowsMediaDeviceReader(QObject *parent)
- : QObject(parent)
-{
- m_durationTimer.setInterval(100);
- connect(&m_durationTimer, SIGNAL(timeout()), this, SLOT(updateDuration()));
-}
-
-QWindowsMediaDeviceReader::~QWindowsMediaDeviceReader()
-{
- stopRecording();
- deactivate();
-}
-
-// Creates a video or audio media source specified by deviceId (symbolic link)
-HRESULT QWindowsMediaDeviceReader::createSource(const QString &deviceId, bool video, IMFMediaSource **source)
-{
- if (!source)
- return E_INVALIDARG;
-
- *source = nullptr;
- IMFAttributes *sourceAttributes = nullptr;
-
- HRESULT hr = MFCreateAttributes(&sourceAttributes, 2);
- if (SUCCEEDED(hr)) {
-
- hr = sourceAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
- video ? MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
- : MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID);
- if (SUCCEEDED(hr)) {
-
- hr = sourceAttributes->SetString(video ? MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK
- : MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID,
- reinterpret_cast<LPCWSTR>(deviceId.utf16()));
- if (SUCCEEDED(hr)) {
-
- hr = MFCreateDeviceSource(sourceAttributes, source);
- }
- }
- sourceAttributes->Release();
- }
-
- return hr;
-}
-
-// Creates a source/reader aggregating two other sources (video/audio).
-// If one of the sources is null the result will be video-only or audio-only.
-HRESULT QWindowsMediaDeviceReader::createAggregateReader(IMFMediaSource *firstSource,
- IMFMediaSource *secondSource,
- IMFMediaSource **aggregateSource,
- IMFSourceReader **sourceReader)
-{
- if ((!firstSource && !secondSource) || !aggregateSource || !sourceReader)
- return E_INVALIDARG;
-
- *aggregateSource = nullptr;
- *sourceReader = nullptr;
-
- IMFCollection *sourceCollection = nullptr;
-
- HRESULT hr = MFCreateCollection(&sourceCollection);
- if (SUCCEEDED(hr)) {
-
- if (firstSource)
- sourceCollection->AddElement(firstSource);
-
- if (secondSource)
- sourceCollection->AddElement(secondSource);
-
- hr = MFCreateAggregateSource(sourceCollection, aggregateSource);
- if (SUCCEEDED(hr)) {
-
- IMFAttributes *readerAttributes = nullptr;
-
- hr = MFCreateAttributes(&readerAttributes, 1);
- if (SUCCEEDED(hr)) {
-
- // Set callback so OnReadSample() is called for each new video frame or audio sample.
- hr = readerAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK,
- static_cast<IMFSourceReaderCallback*>(this));
- if (SUCCEEDED(hr)) {
-
- hr = MFCreateSourceReaderFromMediaSource(*aggregateSource, readerAttributes, sourceReader);
- }
- readerAttributes->Release();
- }
- }
- sourceCollection->Release();
- }
- return hr;
-}
-
-// Selects the requested resolution/frame rate (if specified),
-// or chooses a high quality configuration otherwise.
-DWORD QWindowsMediaDeviceReader::findMediaTypeIndex(const QCameraFormat &reqFormat)
-{
- DWORD mediaIndex = MEDIA_TYPE_INDEX_DEFAULT;
-
- if (m_sourceReader && m_videoSource) {
-
- DWORD index = 0;
- IMFMediaType *mediaType = nullptr;
-
- UINT32 currArea = 0;
- float currFrameRate = 0.0f;
-
- while (SUCCEEDED(m_sourceReader->GetNativeMediaType(DWORD(MF_SOURCE_READER_FIRST_VIDEO_STREAM),
- index, &mediaType))) {
-
- GUID subtype = GUID_NULL;
- if (SUCCEEDED(mediaType->GetGUID(MF_MT_SUBTYPE, &subtype))) {
-
- auto pixelFormat = QWindowsMultimediaUtils::pixelFormatFromMediaSubtype(subtype);
- if (pixelFormat != QVideoFrameFormat::Format_Invalid) {
-
- UINT32 width, height;
- if (SUCCEEDED(MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height))) {
-
- UINT32 num, den;
- if (SUCCEEDED(MFGetAttributeRatio(mediaType, MF_MT_FRAME_RATE, &num, &den))) {
-
- UINT32 area = width * height;
- float frameRate = float(num) / den;
-
- if (!reqFormat.isNull()
- && reqFormat.resolution().width() == width
- && reqFormat.resolution().height() == height
- && qFuzzyCompare(reqFormat.maxFrameRate(), frameRate)
- && reqFormat.pixelFormat() == pixelFormat) {
- mediaType->Release();
- return index;
- }
-
- if ((currFrameRate < 29.9 && currFrameRate < frameRate) ||
- (currFrameRate == frameRate && currArea < area)) {
- currArea = area;
- currFrameRate = frameRate;
- mediaIndex = index;
- }
- }
- }
- }
- }
- mediaType->Release();
- ++index;
- }
- }
-
- return mediaIndex;
-}
-
-
-// Prepares the source video stream and gets some metadata.
-HRESULT QWindowsMediaDeviceReader::prepareVideoStream(DWORD mediaTypeIndex)
-{
- if (!m_sourceReader)
- return E_FAIL;
-
- if (!m_videoSource)
- return S_OK; // It may be audio-only
-
- HRESULT hr;
-
- if (mediaTypeIndex == MEDIA_TYPE_INDEX_DEFAULT) {
- hr = m_sourceReader->GetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_VIDEO_STREAM),
- &m_videoMediaType);
- } else {
- hr = m_sourceReader->GetNativeMediaType(DWORD(MF_SOURCE_READER_FIRST_VIDEO_STREAM),
- mediaTypeIndex, &m_videoMediaType);
- if (SUCCEEDED(hr))
- hr = m_sourceReader->SetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_VIDEO_STREAM),
- nullptr, m_videoMediaType);
- }
-
- if (SUCCEEDED(hr)) {
-
- GUID subtype = GUID_NULL;
- hr = m_videoMediaType->GetGUID(MF_MT_SUBTYPE, &subtype);
- if (SUCCEEDED(hr)) {
-
- m_pixelFormat = QWindowsMultimediaUtils::pixelFormatFromMediaSubtype(subtype);
-
- if (m_pixelFormat == QVideoFrameFormat::Format_Invalid) {
- hr = E_FAIL;
- } else {
-
- // get the frame dimensions
- hr = MFGetAttributeSize(m_videoMediaType, MF_MT_FRAME_SIZE, &m_frameWidth, &m_frameHeight);
- if (SUCCEEDED(hr)) {
-
- // and the stride, which we need to convert the frame later
- hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, m_frameWidth, &m_stride);
- if (SUCCEEDED(hr)) {
-
- UINT32 frameRateNum, frameRateDen;
- hr = MFGetAttributeRatio(m_videoMediaType, MF_MT_FRAME_RATE, &frameRateNum, &frameRateDen);
- if (SUCCEEDED(hr)) {
-
- m_frameRate = qreal(frameRateNum) / frameRateDen;
-
- hr = m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_VIDEO_STREAM), TRUE);
- }
- }
- }
- }
- }
- }
-
- return hr;
-}
-
-HRESULT QWindowsMediaDeviceReader::initAudioType(IMFMediaType *mediaType, UINT32 channels, UINT32 samplesPerSec, bool flt)
-{
- if (!mediaType)
- return E_INVALIDARG;
-
- HRESULT hr = mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
- if (SUCCEEDED(hr)) {
- hr = mediaType->SetGUID(MF_MT_SUBTYPE, flt ? MFAudioFormat_Float : MFAudioFormat_PCM);
- if (SUCCEEDED(hr)) {
- hr = mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, channels);
- if (SUCCEEDED(hr)) {
- hr = mediaType->SetUINT32(MF_MT_AUDIO_CHANNEL_MASK,
- (channels == 1) ? SPEAKER_FRONT_CENTER : (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT ));
- if (SUCCEEDED(hr)) {
- hr = mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSec);
- if (SUCCEEDED(hr)) {
- UINT32 bitsPerSample = flt ? 32 : 16;
- UINT32 bytesPerFrame = channels * bitsPerSample/8;
- hr = mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample);
- if (SUCCEEDED(hr)) {
- hr = mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, bytesPerFrame);
- if (SUCCEEDED(hr)) {
- hr = mediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bytesPerFrame * samplesPerSec);
- }
- }
- }
- }
- }
- }
- }
-
- return hr;
-}
-
-// Prepares the source audio stream.
-HRESULT QWindowsMediaDeviceReader::prepareAudioStream()
-{
- if (!m_sourceReader)
- return E_FAIL;
-
- if (!m_audioSource)
- return S_OK; // It may be video-only
-
- HRESULT hr = m_sourceReader->GetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM),
- &m_audioMediaType);
- if (SUCCEEDED(hr)) {
- hr = initAudioType(m_audioMediaType, 2, 48000, true);
- if (SUCCEEDED(hr)) {
- hr = m_sourceReader->SetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM),
- nullptr, m_audioMediaType);
- if (SUCCEEDED(hr)) {
- hr = m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
- }
- }
- }
- return hr;
-}
-
-// Retrieves the indexes for selected video/audio streams.
-HRESULT QWindowsMediaDeviceReader::initSourceIndexes()
-{
- if (!m_sourceReader)
- return E_FAIL;
-
- m_sourceVideoStreamIndex = MF_SOURCE_READER_INVALID_STREAM_INDEX;
- m_sourceAudioStreamIndex = MF_SOURCE_READER_INVALID_STREAM_INDEX;
-
- DWORD index = 0;
- BOOL selected = FALSE;
-
- while (m_sourceReader->GetStreamSelection(index, &selected) == S_OK) {
- if (selected) {
- IMFMediaType *mediaType = nullptr;
- if (SUCCEEDED(m_sourceReader->GetCurrentMediaType(index, &mediaType))) {
- GUID majorType = GUID_NULL;
- if (SUCCEEDED(mediaType->GetGUID(MF_MT_MAJOR_TYPE, &majorType))) {
- if (majorType == MFMediaType_Video)
- m_sourceVideoStreamIndex = index;
- else if (majorType == MFMediaType_Audio)
- m_sourceAudioStreamIndex = index;
- }
- mediaType->Release();
- }
- }
- ++index;
- }
- if ((m_videoSource && m_sourceVideoStreamIndex == MF_SOURCE_READER_INVALID_STREAM_INDEX) ||
- (m_audioSource && m_sourceAudioStreamIndex == MF_SOURCE_READER_INVALID_STREAM_INDEX))
- return E_FAIL;
- return S_OK;
-}
-
-bool QWindowsMediaDeviceReader::setAudioOutput(const QString &audioOutputId)
-{
- QMutexLocker locker(&m_mutex);
-
- stopMonitoring();
-
- m_audioOutputId = audioOutputId;
-
- if (!m_active || m_audioOutputId.isEmpty())
- return true;
-
- HRESULT hr = startMonitoring();
-
- return SUCCEEDED(hr);
-}
-
-HRESULT QWindowsMediaDeviceReader::startMonitoring()
-{
- if (m_audioOutputId.isEmpty())
- return E_FAIL;
-
- IMFAttributes *sinkAttributes = nullptr;
-
- HRESULT hr = MFCreateAttributes(&sinkAttributes, 1);
- if (SUCCEEDED(hr)) {
-
- hr = sinkAttributes->SetString(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID,
- reinterpret_cast<LPCWSTR>(m_audioOutputId.utf16()));
- if (SUCCEEDED(hr)) {
-
- IMFMediaSink *mediaSink = nullptr;
- hr = MFCreateAudioRenderer(sinkAttributes, &mediaSink);
- if (SUCCEEDED(hr)) {
-
- IMFStreamSink *streamSink = nullptr;
- hr = mediaSink->GetStreamSinkByIndex(0, &streamSink);
- if (SUCCEEDED(hr)) {
-
- IMFMediaTypeHandler *typeHandler = nullptr;
- hr = streamSink->GetMediaTypeHandler(&typeHandler);
- if (SUCCEEDED(hr)) {
-
- hr = typeHandler->IsMediaTypeSupported(m_audioMediaType, nullptr);
- if (SUCCEEDED(hr)) {
-
- hr = typeHandler->SetCurrentMediaType(m_audioMediaType);
- if (SUCCEEDED(hr)) {
-
- IMFAttributes *writerAttributes = nullptr;
-
- HRESULT hr = MFCreateAttributes(&writerAttributes, 1);
- if (SUCCEEDED(hr)) {
-
- hr = writerAttributes->SetUINT32(MF_SINK_WRITER_DISABLE_THROTTLING, TRUE);
- if (SUCCEEDED(hr)) {
-
- IMFSinkWriter *sinkWriter = nullptr;
- hr = MFCreateSinkWriterFromMediaSink(mediaSink, writerAttributes, &sinkWriter);
- if (SUCCEEDED(hr)) {
-
- hr = sinkWriter->SetInputMediaType(0, m_audioMediaType, nullptr);
- if (SUCCEEDED(hr)) {
-
- IMFSimpleAudioVolume *audioVolume = nullptr;
-
- if (SUCCEEDED(MFGetService(mediaSink, MR_POLICY_VOLUME_SERVICE, IID_PPV_ARGS(&audioVolume)))) {
- audioVolume->SetMasterVolume(float(m_outputVolume));
- audioVolume->SetMute(m_outputMuted);
- audioVolume->Release();
- }
-
- hr = sinkWriter->BeginWriting();
- if (SUCCEEDED(hr)) {
- m_monitorSink = mediaSink;
- m_monitorSink->AddRef();
- m_monitorWriter = sinkWriter;
- m_monitorWriter->AddRef();
- }
- }
- sinkWriter->Release();
- }
- }
- writerAttributes->Release();
- }
- }
- }
- typeHandler->Release();
- }
- streamSink->Release();
- }
- mediaSink->Release();
- }
- }
- sinkAttributes->Release();
- }
-
- return hr;
-}
-
-void QWindowsMediaDeviceReader::stopMonitoring()
-{
- if (m_monitorWriter) {
- m_monitorWriter->Release();
- m_monitorWriter = nullptr;
- }
- if (m_monitorSink) {
- m_monitorSink->Shutdown();
- m_monitorSink->Release();
- m_monitorSink = nullptr;
- }
-}
-
-// Activates the requested camera/microphone for streaming.
-// One of the IDs may be empty for video-only/audio-only.
-bool QWindowsMediaDeviceReader::activate(const QString &cameraId,
- const QCameraFormat &cameraFormat,
- const QString &microphoneId)
-{
- QMutexLocker locker(&m_mutex);
-
- if (cameraId.isEmpty() && microphoneId.isEmpty())
- return false;
-
- stopMonitoring();
- releaseResources();
-
- m_active = false;
- m_streaming = false;
-
- if (!cameraId.isEmpty()) {
- if (!SUCCEEDED(createSource(cameraId, true, &m_videoSource))) {
- releaseResources();
- return false;
- }
- }
-
- if (!microphoneId.isEmpty()) {
- if (!SUCCEEDED(createSource(microphoneId, false, &m_audioSource))) {
- releaseResources();
- return false;
- }
- }
-
- if (!SUCCEEDED(createAggregateReader(m_videoSource, m_audioSource, &m_aggregateSource, &m_sourceReader))) {
- releaseResources();
- return false;
- }
-
- DWORD mediaTypeIndex = findMediaTypeIndex(cameraFormat);
-
- if (!SUCCEEDED(prepareVideoStream(mediaTypeIndex))) {
- releaseResources();
- return false;
- }
-
- if (!SUCCEEDED(prepareAudioStream())) {
- releaseResources();
- return false;
- }
-
- if (!SUCCEEDED(initSourceIndexes())) {
- releaseResources();
- return false;
- }
-
- updateSinkInputMediaTypes();
- startMonitoring();
-
- // Request the first frame or audio sample.
- if (!SUCCEEDED(m_sourceReader->ReadSample(MF_SOURCE_READER_ANY_STREAM, 0, nullptr, nullptr, nullptr, nullptr))) {
- releaseResources();
- return false;
- }
-
- m_active = true;
- return true;
-}
-
-void QWindowsMediaDeviceReader::deactivate()
-{
- stopMonitoring();
- stopStreaming();
- m_active = false;
- m_streaming = false;
-}
-
-void QWindowsMediaDeviceReader::stopStreaming()
-{
- QMutexLocker locker(&m_mutex);
- releaseResources();
-}
-
-// Releases allocated streaming stuff.
-void QWindowsMediaDeviceReader::releaseResources()
-{
- if (m_videoMediaType) {
- m_videoMediaType->Release();
- m_videoMediaType = nullptr;
- }
- if (m_audioMediaType) {
- m_audioMediaType->Release();
- m_audioMediaType = nullptr;
- }
- if (m_sourceReader) {
- m_sourceReader->Release();
- m_sourceReader = nullptr;
- }
- if (m_aggregateSource) {
- m_aggregateSource->Release();
- m_aggregateSource = nullptr;
- }
- if (m_videoSource) {
- m_videoSource->Release();
- m_videoSource = nullptr;
- }
- if (m_audioSource) {
- m_audioSource->Release();
- m_audioSource = nullptr;
- }
-}
-
-HRESULT QWindowsMediaDeviceReader::createVideoMediaType(const GUID &format, UINT32 bitRate, UINT32 width,
- UINT32 height, qreal frameRate, IMFMediaType **mediaType)
-{
- if (!mediaType)
- return E_INVALIDARG;
-
- *mediaType = nullptr;
- IMFMediaType *targetMediaType = nullptr;
-
- if (SUCCEEDED(MFCreateMediaType(&targetMediaType))) {
-
- if (SUCCEEDED(targetMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video))) {
-
- if (SUCCEEDED(targetMediaType->SetGUID(MF_MT_SUBTYPE, format))) {
-
- if (SUCCEEDED(targetMediaType->SetUINT32(MF_MT_AVG_BITRATE, bitRate))) {
-
- if (SUCCEEDED(MFSetAttributeSize(targetMediaType, MF_MT_FRAME_SIZE, width, height))) {
-
- if (SUCCEEDED(MFSetAttributeRatio(targetMediaType, MF_MT_FRAME_RATE,
- UINT32(frameRate * 1000), 1000))) {
- UINT32 t1, t2;
- if (SUCCEEDED(MFGetAttributeRatio(m_videoMediaType, MF_MT_PIXEL_ASPECT_RATIO, &t1, &t2))) {
-
- if (SUCCEEDED(MFSetAttributeRatio(targetMediaType, MF_MT_PIXEL_ASPECT_RATIO, t1, t2))) {
-
- if (SUCCEEDED(m_videoMediaType->GetUINT32(MF_MT_INTERLACE_MODE, &t1))) {
-
- if (SUCCEEDED(targetMediaType->SetUINT32(MF_MT_INTERLACE_MODE, t1))) {
-
- *mediaType = targetMediaType;
- return S_OK;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- targetMediaType->Release();
- }
- return E_FAIL;
-}
-
-HRESULT QWindowsMediaDeviceReader::createAudioMediaType(const GUID &format, UINT32 bitRate, IMFMediaType **mediaType)
-{
- if (!mediaType)
- return E_INVALIDARG;
-
- *mediaType = nullptr;
- IMFMediaType *targetMediaType = nullptr;
-
- if (SUCCEEDED(MFCreateMediaType(&targetMediaType))) {
-
- if (SUCCEEDED(targetMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio))) {
-
- if (SUCCEEDED(targetMediaType->SetGUID(MF_MT_SUBTYPE, format))) {
-
- if (bitRate == 0 || SUCCEEDED(targetMediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bitRate / 8))) {
-
- *mediaType = targetMediaType;
- return S_OK;
- }
- }
- }
- targetMediaType->Release();
- }
- return E_FAIL;
-}
-
-HRESULT QWindowsMediaDeviceReader::updateSinkInputMediaTypes()
-{
- HRESULT hr = S_OK;
- if (m_sinkWriter) {
- if (m_videoSource && m_videoMediaType && m_sinkVideoStreamIndex != MF_SINK_WRITER_INVALID_STREAM_INDEX) {
- hr = m_sinkWriter->SetInputMediaType(m_sinkVideoStreamIndex, m_videoMediaType, nullptr);
- }
- if (SUCCEEDED(hr)) {
- if (m_audioSource && m_audioMediaType && m_sinkAudioStreamIndex != MF_SINK_WRITER_INVALID_STREAM_INDEX) {
- hr = m_sinkWriter->SetInputMediaType(m_sinkAudioStreamIndex, m_audioMediaType, nullptr);
- }
- }
- }
- return hr;
-}
-
-bool QWindowsMediaDeviceReader::startRecording(const QString &fileName, const GUID &container,
- const GUID &videoFormat, UINT32 videoBitRate, UINT32 width,
- UINT32 height, qreal frameRate, const GUID &audioFormat,
- UINT32 audioBitRate)
-{
- QMutexLocker locker(&m_mutex);
-
- if (!m_active || m_recording || (videoFormat == GUID_NULL && audioFormat == GUID_NULL))
- return false;
-
- IMFAttributes *writerAttributes = nullptr;
-
- HRESULT hr = MFCreateAttributes(&writerAttributes, 2);
- if (SUCCEEDED(hr)) {
-
- // Set callback so OnFinalize() is called after video is saved.
- hr = writerAttributes->SetUnknown(MF_SINK_WRITER_ASYNC_CALLBACK,
- static_cast<IMFSinkWriterCallback*>(this));
- if (SUCCEEDED(hr)) {
-
- hr = writerAttributes->SetGUID(MF_TRANSCODE_CONTAINERTYPE, container);
- if (SUCCEEDED(hr)) {
-
- hr = MFCreateSinkWriterFromURL(reinterpret_cast<LPCWSTR>(fileName.utf16()),
- nullptr, writerAttributes, &m_sinkWriter);
- if (SUCCEEDED(hr)) {
-
- m_sinkVideoStreamIndex = MF_SINK_WRITER_INVALID_STREAM_INDEX;
- m_sinkAudioStreamIndex = MF_SINK_WRITER_INVALID_STREAM_INDEX;
-
- if (m_videoSource && videoFormat != GUID_NULL) {
- IMFMediaType *targetMediaType = nullptr;
-
- hr = createVideoMediaType(videoFormat, videoBitRate, width, height,
- frameRate, &targetMediaType);
- if (SUCCEEDED(hr)) {
-
- hr = m_sinkWriter->AddStream(targetMediaType, &m_sinkVideoStreamIndex);
- if (SUCCEEDED(hr)) {
-
- hr = m_sinkWriter->SetInputMediaType(m_sinkVideoStreamIndex,
- m_videoMediaType, nullptr);
- }
- targetMediaType->Release();
- }
- }
-
- if (SUCCEEDED(hr)) {
-
- if (m_audioSource && audioFormat != GUID_NULL) {
- IMFMediaType *targetMediaType = nullptr;
-
- hr = createAudioMediaType(audioFormat, audioBitRate, &targetMediaType);
- if (SUCCEEDED(hr)) {
-
- hr = m_sinkWriter->AddStream(targetMediaType, &m_sinkAudioStreamIndex);
- if (SUCCEEDED(hr)) {
-
- hr = m_sinkWriter->SetInputMediaType(m_sinkAudioStreamIndex,
- m_audioMediaType, nullptr);
- }
- targetMediaType->Release();
- }
- }
-
- if (SUCCEEDED(hr)) {
-
- hr = m_sinkWriter->BeginWriting();
- if (SUCCEEDED(hr)) {
- m_lastDuration = -1;
- m_currentDuration = 0;
- updateDuration();
- m_durationTimer.start();
- m_recording = true;
- m_firstFrame = true;
- m_paused = false;
- m_pauseChanging = false;
- }
- }
- }
- }
- }
- }
- writerAttributes->Release();
- }
- if (m_sinkWriter && !SUCCEEDED(hr)) {
- m_sinkWriter->Release();
- m_sinkWriter = nullptr;
- }
- return SUCCEEDED(hr);
-}
-
-void QWindowsMediaDeviceReader::stopRecording()
-{
- QMutexLocker locker(&m_mutex);
-
- if (m_sinkWriter && m_recording) {
-
- HRESULT hr = m_sinkWriter->Finalize();
-
- if (SUCCEEDED(hr)) {
- m_hasFinalized.wait(&m_mutex);
- } else {
- m_sinkWriter->Release();
- m_sinkWriter = nullptr;
-
- QMetaObject::invokeMethod(this, "recordingError",
- Qt::QueuedConnection, Q_ARG(int, hr));
- }
- }
-
- m_recording = false;
- m_paused = false;
- m_pauseChanging = false;
-
- m_durationTimer.stop();
- m_lastDuration = -1;
- m_currentDuration = -1;
-}
-
-bool QWindowsMediaDeviceReader::pauseRecording()
-{
- if (!m_recording || m_paused)
- return false;
- m_pauseTime = m_lastTimestamp;
- m_paused = true;
- m_pauseChanging = true;
- return true;
-}
-
-bool QWindowsMediaDeviceReader::resumeRecording()
-{
- if (!m_recording || !m_paused)
- return false;
- m_paused = false;
- m_pauseChanging = true;
- return true;
-}
-
-//from IUnknown
-STDMETHODIMP QWindowsMediaDeviceReader::QueryInterface(REFIID riid, LPVOID *ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFSourceReaderCallback) {
- *ppvObject = static_cast<IMFSourceReaderCallback*>(this);
- } else if (riid == IID_IMFSinkWriterCallback) {
- *ppvObject = static_cast<IMFSinkWriterCallback*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(static_cast<IMFSourceReaderCallback*>(this));
- } else {
- *ppvObject = nullptr;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) QWindowsMediaDeviceReader::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) QWindowsMediaDeviceReader::Release(void)
-{
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0) {
- this->deleteLater();
- }
- return cRef;
-}
-
-UINT32 QWindowsMediaDeviceReader::frameWidth() const
-{
- return m_frameWidth;
-}
-
-UINT32 QWindowsMediaDeviceReader::frameHeight() const
-{
- return m_frameHeight;
-}
-
-qreal QWindowsMediaDeviceReader::frameRate() const
-{
- return m_frameRate;
-}
-
-void QWindowsMediaDeviceReader::setInputMuted(bool muted)
-{
- m_inputMuted = muted;
-}
-
-void QWindowsMediaDeviceReader::setInputVolume(qreal volume)
-{
- m_inputVolume = qBound(0.0, volume, 1.0);
-}
-
-void QWindowsMediaDeviceReader::setOutputMuted(bool muted)
-{
- QMutexLocker locker(&m_mutex);
-
- m_outputMuted = muted;
-
- if (m_active && m_monitorSink) {
- IMFSimpleAudioVolume *audioVolume = nullptr;
- if (SUCCEEDED(MFGetService(m_monitorSink, MR_POLICY_VOLUME_SERVICE,
- IID_PPV_ARGS(&audioVolume)))) {
- audioVolume->SetMute(m_outputMuted);
- audioVolume->Release();
- }
- }
-}
-
-void QWindowsMediaDeviceReader::setOutputVolume(qreal volume)
-{
- QMutexLocker locker(&m_mutex);
-
- m_outputVolume = qBound(0.0, volume, 1.0);
-
- if (m_active && m_monitorSink) {
- IMFSimpleAudioVolume *audioVolume = nullptr;
- if (SUCCEEDED(MFGetService(m_monitorSink, MR_POLICY_VOLUME_SERVICE,
- IID_PPV_ARGS(&audioVolume)))) {
- audioVolume->SetMasterVolume(float(m_outputVolume));
- audioVolume->Release();
- }
- }
-}
-
-void QWindowsMediaDeviceReader::updateDuration()
-{
- if (m_currentDuration >= 0 && m_lastDuration != m_currentDuration) {
- m_lastDuration = m_currentDuration;
- emit durationChanged(m_currentDuration);
- }
-}
-
-//from IMFSourceReaderCallback
-STDMETHODIMP QWindowsMediaDeviceReader::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex,
- DWORD dwStreamFlags, LONGLONG llTimestamp,
- IMFSample *pSample)
-{
- QMutexLocker locker(&m_mutex);
-
- if (FAILED(hrStatus)) {
- emit streamingError(int(hrStatus));
- return hrStatus;
- }
-
- m_lastTimestamp = llTimestamp;
-
- if ((dwStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM) == MF_SOURCE_READERF_ENDOFSTREAM) {
- m_streaming = false;
- emit streamingStopped();
- } else {
-
- if (!m_streaming) {
- m_streaming = true;
- emit streamingStarted();
- }
- if (pSample) {
-
- if (m_monitorWriter && dwStreamIndex == m_sourceAudioStreamIndex)
- m_monitorWriter->WriteSample(0, pSample);
-
- if (m_recording) {
-
- if (m_firstFrame) {
- m_timeOffset = llTimestamp;
- m_firstFrame = false;
- emit recordingStarted();
- }
-
- if (m_pauseChanging) {
- // Recording time should not pass while paused.
- if (m_paused)
- m_pauseTime = llTimestamp;
- else
- m_timeOffset += llTimestamp - m_pauseTime;
- m_pauseChanging = false;
- }
-
- // Send the video frame or audio sample to be encoded.
- if (m_sinkWriter && !m_paused) {
-
- pSample->SetSampleTime(llTimestamp - m_timeOffset);
-
- if (dwStreamIndex == m_sourceVideoStreamIndex) {
-
- m_sinkWriter->WriteSample(m_sinkVideoStreamIndex, pSample);
-
- } else if (dwStreamIndex == m_sourceAudioStreamIndex) {
-
- float volume = m_inputMuted ? 0.0f : float(m_inputVolume);
-
- // Change the volume of the audio sample, if needed.
- if (volume != 1.0f) {
- IMFMediaBuffer *mediaBuffer = nullptr;
- if (SUCCEEDED(pSample->ConvertToContiguousBuffer(&mediaBuffer))) {
-
- DWORD bufLen = 0;
- BYTE *buffer = nullptr;
-
- if (SUCCEEDED(mediaBuffer->Lock(&buffer, nullptr, &bufLen))) {
-
- float *floatBuffer = reinterpret_cast<float*>(buffer);
-
- for (DWORD i = 0; i < bufLen/4; ++i)
- floatBuffer[i] *= volume;
-
- mediaBuffer->Unlock();
- }
- mediaBuffer->Release();
- }
- }
-
- m_sinkWriter->WriteSample(m_sinkAudioStreamIndex, pSample);
- }
- m_currentDuration = (llTimestamp - m_timeOffset) / 10000;
- }
- }
-
- // Generate a new QVideoFrame from IMFSample.
- if (dwStreamIndex == m_sourceVideoStreamIndex) {
- IMFMediaBuffer *mediaBuffer = nullptr;
- if (SUCCEEDED(pSample->ConvertToContiguousBuffer(&mediaBuffer))) {
-
- DWORD bufLen = 0;
- BYTE *buffer = nullptr;
-
- if (SUCCEEDED(mediaBuffer->Lock(&buffer, nullptr, &bufLen))) {
- auto bytes = QByteArray(reinterpret_cast<char*>(buffer), bufLen);
-
- QVideoFrame frame(new QMemoryVideoBuffer(bytes, m_stride),
- QVideoFrameFormat(QSize(m_frameWidth, m_frameHeight), m_pixelFormat));
-
- // WMF uses 100-nanosecond units, Qt uses microseconds
- frame.setStartTime(llTimestamp * 0.1);
-
- LONGLONG duration = -1;
- if (SUCCEEDED(pSample->GetSampleDuration(&duration)))
- frame.setEndTime((llTimestamp + duration) * 0.1);
-
- emit videoFrameChanged(frame);
-
- mediaBuffer->Unlock();
- }
- mediaBuffer->Release();
- }
- }
- }
- // request the next video frame or sound sample
- if (m_sourceReader)
- m_sourceReader->ReadSample(MF_SOURCE_READER_ANY_STREAM,
- 0, nullptr, nullptr, nullptr, nullptr);
- }
-
- return S_OK;
-}
-
-STDMETHODIMP QWindowsMediaDeviceReader::OnFlush(DWORD)
-{
- return S_OK;
-}
-
-STDMETHODIMP QWindowsMediaDeviceReader::OnEvent(DWORD, IMFMediaEvent*)
-{
- return S_OK;
-}
-
-//from IMFSinkWriterCallback
-STDMETHODIMP QWindowsMediaDeviceReader::OnFinalize(HRESULT)
-{
- QMutexLocker locker(&m_mutex);
- if (m_sinkWriter) {
- m_sinkWriter->Release();
- m_sinkWriter = nullptr;
- }
- emit recordingStopped();
- m_hasFinalized.notify_one();
- return S_OK;
-}
-
-STDMETHODIMP QWindowsMediaDeviceReader::OnMarker(DWORD, LPVOID)
-{
- return S_OK;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader_p.h b/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader_p.h
deleted file mode 100644
index e7af22e5d..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicereader_p.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSMEDIADEVICEREADER_H
-#define QWINDOWSMEDIADEVICEREADER_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 <mfapi.h>
-#include <mfidl.h>
-#include <Mferror.h>
-#include <Mfreadwrite.h>
-
-#include <QtCore/qobject.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qwaitcondition.h>
-#include <QtCore/qtimer.h>
-#include <qvideoframe.h>
-#include <qcameradevice.h>
-
-QT_BEGIN_NAMESPACE
-
-class QVideoSink;
-
-class QWindowsMediaDeviceReader : public QObject,
- public IMFSourceReaderCallback,
- public IMFSinkWriterCallback
-{
- Q_OBJECT
-public:
- explicit QWindowsMediaDeviceReader(QObject *parent = nullptr);
- ~QWindowsMediaDeviceReader();
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
- STDMETHODIMP_(ULONG) AddRef(void);
- STDMETHODIMP_(ULONG) Release(void);
-
- //from IMFSourceReaderCallback
- STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex,
- DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample);
- STDMETHODIMP OnFlush(DWORD dwStreamIndex);
- STDMETHODIMP OnEvent(DWORD dwStreamIndex, IMFMediaEvent *pEvent);
-
- //from IMFSinkWriterCallback
- STDMETHODIMP OnFinalize(HRESULT hrStatus);
- STDMETHODIMP OnMarker(DWORD dwStreamIndex, LPVOID pvContext);
-
- bool activate(const QString &cameraId,
- const QCameraFormat &cameraFormat,
- const QString &microphoneId);
- void deactivate();
-
- bool startRecording(const QString &fileName, const GUID &container,
- const GUID &videoFormat, UINT32 videoBitRate, UINT32 width,
- UINT32 height, qreal frameRate, const GUID &audioFormat,
- UINT32 audioBitRate);
- void stopRecording();
- bool pauseRecording();
- bool resumeRecording();
-
- UINT32 frameWidth() const;
- UINT32 frameHeight() const;
- qreal frameRate() const;
- void setInputMuted(bool muted);
- void setInputVolume(qreal volume);
- void setOutputMuted(bool muted);
- void setOutputVolume(qreal volume);
- bool setAudioOutput(const QString &audioOutputId);
-
-Q_SIGNALS:
- void streamingStarted();
- void streamingStopped();
- void streamingError(int errorCode);
- void recordingStarted();
- void recordingStopped();
- void recordingError(int errorCode);
- void durationChanged(qint64 duration);
- void videoFrameChanged(const QVideoFrame &frame);
-
-private slots:
- void updateDuration();
-
-private:
- HRESULT createSource(const QString &deviceId, bool video, IMFMediaSource **source);
- HRESULT createAggregateReader(IMFMediaSource *firstSource, IMFMediaSource *secondSource,
- IMFMediaSource **aggregateSource, IMFSourceReader **sourceReader);
- HRESULT createVideoMediaType(const GUID &format, UINT32 bitRate, UINT32 width, UINT32 height,
- qreal frameRate, IMFMediaType **mediaType);
- HRESULT createAudioMediaType(const GUID &format, UINT32 bitRate, IMFMediaType **mediaType);
- HRESULT initAudioType(IMFMediaType *mediaType, UINT32 channels, UINT32 samplesPerSec, bool flt);
- HRESULT prepareVideoStream(DWORD mediaTypeIndex);
- HRESULT prepareAudioStream();
- HRESULT initSourceIndexes();
- HRESULT updateSinkInputMediaTypes();
- HRESULT startMonitoring();
- void stopMonitoring();
- void releaseResources();
- void stopStreaming();
- DWORD findMediaTypeIndex(const QCameraFormat &reqFormat);
-
- long m_cRef = 1;
- QMutex m_mutex;
- QWaitCondition m_hasFinalized;
- IMFMediaSource *m_videoSource = nullptr;
- IMFMediaType *m_videoMediaType = nullptr;
- IMFMediaSource *m_audioSource = nullptr;
- IMFMediaType *m_audioMediaType = nullptr;
- IMFMediaSource *m_aggregateSource = nullptr;
- IMFSourceReader *m_sourceReader = nullptr;
- IMFSinkWriter *m_sinkWriter = nullptr;
- IMFMediaSink *m_monitorSink = nullptr;
- IMFSinkWriter *m_monitorWriter = nullptr;
- QString m_audioOutputId;
- DWORD m_sourceVideoStreamIndex = MF_SOURCE_READER_INVALID_STREAM_INDEX;
- DWORD m_sourceAudioStreamIndex = MF_SOURCE_READER_INVALID_STREAM_INDEX;
- DWORD m_sinkVideoStreamIndex = MF_SINK_WRITER_INVALID_STREAM_INDEX;
- DWORD m_sinkAudioStreamIndex = MF_SINK_WRITER_INVALID_STREAM_INDEX;
- UINT32 m_frameWidth = 0;
- UINT32 m_frameHeight = 0;
- qreal m_frameRate = 0.0;
- LONG m_stride = 0;
- bool m_active = false;
- bool m_streaming = false;
- bool m_recording = false;
- bool m_firstFrame = false;
- bool m_paused = false;
- bool m_pauseChanging = false;
- bool m_inputMuted = false;
- bool m_outputMuted = false;
- qreal m_inputVolume = 1.0;
- qreal m_outputVolume = 1.0;
- QVideoFrameFormat::PixelFormat m_pixelFormat = QVideoFrameFormat::Format_Invalid;
- LONGLONG m_timeOffset = 0;
- LONGLONG m_pauseTime = 0;
- LONGLONG m_lastTimestamp = 0;
- QTimer m_durationTimer;
- qint64 m_currentDuration = -1;
- qint64 m_lastDuration = -1;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSMEDIADEVICEREADER_H
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp b/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp
deleted file mode 100644
index c43771d23..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp
+++ /dev/null
@@ -1,399 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsmediadevicesession_p.h"
-
-#include "qwindowsmediadevicereader_p.h"
-#include "qwindowsmultimediautils_p.h"
-#include "private/qplatformvideosink_p.h"
-#include <qvideosink.h>
-#include <QtCore/qdebug.h>
-#include <qaudioinput.h>
-#include <qaudiooutput.h>
-
-QT_BEGIN_NAMESPACE
-
-QWindowsMediaDeviceSession::QWindowsMediaDeviceSession(QObject *parent)
- : QObject(parent)
-{
- m_mediaDeviceReader = new QWindowsMediaDeviceReader(this);
- connect(m_mediaDeviceReader, SIGNAL(streamingStarted()), this, SLOT(handleStreamingStarted()));
- connect(m_mediaDeviceReader, SIGNAL(streamingStopped()), this, SLOT(handleStreamingStopped()));
- connect(m_mediaDeviceReader, SIGNAL(streamingError(int)), this, SLOT(handleStreamingError(int)));
- connect(m_mediaDeviceReader, SIGNAL(videoFrameChanged(QVideoFrame)), this, SLOT(handleVideoFrameChanged(QVideoFrame)));
- connect(m_mediaDeviceReader, SIGNAL(recordingStarted()), this, SIGNAL(recordingStarted()));
- connect(m_mediaDeviceReader, SIGNAL(recordingStopped()), this, SIGNAL(recordingStopped()));
- connect(m_mediaDeviceReader, SIGNAL(recordingError(int)), this, SIGNAL(recordingError(int)));
- connect(m_mediaDeviceReader, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64)));
-}
-
-QWindowsMediaDeviceSession::~QWindowsMediaDeviceSession()
-{
- delete m_mediaDeviceReader;
-}
-
-bool QWindowsMediaDeviceSession::isActive() const
-{
- return m_active;
-}
-
-bool QWindowsMediaDeviceSession::isActivating() const
-{
- return m_activating;
-}
-
-void QWindowsMediaDeviceSession::setActive(bool active)
-{
- if ((active && (m_active || m_activating)) || (!active && !m_active && !m_activating))
- return;
-
- if (active) {
- auto camId = QString::fromUtf8(m_activeCameraDevice.id());
- auto micId = m_audioInput ? QString::fromUtf8(m_audioInput->device().id()) : QString();
- if (!camId.isEmpty() || !micId.isEmpty()) {
- if (m_mediaDeviceReader->activate(camId, m_cameraFormat, micId)) {
- m_activating = true;
- } else {
- emit streamingError(MF_E_NOT_AVAILABLE);
- }
- } else {
- qWarning() << Q_FUNC_INFO << "Camera ID and Microphone ID both undefined.";
- }
- } else {
- m_mediaDeviceReader->deactivate();
- m_active = false;
- m_activating = false;
- emit activeChanged(m_active);
- emit readyForCaptureChanged(m_active);
- }
-}
-
-void QWindowsMediaDeviceSession::reactivate()
-{
- if (m_active || m_activating) {
- pauseRecording();
- setActive(false);
- setActive(true);
- resumeRecording();
- }
-}
-
-void QWindowsMediaDeviceSession::setActiveCamera(const QCameraDevice &camera)
-{
- m_activeCameraDevice = camera;
- reactivate();
-}
-
-QCameraDevice QWindowsMediaDeviceSession::activeCamera() const
-{
- return m_activeCameraDevice;
-}
-
-void QWindowsMediaDeviceSession::setCameraFormat(const QCameraFormat &cameraFormat)
-{
- m_cameraFormat = cameraFormat;
-}
-
-void QWindowsMediaDeviceSession::setVideoSink(QVideoSink *surface)
-{
- m_surface = surface;
-}
-
-void QWindowsMediaDeviceSession::handleStreamingStarted()
-{
- m_active = true;
- m_activating = false;
- emit activeChanged(m_active);
- emit readyForCaptureChanged(m_active);
-}
-
-void QWindowsMediaDeviceSession::handleStreamingStopped()
-{
- m_active = false;
- emit activeChanged(m_active);
- emit readyForCaptureChanged(m_active);
-}
-
-void QWindowsMediaDeviceSession::handleStreamingError(int errorCode)
-{
- if (m_surface)
- emit m_surface->platformVideoSink()->setVideoFrame(QVideoFrame());
- emit streamingError(errorCode);
-}
-
-void QWindowsMediaDeviceSession::handleVideoFrameChanged(const QVideoFrame &frame)
-{
- if (m_surface)
- emit m_surface->platformVideoSink()->setVideoFrame(frame);
- emit videoFrameChanged(frame);
-}
-
-void QWindowsMediaDeviceSession::setAudioInputMuted(bool muted)
-{
- m_mediaDeviceReader->setInputMuted(muted);
-}
-
-void QWindowsMediaDeviceSession::setAudioInputVolume(float volume)
-{
- m_mediaDeviceReader->setInputVolume(volume);
-}
-
-void QWindowsMediaDeviceSession::audioInputDeviceChanged()
-{
- reactivate();
-}
-
-void QWindowsMediaDeviceSession::setAudioOutputMuted(bool muted)
-{
- m_mediaDeviceReader->setOutputMuted(muted);
-}
-
-void QWindowsMediaDeviceSession::setAudioOutputVolume(float volume)
-{
- m_mediaDeviceReader->setOutputVolume(volume);
-}
-
-void QWindowsMediaDeviceSession::audioOutputDeviceChanged()
-{
- if (m_active || m_activating)
- m_mediaDeviceReader->setAudioOutput(QString::fromUtf8(m_audioOutput->device().id()));
-}
-
-void QWindowsMediaDeviceSession::setAudioInput(QAudioInput *input)
-{
- if (m_audioInput == input)
- return;
- if (m_audioInput)
- m_audioInput->disconnect(this);
- m_audioInput = input;
-
- audioInputDeviceChanged();
-
- if (!m_audioInput)
- return;
- connect(m_audioInput, &QAudioInput::mutedChanged, this, &QWindowsMediaDeviceSession::setAudioInputMuted);
- connect(m_audioInput, &QAudioInput::volumeChanged, this, &QWindowsMediaDeviceSession::setAudioInputVolume);
- connect(m_audioInput, &QAudioInput::deviceChanged, this, &QWindowsMediaDeviceSession::audioInputDeviceChanged);
-}
-
-void QWindowsMediaDeviceSession::setAudioOutput(QAudioOutput *output)
-{
- if (m_audioOutput == output)
- return;
- if (m_audioOutput)
- m_audioOutput->disconnect(this);
- m_audioOutput = output;
- if (!m_audioOutput) {
- m_mediaDeviceReader->setAudioOutput({});
- return;
- }
-
- m_mediaDeviceReader->setAudioOutput(QString::fromUtf8(m_audioOutput->device().id()));
-
- connect(m_audioOutput, &QAudioOutput::mutedChanged, this, &QWindowsMediaDeviceSession::setAudioOutputMuted);
- connect(m_audioOutput, &QAudioOutput::volumeChanged, this, &QWindowsMediaDeviceSession::setAudioOutputVolume);
- connect(m_audioOutput, &QAudioOutput::deviceChanged, this, &QWindowsMediaDeviceSession::audioOutputDeviceChanged);
-}
-
-bool QWindowsMediaDeviceSession::startRecording(QMediaEncoderSettings &settings, const QString &fileName, bool audioOnly)
-{
- GUID container = QWindowsMultimediaUtils::containerForVideoFileFormat(settings.mediaFormat().fileFormat());
- GUID videoFormat = QWindowsMultimediaUtils::videoFormatForCodec(settings.videoCodec());
- GUID audioFormat = QWindowsMultimediaUtils::audioFormatForCodec(settings.audioCodec());
-
- QSize res = settings.videoResolution();
- UINT32 width, height;
- if (res.width() > 0 && res.height() > 0) {
- width = UINT32(res.width());
- height = UINT32(res.height());
- } else {
- width = m_mediaDeviceReader->frameWidth();
- height = m_mediaDeviceReader->frameHeight();
- settings.setVideoResolution(QSize(int(width), int(height)));
- }
-
- qreal frameRate = settings.videoFrameRate();
- if (frameRate <= 0) {
- frameRate = m_mediaDeviceReader->frameRate();
- settings.setVideoFrameRate(frameRate);
- }
-
- auto quality = settings.quality();
-
- UINT32 videoBitRate = 0;
- if (settings.videoBitRate() > 0) {
- videoBitRate = UINT32(settings.videoBitRate());
- } else {
- videoBitRate = estimateVideoBitRate(videoFormat, width, height, frameRate, quality);
- settings.setVideoBitRate(int(videoBitRate));
- }
-
- UINT32 audioBitRate = 0;
- if (settings.audioBitRate() > 0) {
- audioBitRate = UINT32(settings.audioBitRate());
- } else {
- audioBitRate = estimateAudioBitRate(audioFormat, quality);
- settings.setAudioBitRate(int(audioBitRate));
- }
-
- return m_mediaDeviceReader->startRecording(fileName, container, audioOnly ? GUID_NULL : videoFormat,
- videoBitRate, width, height, frameRate,
- audioFormat, audioBitRate);
-}
-
-void QWindowsMediaDeviceSession::stopRecording()
-{
- m_mediaDeviceReader->stopRecording();
-}
-
-bool QWindowsMediaDeviceSession::pauseRecording()
-{
- return m_mediaDeviceReader->pauseRecording();
-}
-
-bool QWindowsMediaDeviceSession::resumeRecording()
-{
- return m_mediaDeviceReader->resumeRecording();
-}
-
-// empirical estimate of the required video bitrate (for H.264)
-quint32 QWindowsMediaDeviceSession::estimateVideoBitRate(const GUID &videoFormat, quint32 width, quint32 height,
- qreal frameRate, QMediaRecorder::Quality quality)
-{
- Q_UNUSED(videoFormat);
-
- qreal bitsPerPixel;
- switch (quality) {
- case QMediaRecorder::Quality::VeryLowQuality:
- bitsPerPixel = 0.08;
- break;
- case QMediaRecorder::Quality::LowQuality:
- bitsPerPixel = 0.2;
- break;
- case QMediaRecorder::Quality::NormalQuality:
- bitsPerPixel = 0.3;
- break;
- case QMediaRecorder::Quality::HighQuality:
- bitsPerPixel = 0.5;
- break;
- case QMediaRecorder::Quality::VeryHighQuality:
- bitsPerPixel = 0.8;
- break;
- default:
- bitsPerPixel = 0.3;
- }
-
- // Required bitrate is not linear on the number of pixels; small resolutions
- // require more BPP, thus the minimum values, to try to compensate it.
- quint32 pixelsPerSec = quint32(qMax(width, 320u) * qMax(height, 240u) * qMax(frameRate, 6.0));
- return pixelsPerSec * bitsPerPixel;
-}
-
-quint32 QWindowsMediaDeviceSession::estimateAudioBitRate(const GUID &audioFormat, QMediaRecorder::Quality quality)
-{
- if (audioFormat == MFAudioFormat_AAC) {
- // Bitrates supported by the AAC encoder are 96K, 128K, 160K, 192K.
- switch (quality) {
- case QMediaRecorder::Quality::VeryLowQuality:
- return 96000;
- case QMediaRecorder::Quality::LowQuality:
- return 96000;
- case QMediaRecorder::Quality::NormalQuality:
- return 128000;
- case QMediaRecorder::Quality::HighQuality:
- return 160000;
- case QMediaRecorder::Quality::VeryHighQuality:
- return 192000;
- default:
- return 128000;
- }
- } else if (audioFormat == MFAudioFormat_MP3) {
- // Bitrates supported by the MP3 encoder are
- // 32K, 40K, 48K, 56K, 64K, 80K, 96K, 112K, 128K, 160K, 192K, 224K, 256K, 320K.
- switch (quality) {
- case QMediaRecorder::Quality::VeryLowQuality:
- return 48000;
- case QMediaRecorder::Quality::LowQuality:
- return 96000;
- case QMediaRecorder::Quality::NormalQuality:
- return 128000;
- case QMediaRecorder::Quality::HighQuality:
- return 224000;
- case QMediaRecorder::Quality::VeryHighQuality:
- return 320000;
- default:
- return 128000;
- }
- } else if (audioFormat == MFAudioFormat_WMAudioV8) {
- // Bitrates supported by the Windows Media Audio 8 encoder
- switch (quality) {
- case QMediaRecorder::Quality::VeryLowQuality:
- return 32000;
- case QMediaRecorder::Quality::LowQuality:
- return 96000;
- case QMediaRecorder::Quality::NormalQuality:
- return 192000;
- case QMediaRecorder::Quality::HighQuality:
- return 256016;
- case QMediaRecorder::Quality::VeryHighQuality:
- return 320032;
- default:
- return 192000;
- }
- } else if (audioFormat == MFAudioFormat_WMAudioV9) {
- // Bitrates supported by the Windows Media Audio 9 encoder
- switch (quality) {
- case QMediaRecorder::Quality::VeryLowQuality:
- return 32000;
- case QMediaRecorder::Quality::LowQuality:
- return 96000;
- case QMediaRecorder::Quality::NormalQuality:
- return 192000;
- case QMediaRecorder::Quality::HighQuality:
- return 256016;
- case QMediaRecorder::Quality::VeryHighQuality:
- return 384000;
- default:
- return 192000;
- }
- }
- return 0; // Use default for format
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession_p.h b/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession_p.h
deleted file mode 100644
index 4620bd6fb..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession_p.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSMEDIADEVICESESSION_H
-#define QWINDOWSMEDIADEVICESESSION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtmultimediaglobal_p.h>
-#include <qcamera.h>
-#include <qaudiodevice.h>
-#include <qwindowsmultimediautils_p.h>
-#include <qplatformmediaencoder_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAudioInput;
-class QAudioOutput;
-class QVideoSink;
-class QWindowsMediaDeviceReader;
-
-class QWindowsMediaDeviceSession : public QObject
-{
- Q_OBJECT
-public:
- explicit QWindowsMediaDeviceSession(QObject *parent = nullptr);
- ~QWindowsMediaDeviceSession();
-
- bool isActive() const;
- void setActive(bool active);
-
- bool isActivating() const;
-
- void setActiveCamera(const QCameraDevice &camera);
- QCameraDevice activeCamera() const;
-
- void setCameraFormat(const QCameraFormat &cameraFormat);
-
- void setVideoSink(QVideoSink *surface);
-
-public Q_SLOTS:
- void setAudioInputMuted(bool muted);
- void setAudioInputVolume(float volume);
- void audioInputDeviceChanged();
- void setAudioOutputMuted(bool muted);
- void setAudioOutputVolume(float volume);
- void audioOutputDeviceChanged();
-
-public:
- void setAudioInput(QAudioInput *input);
- void setAudioOutput(QAudioOutput *output);
-
- bool startRecording(QMediaEncoderSettings &settings, const QString &fileName, bool audioOnly);
- void stopRecording();
- bool pauseRecording();
- bool resumeRecording();
-
-Q_SIGNALS:
- void activeChanged(bool);
- void readyForCaptureChanged(bool);
- void durationChanged(qint64 duration);
- void recordingStarted();
- void recordingStopped();
- void streamingError(int errorCode);
- void recordingError(int errorCode);
- void videoFrameChanged(const QVideoFrame &frame);
-
-private Q_SLOTS:
- void handleStreamingStarted();
- void handleStreamingStopped();
- void handleStreamingError(int errorCode);
- void handleVideoFrameChanged(const QVideoFrame &frame);
-
-private:
- void reactivate();
- quint32 estimateVideoBitRate(const GUID &videoFormat, quint32 width, quint32 height,
- qreal frameRate, QMediaRecorder::Quality quality);
- quint32 estimateAudioBitRate(const GUID &audioFormat, QMediaRecorder::Quality quality);
- bool m_active = false;
- bool m_activating = false;
- QCameraDevice m_activeCameraDevice;
- QCameraFormat m_cameraFormat;
- QWindowsMediaDeviceReader *m_mediaDeviceReader = nullptr;
- QAudioInput *m_audioInput = nullptr;
- QAudioOutput *m_audioOutput = nullptr;
- QVideoSink *m_surface = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSMEDIADEVICESESSION_H
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder.cpp b/src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder.cpp
deleted file mode 100644
index 555d5bbda..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsmediaencoder_p.h"
-
-#include "qwindowsmediadevicesession_p.h"
-#include "qwindowsmediacapture_p.h"
-#include "qmediastoragelocation_p.h"
-#include "mfmetadata_p.h"
-#include <QtCore/QUrl>
-#include <QtCore/QMimeType>
-#include <Mferror.h>
-#include <shobjidl.h>
-#include <private/qmediarecorder_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QWindowsMediaEncoder::QWindowsMediaEncoder(QMediaRecorder *parent)
- : QObject(parent),
- QPlatformMediaEncoder(parent)
-{
-}
-
-bool QWindowsMediaEncoder::isLocationWritable(const QUrl &location) const
-{
- return location.scheme() == QLatin1String("file") || location.scheme().isEmpty();
-}
-
-QMediaRecorder::RecorderState QWindowsMediaEncoder::state() const
-{
- return m_state;
-}
-
-qint64 QWindowsMediaEncoder::duration() const
-{
- return m_duration;
-}
-
-void QWindowsMediaEncoder::record(QMediaEncoderSettings &settings)
-{
- if (!m_captureService || !m_mediaDeviceSession) {
- qWarning() << Q_FUNC_INFO << "Encoder is not set to a capture session";
- return;
- }
- if (m_state != QMediaRecorder::StoppedState)
- return;
-
- m_mediaDeviceSession->setActive(true);
-
- if (!m_mediaDeviceSession->isActive() && !m_mediaDeviceSession->isActivating()) {
- error(QMediaRecorder::ResourceError,
- QMediaRecorderPrivate::msgFailedStartRecording());
- return;
- }
-
- const auto audioOnly = settings.videoCodec() == QMediaFormat::VideoCodec::Unspecified;
-
- const QString path = (outputLocation().scheme() == QLatin1String("file") ?
- outputLocation().path() : outputLocation().toString());
-
- m_fileName = QMediaStorageLocation::generateFileName(path, audioOnly
- ? QStandardPaths::MusicLocation
- : QStandardPaths::MoviesLocation,
- settings.mimeType().preferredSuffix());
-
- if (m_mediaDeviceSession->startRecording(settings, m_fileName, audioOnly)) {
-
- m_state = QMediaRecorder::RecordingState;
-
- actualLocationChanged(QUrl::fromLocalFile(m_fileName));
- stateChanged(m_state);
-
- } else {
- error(QMediaRecorder::FormatError,
- QMediaRecorderPrivate::msgFailedStartRecording());
- }
-}
-
-void QWindowsMediaEncoder::pause()
-{
- if (!m_mediaDeviceSession || m_state != QMediaRecorder::RecordingState)
- return;
-
- if (m_mediaDeviceSession->pauseRecording()) {
- m_state = QMediaRecorder::PausedState;
- stateChanged(m_state);
- } else {
- error(QMediaRecorder::FormatError, tr("Failed to pause recording"));
- }
-}
-
-void QWindowsMediaEncoder::resume()
-{
- if (!m_mediaDeviceSession || m_state != QMediaRecorder::PausedState)
- return;
-
- if (m_mediaDeviceSession->resumeRecording()) {
- m_state = QMediaRecorder::RecordingState;
- stateChanged(m_state);
- } else {
- error(QMediaRecorder::FormatError, tr("Failed to resume recording"));
- }
-}
-
-void QWindowsMediaEncoder::stop()
-{
- if (m_mediaDeviceSession && m_state != QMediaRecorder::StoppedState)
- m_mediaDeviceSession->stopRecording();
-}
-
-
-
-void QWindowsMediaEncoder::setCaptureSession(QPlatformMediaCaptureSession *session)
-{
- QWindowsMediaCaptureService *captureSession = static_cast<QWindowsMediaCaptureService *>(session);
- if (m_captureService == captureSession)
- return;
-
- if (m_captureService)
- stop();
-
- m_captureService = captureSession;
- if (!m_captureService) {
- m_mediaDeviceSession = nullptr;
- return;
- }
-
- m_mediaDeviceSession = m_captureService->session();
- Q_ASSERT(m_mediaDeviceSession);
-
- connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::recordingStarted, this, &QWindowsMediaEncoder::onRecordingStarted);
- connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::recordingStopped, this, &QWindowsMediaEncoder::onRecordingStopped);
- connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::streamingError, this, &QWindowsMediaEncoder::onStreamingError);
- connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::recordingError, this, &QWindowsMediaEncoder::onRecordingError);
- connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::durationChanged, this, &QWindowsMediaEncoder::onDurationChanged);
- connect(m_captureService, &QWindowsMediaCaptureService::cameraChanged, this, &QWindowsMediaEncoder::onCameraChanged);
- onCameraChanged();
-}
-
-void QWindowsMediaEncoder::setMetaData(const QMediaMetaData &metaData)
-{
- m_metaData = metaData;
-}
-
-QMediaMetaData QWindowsMediaEncoder::metaData() const
-{
- return m_metaData;
-}
-
-void QWindowsMediaEncoder::saveMetadata()
-{
- if (!m_metaData.isEmpty()) {
-
- const QString nativeFileName = QDir::toNativeSeparators(m_fileName);
-
- IPropertyStore *store = nullptr;
-
- if (SUCCEEDED(SHGetPropertyStoreFromParsingName(reinterpret_cast<LPCWSTR>(nativeFileName.utf16()),
- nullptr, GPS_READWRITE, IID_PPV_ARGS(&store)))) {
-
- MFMetaData::toNative(m_metaData, store);
-
- store->Commit();
- store->Release();
- }
- }
-}
-
-void QWindowsMediaEncoder::onDurationChanged(qint64 duration)
-{
- m_duration = duration;
- durationChanged(m_duration);
-}
-
-void QWindowsMediaEncoder::onStreamingError(int errorCode)
-{
- if (errorCode == MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED)
- error(QMediaRecorder::ResourceError, tr("Camera is no longer present"));
- else if (errorCode == MF_E_AUDIO_RECORDING_DEVICE_INVALIDATED)
- error(QMediaRecorder::ResourceError, tr("Audio input is no longer present"));
- else
- error(QMediaRecorder::ResourceError, tr("Streaming error"));
-
- if (m_state != QMediaRecorder::StoppedState) {
- m_mediaDeviceSession->stopRecording();
- }
-}
-
-void QWindowsMediaEncoder::onRecordingError(int errorCode)
-{
- error(QMediaRecorder::ResourceError, tr("Recording error"));
-
- auto lastState = m_state;
- m_state = QMediaRecorder::StoppedState;
- if (m_state != lastState)
- stateChanged(m_state);
-}
-
-void QWindowsMediaEncoder::onCameraChanged()
-{
-}
-
-void QWindowsMediaEncoder::onRecordingStarted()
-{
-}
-
-void QWindowsMediaEncoder::onRecordingStopped()
-{
- saveMetadata();
-
- auto lastState = m_state;
- m_state = QMediaRecorder::StoppedState;
- if (m_state != lastState)
- stateChanged(m_state);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder_p.h b/src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder_p.h
deleted file mode 100644
index c7b9d8931..000000000
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediaencoder_p.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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.
-//
-
-#ifndef QWINDOWSMEDIAENCODER_H
-#define QWINDOWSMEDIAENCODER_H
-
-#include <private/qplatformmediaencoder_p.h>
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qurl.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsMediaDeviceSession;
-class QPlatformMediaCaptureSession;
-class QWindowsMediaCaptureService;
-
-class QWindowsMediaEncoder : public QObject, public QPlatformMediaEncoder
-{
- Q_OBJECT
-public:
- explicit QWindowsMediaEncoder(QMediaRecorder *parent);
-
- bool isLocationWritable(const QUrl &location) const override;
- QMediaRecorder::RecorderState state() const override;
- qint64 duration() const override;
-
- void setMetaData(const QMediaMetaData &metaData) override;
- QMediaMetaData metaData() const override;
-
- void setCaptureSession(QPlatformMediaCaptureSession *session);
-
- void record(QMediaEncoderSettings &settings) override;
- void pause() override;
- void resume() override;
- void stop() override;
-
-private Q_SLOTS:
- void onCameraChanged();
- void onRecordingStarted();
- void onRecordingStopped();
- void onDurationChanged(qint64 duration);
- void onStreamingError(int errorCode);
- void onRecordingError(int errorCode);
-
-private:
- void saveMetadata();
-
- QWindowsMediaCaptureService *m_captureService = nullptr;
- QWindowsMediaDeviceSession *m_mediaDeviceSession = nullptr;
- QMediaRecorder::RecorderState m_state = QMediaRecorder::StoppedState;
- QString m_fileName;
- QMediaMetaData m_metaData;
- qint64 m_duration = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/windows/mfstream.cpp b/src/multimedia/platform/windows/mfstream.cpp
deleted file mode 100644
index b01dbb7b1..000000000
--- a/src/multimedia/platform/windows/mfstream.cpp
+++ /dev/null
@@ -1,361 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mfstream_p.h"
-#include <QtCore/qcoreapplication.h>
-
-//MFStream is added for supporting QIODevice type of media source.
-//It is used to delegate invocations from media foundation(through IMFByteStream) to QIODevice.
-
-MFStream::MFStream(QIODevice *stream, bool ownStream)
- : m_cRef(1)
- , m_stream(stream)
- , m_ownStream(ownStream)
- , m_currentReadResult(0)
-{
- //Move to the thread of the stream object
- //to make sure invocations on stream
- //are happened in the same thread of stream object
- this->moveToThread(stream->thread());
- connect(stream, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
-}
-
-MFStream::~MFStream()
-{
- if (m_currentReadResult)
- m_currentReadResult->Release();
- if (m_ownStream)
- m_stream->deleteLater();
-}
-
-//from IUnknown
-STDMETHODIMP MFStream::QueryInterface(REFIID riid, LPVOID *ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFByteStream) {
- *ppvObject = static_cast<IMFByteStream*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) MFStream::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) MFStream::Release(void)
-{
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0) {
- this->deleteLater();
- }
- return cRef;
-}
-
-
-//from IMFByteStream
-STDMETHODIMP MFStream::GetCapabilities(DWORD *pdwCapabilities)
-{
- if (!pdwCapabilities)
- return E_INVALIDARG;
- *pdwCapabilities = MFBYTESTREAM_IS_READABLE;
- if (!m_stream->isSequential())
- *pdwCapabilities |= MFBYTESTREAM_IS_SEEKABLE;
- return S_OK;
-}
-
-STDMETHODIMP MFStream::GetLength(QWORD *pqwLength)
-{
- if (!pqwLength)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- *pqwLength = QWORD(m_stream->size());
- return S_OK;
-}
-
-STDMETHODIMP MFStream::SetLength(QWORD)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFStream::GetCurrentPosition(QWORD *pqwPosition)
-{
- if (!pqwPosition)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- *pqwPosition = m_stream->pos();
- return S_OK;
-}
-
-STDMETHODIMP MFStream::SetCurrentPosition(QWORD qwPosition)
-{
- QMutexLocker locker(&m_mutex);
- //SetCurrentPosition may happend during the BeginRead/EndRead pair,
- //refusing to execute SetCurrentPosition during that time seems to be
- //the simplest workable solution
- if (m_currentReadResult)
- return S_FALSE;
-
- bool seekOK = m_stream->seek(qint64(qwPosition));
- if (seekOK)
- return S_OK;
- else
- return S_FALSE;
-}
-
-STDMETHODIMP MFStream::IsEndOfStream(BOOL *pfEndOfStream)
-{
- if (!pfEndOfStream)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- *pfEndOfStream = m_stream->atEnd() ? TRUE : FALSE;
- return S_OK;
-}
-
-STDMETHODIMP MFStream::Read(BYTE *pb, ULONG cb, ULONG *pcbRead)
-{
- QMutexLocker locker(&m_mutex);
- qint64 read = m_stream->read((char*)(pb), qint64(cb));
- if (pcbRead)
- *pcbRead = ULONG(read);
- return S_OK;
-}
-
-STDMETHODIMP MFStream::BeginRead(BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback,
- IUnknown *punkState)
-{
- if (!pCallback || !pb)
- return E_INVALIDARG;
-
- Q_ASSERT(m_currentReadResult == NULL);
-
- AsyncReadState *state = new (std::nothrow) AsyncReadState(pb, cb);
- if (state == NULL)
- return E_OUTOFMEMORY;
-
- HRESULT hr = MFCreateAsyncResult(state, pCallback, punkState, &m_currentReadResult);
- state->Release();
- if (FAILED(hr))
- return hr;
-
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
- return hr;
-}
-
-STDMETHODIMP MFStream::EndRead(IMFAsyncResult* pResult, ULONG *pcbRead)
-{
- if (!pcbRead)
- return E_INVALIDARG;
- IUnknown *pUnk;
- pResult->GetObject(&pUnk);
- AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
- *pcbRead = state->bytesRead();
- pUnk->Release();
-
- m_currentReadResult->Release();
- m_currentReadResult = NULL;
-
- return S_OK;
-}
-
-STDMETHODIMP MFStream::Write(const BYTE *, ULONG, ULONG *)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFStream::BeginWrite(const BYTE *, ULONG ,
- IMFAsyncCallback *,
- IUnknown *)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFStream::EndWrite(IMFAsyncResult *,
- ULONG *)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFStream::Seek(
- MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
- LONGLONG llSeekOffset,
- DWORD,
- QWORD *pqwCurrentPosition)
-{
- QMutexLocker locker(&m_mutex);
- if (m_currentReadResult)
- return S_FALSE;
-
- qint64 pos = qint64(llSeekOffset);
- switch (SeekOrigin) {
- case msoBegin:
- break;
- case msoCurrent:
- pos += m_stream->pos();
- break;
- }
- bool seekOK = m_stream->seek(pos);
- if (pqwCurrentPosition)
- *pqwCurrentPosition = pos;
- if (seekOK)
- return S_OK;
- else
- return S_FALSE;
-}
-
-STDMETHODIMP MFStream::Flush()
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFStream::Close()
-{
- QMutexLocker locker(&m_mutex);
- if (m_ownStream)
- m_stream->close();
- return S_OK;
-}
-
-void MFStream::doRead()
-{
- bool readDone = true;
- IUnknown *pUnk = NULL;
- HRESULT hr = m_currentReadResult->GetObject(&pUnk);
- if (SUCCEEDED(hr)) {
- //do actual read
- AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
- ULONG cbRead;
- Read(state->pb(), state->cb() - state->bytesRead(), &cbRead);
- pUnk->Release();
-
- state->setBytesRead(cbRead + state->bytesRead());
- if (state->cb() > state->bytesRead() && !m_stream->atEnd()) {
- readDone = false;
- }
- }
-
- if (readDone) {
- //now inform the original caller
- m_currentReadResult->SetStatus(hr);
- MFInvokeCallback(m_currentReadResult);
- }
-}
-
-
-void MFStream::handleReadyRead()
-{
- doRead();
-}
-
-void MFStream::customEvent(QEvent *event)
-{
- if (event->type() != QEvent::User) {
- QObject::customEvent(event);
- return;
- }
- doRead();
-}
-
-//AsyncReadState is a helper class used in BeginRead for asynchronous operation
-//to record some BeginRead parameters, so these parameters could be
-//used later when actually executing the read operation in another thread.
-MFStream::AsyncReadState::AsyncReadState(BYTE *pb, ULONG cb)
- : m_cRef(1)
- , m_pb(pb)
- , m_cb(cb)
- , m_cbRead(0)
-{
-}
-
-//from IUnknown
-STDMETHODIMP MFStream::AsyncReadState::QueryInterface(REFIID riid, LPVOID *ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
-
- if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) MFStream::AsyncReadState::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) MFStream::AsyncReadState::Release(void)
-{
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return cRef;
-}
-
-BYTE* MFStream::AsyncReadState::pb() const
-{
- return m_pb;
-}
-
-ULONG MFStream::AsyncReadState::cb() const
-{
- return m_cb;
-}
-
-ULONG MFStream::AsyncReadState::bytesRead() const
-{
- return m_cbRead;
-}
-
-void MFStream::AsyncReadState::setBytesRead(ULONG cbRead)
-{
- m_cbRead = cbRead;
-}
diff --git a/src/multimedia/platform/windows/mfstream_p.h b/src/multimedia/platform/windows/mfstream_p.h
deleted file mode 100644
index 975d02c9d..000000000
--- a/src/multimedia/platform/windows/mfstream_p.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFSTREAM_H
-#define MFSTREAM_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 <mfapi.h>
-#include <mfidl.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qcoreevent.h>
-
-QT_USE_NAMESPACE
-
-class MFStream : public QObject, public IMFByteStream
-{
- Q_OBJECT
-public:
- MFStream(QIODevice *stream, bool ownStream);
-
- ~MFStream();
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
-
- STDMETHODIMP_(ULONG) AddRef(void);
-
- STDMETHODIMP_(ULONG) Release(void);
-
-
- //from IMFByteStream
- STDMETHODIMP GetCapabilities(DWORD *pdwCapabilities);
-
- STDMETHODIMP GetLength(QWORD *pqwLength);
-
- STDMETHODIMP SetLength(QWORD);
-
- STDMETHODIMP GetCurrentPosition(QWORD *pqwPosition);
-
- STDMETHODIMP SetCurrentPosition(QWORD qwPosition);
-
- STDMETHODIMP IsEndOfStream(BOOL *pfEndOfStream);
-
- STDMETHODIMP Read(BYTE *pb, ULONG cb, ULONG *pcbRead);
-
- STDMETHODIMP BeginRead(BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback,
- IUnknown *punkState);
-
- STDMETHODIMP EndRead(IMFAsyncResult* pResult, ULONG *pcbRead);
-
- STDMETHODIMP Write(const BYTE *, ULONG, ULONG *);
-
- STDMETHODIMP BeginWrite(const BYTE *, ULONG ,
- IMFAsyncCallback *,
- IUnknown *);
-
- STDMETHODIMP EndWrite(IMFAsyncResult *,
- ULONG *);
-
- STDMETHODIMP Seek(
- MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
- LONGLONG llSeekOffset,
- DWORD,
- QWORD *pqwCurrentPosition);
-
- STDMETHODIMP Flush();
-
- STDMETHODIMP Close();
-
-private:
- class AsyncReadState : public IUnknown
- {
- public:
- AsyncReadState(BYTE *pb, ULONG cb);
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
-
- STDMETHODIMP_(ULONG) AddRef(void);
-
- STDMETHODIMP_(ULONG) Release(void);
-
- BYTE* pb() const;
- ULONG cb() const;
- ULONG bytesRead() const;
-
- void setBytesRead(ULONG cbRead);
-
- private:
- long m_cRef;
- BYTE *m_pb;
- ULONG m_cb;
- ULONG m_cbRead;
- };
-
- long m_cRef;
- QIODevice *m_stream;
- bool m_ownStream;
- DWORD m_workQueueId;
- QMutex m_mutex;
-
- void doRead();
-
-private Q_SLOTS:
- void handleReadyRead();
-
-protected:
- void customEvent(QEvent *event);
- IMFAsyncResult *m_currentReadResult;
-};
-
-#endif
diff --git a/src/multimedia/platform/windows/player/mfactivate.cpp b/src/multimedia/platform/windows/player/mfactivate.cpp
deleted file mode 100644
index 05d9321be..000000000
--- a/src/multimedia/platform/windows/player/mfactivate.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mfactivate_p.h"
-
-#include <mfapi.h>
-
-MFAbstractActivate::MFAbstractActivate()
- : m_attributes(0)
- , m_cRef(1)
-{
- MFCreateAttributes(&m_attributes, 0);
-}
-
-MFAbstractActivate::~MFAbstractActivate()
-{
- if (m_attributes)
- m_attributes->Release();
-}
-
-
-HRESULT MFAbstractActivate::QueryInterface(REFIID riid, LPVOID *ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFActivate) {
- *ppvObject = static_cast<IMFActivate*>(this);
- } else if (riid == IID_IMFAttributes) {
- *ppvObject = static_cast<IMFAttributes*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(static_cast<IMFActivate*>(this));
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-ULONG MFAbstractActivate::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-ULONG MFAbstractActivate::Release(void)
-{
- ULONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- return cRef;
-}
diff --git a/src/multimedia/platform/windows/player/mfactivate_p.h b/src/multimedia/platform/windows/player/mfactivate_p.h
deleted file mode 100644
index 86ef1c438..000000000
--- a/src/multimedia/platform/windows/player/mfactivate_p.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFACTIVATE_H
-#define MFACTIVATE_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 <mfidl.h>
-
-class MFAbstractActivate : public IMFActivate
-{
-public:
- explicit MFAbstractActivate();
- virtual ~MFAbstractActivate();
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
- STDMETHODIMP_(ULONG) AddRef(void);
- STDMETHODIMP_(ULONG) Release(void);
-
- //from IMFAttributes
- STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT *pValue)
- {
- return m_attributes->GetItem(guidKey, pValue);
- }
-
- STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE *pType)
- {
- return m_attributes->GetItemType(guidKey, pType);
- }
-
- STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL *pbResult)
- {
- return m_attributes->CompareItem(guidKey, Value, pbResult);
- }
-
- STDMETHODIMP Compare(IMFAttributes *pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, BOOL *pbResult)
- {
- return m_attributes->Compare(pTheirs, MatchType, pbResult);
- }
-
- STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32 *punValue)
- {
- return m_attributes->GetUINT32(guidKey, punValue);
- }
-
- STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64 *punValue)
- {
- return m_attributes->GetUINT64(guidKey, punValue);
- }
-
- STDMETHODIMP GetDouble(REFGUID guidKey, double *pfValue)
- {
- return m_attributes->GetDouble(guidKey, pfValue);
- }
-
- STDMETHODIMP GetGUID(REFGUID guidKey, GUID *pguidValue)
- {
- return m_attributes->GetGUID(guidKey, pguidValue);
- }
-
- STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32 *pcchLength)
- {
- return m_attributes->GetStringLength(guidKey, pcchLength);
- }
-
- STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32 *pcchLength)
- {
- return m_attributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
- }
-
- STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR *ppwszValue, UINT32 *pcchLength)
- {
- return m_attributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
- }
-
- STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32 *pcbBlobSize)
- {
- return m_attributes->GetBlobSize(guidKey, pcbBlobSize);
- }
-
- STDMETHODIMP GetBlob(REFGUID guidKey, UINT8 *pBuf, UINT32 cbBufSize, UINT32 *pcbBlobSize)
- {
- return m_attributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
- }
-
- STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8 **ppBuf, UINT32 *pcbSize)
- {
- return m_attributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
- }
-
- STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID *ppv)
- {
- return m_attributes->GetUnknown(guidKey, riid, ppv);
- }
-
- STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value)
- {
- return m_attributes->SetItem(guidKey, Value);
- }
-
- STDMETHODIMP DeleteItem(REFGUID guidKey)
- {
- return m_attributes->DeleteItem(guidKey);
- }
-
- STDMETHODIMP DeleteAllItems()
- {
- return m_attributes->DeleteAllItems();
- }
-
- STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue)
- {
- return m_attributes->SetUINT32(guidKey, unValue);
- }
-
- STDMETHODIMP SetUINT64(REFGUID guidKey, UINT64 unValue)
- {
- return m_attributes->SetUINT64(guidKey, unValue);
- }
-
- STDMETHODIMP SetDouble(REFGUID guidKey, double fValue)
- {
- return m_attributes->SetDouble(guidKey, fValue);
- }
-
- STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue)
- {
- return m_attributes->SetGUID(guidKey, guidValue);
- }
-
- STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue)
- {
- return m_attributes->SetString(guidKey, wszValue);
- }
-
- STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8 *pBuf, UINT32 cbBufSize)
- {
- return m_attributes->SetBlob(guidKey, pBuf, cbBufSize);
- }
-
- STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown *pUnknown)
- {
- return m_attributes->SetUnknown(guidKey, pUnknown);
- }
-
- STDMETHODIMP LockStore()
- {
- return m_attributes->LockStore();
- }
-
- STDMETHODIMP UnlockStore()
- {
- return m_attributes->UnlockStore();
- }
-
- STDMETHODIMP GetCount(UINT32 *pcItems)
- {
- return m_attributes->GetCount(pcItems);
- }
-
- STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID *pguidKey, PROPVARIANT *pValue)
- {
- return m_attributes->GetItemByIndex(unIndex, pguidKey, pValue);
- }
-
- STDMETHODIMP CopyAllItems(IMFAttributes *pDest)
- {
- return m_attributes->CopyAllItems(pDest);
- }
-
-private:
- IMFAttributes *m_attributes;
- ULONG m_cRef;
-};
-
-#endif // MFACTIVATE_H
diff --git a/src/multimedia/platform/windows/player/mfevrvideowindowcontrol.cpp b/src/multimedia/platform/windows/player/mfevrvideowindowcontrol.cpp
deleted file mode 100644
index 105424253..000000000
--- a/src/multimedia/platform/windows/player/mfevrvideowindowcontrol.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mfevrvideowindowcontrol_p.h"
-
-#include <qdebug.h>
-
-MFEvrVideoWindowControl::MFEvrVideoWindowControl(QVideoSink *parent)
- : EvrVideoWindowControl(parent)
- , m_currentActivate(NULL)
- , m_evrSink(NULL)
-{
-}
-
-MFEvrVideoWindowControl::~MFEvrVideoWindowControl()
-{
- clear();
-}
-
-void MFEvrVideoWindowControl::clear()
-{
- setEvr(NULL);
-
- if (m_evrSink)
- m_evrSink->Release();
- if (m_currentActivate) {
- m_currentActivate->ShutdownObject();
- m_currentActivate->Release();
- }
- m_evrSink = NULL;
- m_currentActivate = NULL;
-}
-
-IMFActivate* MFEvrVideoWindowControl::createActivate()
-{
- clear();
-
- if (FAILED(MFCreateVideoRendererActivate(0, &m_currentActivate))) {
- qWarning() << "Failed to create evr video renderer activate!";
- return NULL;
- }
- if (FAILED(m_currentActivate->ActivateObject(IID_IMFMediaSink, (LPVOID*)(&m_evrSink)))) {
- qWarning() << "Failed to activate evr media sink!";
- return NULL;
- }
- if (!setEvr(m_evrSink))
- return NULL;
-
- return m_currentActivate;
-}
-
-void MFEvrVideoWindowControl::releaseActivate()
-{
- clear();
-}
diff --git a/src/multimedia/platform/windows/player/mfevrvideowindowcontrol_p.h b/src/multimedia/platform/windows/player/mfevrvideowindowcontrol_p.h
deleted file mode 100644
index 2f9d867d6..000000000
--- a/src/multimedia/platform/windows/player/mfevrvideowindowcontrol_p.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFEVRVIDEOWINDOWCONTROL_H
-#define MFEVRVIDEOWINDOWCONTROL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "private/evrvideowindowcontrol_p.h"
-
-QT_USE_NAMESPACE
-
-class MFEvrVideoWindowControl : public EvrVideoWindowControl
-{
-public:
- MFEvrVideoWindowControl(QVideoSink *parent = 0);
- ~MFEvrVideoWindowControl();
-
- IMFActivate* createActivate();
- void releaseActivate();
-
-private:
- void clear();
-
- IMFActivate *m_currentActivate;
- IMFMediaSink *m_evrSink;
-};
-
-#endif // MFEVRVIDEOWINDOWCONTROL_H
diff --git a/src/multimedia/platform/windows/player/mfplayercontrol.cpp b/src/multimedia/platform/windows/player/mfplayercontrol.cpp
deleted file mode 100644
index 47e74ab38..000000000
--- a/src/multimedia/platform/windows/player/mfplayercontrol.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mfplayercontrol_p.h"
-#include "mfplayersession_p.h"
-#include "mfvideorenderercontrol_p.h"
-#include <qdebug.h>
-
-//#define DEBUG_MEDIAFOUNDATION
-
-MFPlayerControl::MFPlayerControl(QMediaPlayer *player)
- : QPlatformMediaPlayer(player)
- , m_state(QMediaPlayer::StoppedState)
- , m_stateDirty(false)
- , m_videoAvailable(false)
- , m_audioAvailable(false)
- , m_duration(0)
- , m_seekable(false)
-{
- m_session = new MFPlayerSession(this);
-}
-
-MFPlayerControl::~MFPlayerControl()
-{
- m_session->close();
- m_session->Release();
-}
-
-void MFPlayerControl::setMedia(const QUrl &media, QIODevice *stream)
-{
- if (m_state != QMediaPlayer::StoppedState) {
- changeState(QMediaPlayer::StoppedState);
- m_session->stop(true);
- refreshState();
- }
-
- m_media = media;
- m_stream = stream;
- resetAudioVideoAvailable();
- handleDurationUpdate(0);
- handleSeekableUpdate(false);
- m_session->load(media, stream);
-}
-
-void MFPlayerControl::play()
-{
- if (m_state == QMediaPlayer::PlayingState)
- return;
- if (QMediaPlayer::InvalidMedia == m_session->status())
- m_session->load(m_media, m_stream);
-
- switch (m_session->status()) {
- case QMediaPlayer::NoMedia:
- case QMediaPlayer::InvalidMedia:
- return;
- case QMediaPlayer::LoadedMedia:
- case QMediaPlayer::BufferingMedia:
- case QMediaPlayer::BufferedMedia:
- case QMediaPlayer::EndOfMedia:
- changeState(QMediaPlayer::PlayingState);
- m_session->start();
- break;
- default: //Loading/Stalled
- changeState(QMediaPlayer::PlayingState);
- break;
- }
- refreshState();
-}
-
-void MFPlayerControl::pause()
-{
- if (m_state != QMediaPlayer::PlayingState)
- return;
- changeState(QMediaPlayer::PausedState);
- m_session->pause();
- refreshState();
-}
-
-void MFPlayerControl::stop()
-{
- if (m_state == QMediaPlayer::StoppedState)
- return;
- changeState(QMediaPlayer::StoppedState);
- m_session->stop();
- refreshState();
-}
-
-QMediaMetaData MFPlayerControl::metaData() const
-{
- return m_session->metaData();
-}
-
-void MFPlayerControl::setAudioOutput(QPlatformAudioOutput *output)
-{
- m_session->setAudioOutput(output);
-}
-
-void MFPlayerControl::setVideoSink(QVideoSink *sink)
-{
- m_session->setVideoSink(sink);
-}
-
-void MFPlayerControl::changeState(QMediaPlayer::PlaybackState state)
-{
- if (m_state == state)
- return;
- m_state = state;
- m_stateDirty = true;
-}
-
-void MFPlayerControl::refreshState()
-{
- if (!m_stateDirty)
- return;
- m_stateDirty = false;
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MFPlayerControl::emit stateChanged" << m_state;
-#endif
- emit stateChanged(m_state);
-}
-
-void MFPlayerControl::handleStatusChanged()
-{
- QMediaPlayer::MediaStatus status = m_session->status();
- switch (status) {
- case QMediaPlayer::EndOfMedia:
- changeState(QMediaPlayer::StoppedState);
- break;
- case QMediaPlayer::InvalidMedia:
- break;
- case QMediaPlayer::LoadedMedia:
- case QMediaPlayer::BufferingMedia:
- case QMediaPlayer::BufferedMedia:
- if (m_state == QMediaPlayer::PlayingState)
- m_session->start();
- break;
- }
- emit mediaStatusChanged(m_session->status());
- refreshState();
-}
-
-void MFPlayerControl::handleTracksChanged()
-{
- tracksChanged();
-}
-
-void MFPlayerControl::handleVideoAvailable()
-{
- if (m_videoAvailable)
- return;
- m_videoAvailable = true;
- emit videoAvailableChanged(m_videoAvailable);
-}
-
-void MFPlayerControl::handleAudioAvailable()
-{
- if (m_audioAvailable)
- return;
- m_audioAvailable = true;
- emit audioAvailableChanged(m_audioAvailable);
-}
-
-void MFPlayerControl::resetAudioVideoAvailable()
-{
- bool videoDirty = false;
- if (m_videoAvailable) {
- m_videoAvailable = false;
- videoDirty = true;
- }
- if (m_audioAvailable) {
- m_audioAvailable = false;
- emit audioAvailableChanged(m_audioAvailable);
- }
- if (videoDirty)
- emit videoAvailableChanged(m_videoAvailable);
-}
-
-void MFPlayerControl::handleDurationUpdate(qint64 duration)
-{
- if (m_duration == duration)
- return;
- m_duration = duration;
- emit durationChanged(m_duration);
-}
-
-void MFPlayerControl::handleSeekableUpdate(bool seekable)
-{
- if (m_seekable == seekable)
- return;
- m_seekable = seekable;
- emit seekableChanged(m_seekable);
-}
-
-QMediaPlayer::PlaybackState MFPlayerControl::state() const
-{
- return m_state;
-}
-
-QMediaPlayer::MediaStatus MFPlayerControl::mediaStatus() const
-{
- return m_session->status();
-}
-
-qint64 MFPlayerControl::duration() const
-{
- return m_duration;
-}
-
-qint64 MFPlayerControl::position() const
-{
- return m_session->position();
-}
-
-void MFPlayerControl::setPosition(qint64 position)
-{
- if (!m_seekable || position == m_session->position())
- return;
- m_session->setPosition(position);
-}
-
-float MFPlayerControl::bufferProgress() const
-{
- return m_session->bufferProgress() / 100.;
-}
-
-bool MFPlayerControl::isAudioAvailable() const
-{
- return m_audioAvailable;
-}
-
-bool MFPlayerControl::isVideoAvailable() const
-{
- return m_videoAvailable;
-}
-
-bool MFPlayerControl::isSeekable() const
-{
- return m_seekable;
-}
-
-QMediaTimeRange MFPlayerControl::availablePlaybackRanges() const
-{
- return m_session->availablePlaybackRanges();
-}
-
-qreal MFPlayerControl::playbackRate() const
-{
- return m_session->playbackRate();
-}
-
-void MFPlayerControl::setPlaybackRate(qreal rate)
-{
- m_session->setPlaybackRate(rate);
-}
-
-QUrl MFPlayerControl::media() const
-{
- return m_media;
-}
-
-const QIODevice* MFPlayerControl::mediaStream() const
-{
- return m_stream;
-}
-
-void MFPlayerControl::handleError(QMediaPlayer::Error errorCode, const QString& errorString, bool isFatal)
-{
- if (isFatal)
- stop();
- emit error(int(errorCode), errorString);
-}
-
-void MFPlayerControl::setActiveTrack(TrackType type, int index)
-{
- m_session->setActiveTrack(type, index);
-}
-
-int MFPlayerControl::activeTrack(TrackType type)
-{
- return m_session->activeTrack(type);
-}
-
-int MFPlayerControl::trackCount(TrackType type)
-{
- return m_session->trackCount(type);
-}
-
-QMediaMetaData MFPlayerControl::trackMetaData(TrackType type, int trackNumber)
-{
- return m_session->trackMetaData(type, trackNumber);
-}
-
diff --git a/src/multimedia/platform/windows/player/mfplayercontrol_p.h b/src/multimedia/platform/windows/player/mfplayercontrol_p.h
deleted file mode 100644
index e8467ab8d..000000000
--- a/src/multimedia/platform/windows/player/mfplayercontrol_p.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFPLAYERCONTROL_H
-#define MFPLAYERCONTROL_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 "QUrl.h"
-#include "qplatformmediaplayer_p.h"
-
-#include <QtCore/qcoreevent.h>
-
-QT_USE_NAMESPACE
-
-class MFPlayerSession;
-
-class MFPlayerControl : public QPlatformMediaPlayer
-{
-public:
- MFPlayerControl(QMediaPlayer *player);
- ~MFPlayerControl();
-
- QMediaPlayer::PlaybackState state() const override;
-
- QMediaPlayer::MediaStatus mediaStatus() const override;
-
- qint64 duration() const override;
-
- qint64 position() const override;
- void setPosition(qint64 position) override;
-
- float bufferProgress() const override;
-
- bool isAudioAvailable() const override;
- bool isVideoAvailable() const override;
-
- bool isSeekable() const override;
-
- QMediaTimeRange availablePlaybackRanges() const override;
-
- qreal playbackRate() const override;
- void setPlaybackRate(qreal rate) override;
-
- QUrl media() const override;
- const QIODevice *mediaStream() const override;
- void setMedia(const QUrl &media, QIODevice *stream) override;
-
- void play() override;
- void pause() override;
- void stop() override;
-
- bool streamPlaybackSupported() const override { return true; }
-
- QMediaMetaData metaData() const override;
-
- void setAudioOutput(QPlatformAudioOutput *output) override;
-
- void setVideoSink(QVideoSink *sink) override;
-
- void setActiveTrack(TrackType type, int index) override;
- int activeTrack(TrackType type) override;
- int trackCount(TrackType type) override;
- QMediaMetaData trackMetaData(TrackType type, int trackNumber) override;
-
- void handleStatusChanged();
- void handleTracksChanged();
- void handleVideoAvailable();
- void handleAudioAvailable();
- void handleDurationUpdate(qint64 duration);
- void handleSeekableUpdate(bool seekable);
- void handleError(QMediaPlayer::Error errorCode, const QString& errorString, bool isFatal);
-
-private:
- void changeState(QMediaPlayer::PlaybackState state);
- void resetAudioVideoAvailable();
- void refreshState();
-
- QMediaPlayer::PlaybackState m_state;
- bool m_stateDirty;
- QMediaPlayer::MediaStatus m_status;
- QMediaPlayer::Error m_error;
-
- bool m_videoAvailable;
- bool m_audioAvailable;
- qint64 m_duration;
- bool m_seekable;
-
- QIODevice *m_stream;
- QUrl m_media;
- MFPlayerSession *m_session;
-};
-
-#endif
diff --git a/src/multimedia/platform/windows/player/mfplayersession.cpp b/src/multimedia/platform/windows/player/mfplayersession.cpp
deleted file mode 100644
index aeeb7c792..000000000
--- a/src/multimedia/platform/windows/player/mfplayersession.cpp
+++ /dev/null
@@ -1,2009 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qplatformmediaplayer_p.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qthread.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qbuffer.h>
-
-#include "qplatformaudiooutput_p.h"
-#include "qaudiooutput.h"
-
-#include "mfplayercontrol_p.h"
-#include "mfevrvideowindowcontrol_p.h"
-#include "mfvideorenderercontrol_p.h"
-#include <private/mfmetadata_p.h>
-
-#include "mfplayersession_p.h"
-#include <mferror.h>
-#include <nserror.h>
-#include "private/sourceresolver_p.h"
-#include "samplegrabber_p.h"
-#include "mftvideo_p.h"
-#include <wmcodecdsp.h>
-
-#include <mmdeviceapi.h>
-#include <propvarutil.h>
-#include <Functiondiscoverykeys_devpkey.h>
-
-//#define DEBUG_MEDIAFOUNDATION
-
-MFPlayerSession::MFPlayerSession(MFPlayerControl *playerControl)
- : m_cRef(1)
- , m_playerControl(playerControl)
- , m_session(0)
- , m_presentationClock(0)
- , m_rateControl(0)
- , m_rateSupport(0)
- , m_volumeControl(0)
- , m_netsourceStatistics(0)
- , m_scrubbing(false)
- , m_restoreRate(1)
- , m_sourceResolver(0)
- , m_hCloseEvent(0)
- , m_closing(false)
- , m_mediaTypes(0)
- , m_pendingRate(1)
- , m_status(QMediaPlayer::NoMedia)
- , m_audioSampleGrabber(0)
- , m_audioSampleGrabberNode(0)
- , m_videoProbeMFT(0)
-
-{
- QObject::connect(this, SIGNAL(sessionEvent(IMFMediaEvent*)), this, SLOT(handleSessionEvent(IMFMediaEvent*)));
-
- m_signalPositionChangeTimer.setInterval(100);
- m_signalPositionChangeTimer.callOnTimeout([this](){
- positionChanged(position());
- });
-
- m_pendingState = NoPending;
- ZeroMemory(&m_state, sizeof(m_state));
- m_state.command = CmdStop;
- m_state.prevCmd = CmdNone;
- m_state.rate = 1.0f;
- ZeroMemory(&m_request, sizeof(m_request));
- m_request.command = CmdNone;
- m_request.prevCmd = CmdNone;
- m_request.rate = 1.0f;
-
- m_audioSampleGrabber = new AudioSampleGrabberCallback;
- m_videoRendererControl = new MFVideoRendererControl;
-}
-
-void MFPlayerSession::close()
-{
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "close";
-#endif
-
- clear();
- if (!m_session)
- return;
-
- HRESULT hr = S_OK;
- if (m_session) {
- m_closing = true;
- hr = m_session->Close();
- if (SUCCEEDED(hr)) {
- DWORD dwWaitResult = WaitForSingleObject(m_hCloseEvent, 100);
- if (dwWaitResult == WAIT_TIMEOUT) {
- qWarning() << "session close time out!";
- }
- }
- m_closing = false;
- }
-
- if (SUCCEEDED(hr)) {
- if (m_session)
- m_session->Shutdown();
- if (m_sourceResolver)
- m_sourceResolver->shutdown();
- }
- if (m_sourceResolver) {
- m_sourceResolver->Release();
- m_sourceResolver = 0;
- }
- if (m_videoProbeMFT) {
- m_videoProbeMFT->Release();
- m_videoProbeMFT = 0;
- }
-
- m_videoRendererControl->releaseActivate();
-// } else if (m_playerService->videoWindowControl()) {
-// m_playerService->videoWindowControl()->releaseActivate();
-// }
-
- if (m_session)
- m_session->Release();
- m_session = 0;
- if (m_hCloseEvent)
- CloseHandle(m_hCloseEvent);
- m_hCloseEvent = 0;
-}
-
-MFPlayerSession::~MFPlayerSession()
-{
- m_audioSampleGrabber->Release();
-}
-
-
-void MFPlayerSession::load(const QUrl &url, QIODevice *stream)
-{
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "load";
-#endif
- clear();
-
- if (m_status == QMediaPlayer::LoadingMedia && m_sourceResolver)
- m_sourceResolver->cancel();
-
- if (url.isEmpty() && !stream) {
- close();
- changeStatus(QMediaPlayer::NoMedia);
- } else if (stream && (!stream->isReadable())) {
- close();
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Invalid stream source."), true);
- } else {
- createSession();
- changeStatus(QMediaPlayer::LoadingMedia);
- m_sourceResolver->load(url, stream);
- }
- emit positionChanged(position());
-}
-
-void MFPlayerSession::handleSourceError(long hr)
-{
- QString errorString;
- QMediaPlayer::Error errorCode = QMediaPlayer::ResourceError;
- switch (hr) {
- case QMediaPlayer::FormatError:
- errorCode = QMediaPlayer::FormatError;
- errorString = tr("Attempting to play invalid Qt resource.");
- break;
- case NS_E_FILE_NOT_FOUND:
- errorString = tr("The system cannot find the file specified.");
- break;
- case NS_E_SERVER_NOT_FOUND:
- errorString = tr("The specified server could not be found.");
- break;
- case MF_E_UNSUPPORTED_BYTESTREAM_TYPE:
- errorCode = QMediaPlayer::FormatError;
- errorString = tr("Unsupported media type.");
- break;
- default:
- errorString = tr("Failed to load source.");
- break;
- }
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(errorCode, errorString, true);
-}
-
-void MFPlayerSession::handleMediaSourceReady()
-{
- if (QMediaPlayer::LoadingMedia != m_status || !m_sourceResolver || m_sourceResolver != sender())
- return;
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "handleMediaSourceReady";
-#endif
- HRESULT hr = S_OK;
- IMFMediaSource* mediaSource = m_sourceResolver->mediaSource();
-
- DWORD dwCharacteristics = 0;
- mediaSource->GetCharacteristics(&dwCharacteristics);
- emit seekableUpdate(MFMEDIASOURCE_CAN_SEEK & dwCharacteristics);
-
- IMFPresentationDescriptor* sourcePD;
- hr = mediaSource->CreatePresentationDescriptor(&sourcePD);
- if (SUCCEEDED(hr)) {
- m_duration = 0;
- m_metaData = MFMetaData::fromNative(mediaSource);
- emit metaDataChanged();
- sourcePD->GetUINT64(MF_PD_DURATION, &m_duration);
- //convert from 100 nanosecond to milisecond
- emit durationUpdate(qint64(m_duration / 10000));
- setupPlaybackTopology(mediaSource, sourcePD);
- tracksChanged();
- sourcePD->Release();
- } else {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Cannot create presentation descriptor."), true);
- }
-}
-
-bool MFPlayerSession::getStreamInfo(IMFStreamDescriptor *stream,
- MFPlayerSession::MediaType *type,
- QString *name,
- QString *language) const
-{
- if (!stream || !type || !name || !language)
- return false;
-
- *type = Unknown;
- *name = QString();
- *language = QString();
-
- IMFMediaTypeHandler *typeHandler = nullptr;
-
- if (SUCCEEDED(stream->GetMediaTypeHandler(&typeHandler))) {
-
- UINT32 len = 0;
- if (SUCCEEDED(stream->GetStringLength(MF_SD_STREAM_NAME, &len)) && len > 0) {
- WCHAR *wstr = new WCHAR[len+1];
- if (SUCCEEDED(stream->GetString(MF_SD_STREAM_NAME, wstr, len+1, &len))) {
- *name = QString::fromUtf16(reinterpret_cast<const char16_t *>(wstr));
- }
- delete []wstr;
- }
- if (SUCCEEDED(stream->GetStringLength(MF_SD_LANGUAGE, &len)) && len > 0) {
- WCHAR *wstr = new WCHAR[len+1];
- if (SUCCEEDED(stream->GetString(MF_SD_LANGUAGE, wstr, len+1, &len))) {
- *language = QString::fromUtf16(reinterpret_cast<const char16_t *>(wstr));
- }
- delete []wstr;
- }
-
- GUID guidMajorType;
- if (SUCCEEDED(typeHandler->GetMajorType(&guidMajorType))) {
- if (guidMajorType == MFMediaType_Audio)
- *type = Audio;
- else if (guidMajorType == MFMediaType_Video)
- *type = Video;
- }
- typeHandler->Release();
- }
-
- return *type != Unknown;
-}
-
-void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD)
-{
- HRESULT hr = S_OK;
- // Get the number of streams in the media source.
- DWORD cSourceStreams = 0;
- hr = sourcePD->GetStreamDescriptorCount(&cSourceStreams);
- if (FAILED(hr)) {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Failed to get stream count."), true);
- return;
- }
-
- IMFTopology *topology;
- hr = MFCreateTopology(&topology);
- if (FAILED(hr)) {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Failed to create topology."), true);
- return;
- }
-
- // For each stream, create the topology nodes and add them to the topology.
- DWORD succeededCount = 0;
- for (DWORD i = 0; i < cSourceStreams; i++) {
- BOOL selected = FALSE;
- bool streamAdded = false;
- IMFStreamDescriptor *streamDesc = NULL;
-
- HRESULT hr = sourcePD->GetStreamDescriptorByIndex(i, &selected, &streamDesc);
- if (SUCCEEDED(hr)) {
- // The media might have multiple audio and video streams,
- // only use one of each kind, and only if it is selected by default.
- MediaType mediaType = Unknown;
- QString streamName;
- QString streamLanguage;
-
- if (getStreamInfo(streamDesc, &mediaType, &streamName, &streamLanguage)) {
-
- QPlatformMediaPlayer::TrackType trackType = (mediaType == Audio) ?
- QPlatformMediaPlayer::AudioStream : QPlatformMediaPlayer::VideoStream;
-
- QLocale::Language lang = streamLanguage.isEmpty() ?
- QLocale::Language::AnyLanguage : QLocale(streamLanguage).language();
-
- QMediaMetaData metaData;
- metaData.insert(QMediaMetaData::Title, streamName);
- metaData.insert(QMediaMetaData::Language, lang);
-
- m_trackInfo[trackType].metaData.append(metaData);
- m_trackInfo[trackType].nativeIndexes.append(i);
-
- if (((m_mediaTypes & mediaType) == 0) && selected) { // Check if this type isn't already added
- IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc);
- if (sourceNode) {
- IMFTopologyNode *outputNode = addOutputNode(mediaType, topology, 0);
- if (outputNode) {
- bool connected = false;
- if (mediaType == Audio) {
- if (!m_audioSampleGrabberNode)
- connected = setupAudioSampleGrabber(topology, sourceNode, outputNode);
- }
- sourceNode->GetTopoNodeID(&m_trackInfo[trackType].sourceNodeId);
- outputNode->GetTopoNodeID(&m_trackInfo[trackType].outputNodeId);
-
- if (!connected)
- hr = sourceNode->ConnectOutput(0, outputNode, 0);
-
- if (FAILED(hr)) {
- emit error(QMediaPlayer::FormatError, tr("Unable to play any stream."), false);
- } else {
- m_trackInfo[trackType].currentIndex = m_trackInfo[trackType].nativeIndexes.count() - 1;
- streamAdded = true;
- succeededCount++;
- m_mediaTypes |= mediaType;
- switch (mediaType) {
- case Audio:
- emit audioAvailable();
- break;
- case Video:
- emit videoAvailable();
- break;
- }
- }
- outputNode->Release();
- }
- sourceNode->Release();
- }
- }
- }
-
- if (selected && !streamAdded)
- sourcePD->DeselectStream(i);
-
- streamDesc->Release();
- }
- }
-
- if (succeededCount == 0) {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Unable to play."), true);
- } else {
- if (m_trackInfo[QPlatformMediaPlayer::VideoStream].outputNodeId != -1)
- topology = insertMFT(topology, m_trackInfo[QPlatformMediaPlayer::VideoStream].outputNodeId);
-
- hr = m_session->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
- if (SUCCEEDED(hr)) {
- m_updatingTopology = true;
- } else {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Failed to set topology."), true);
- }
- }
- topology->Release();
-}
-
-IMFTopologyNode* MFPlayerSession::addSourceNode(IMFTopology* topology, IMFMediaSource* source,
- IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc)
-{
- IMFTopologyNode *node = NULL;
- HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node);
- if (SUCCEEDED(hr)) {
- hr = node->SetUnknown(MF_TOPONODE_SOURCE, source);
- if (SUCCEEDED(hr)) {
- hr = node->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, presentationDesc);
- if (SUCCEEDED(hr)) {
- hr = node->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, streamDesc);
- if (SUCCEEDED(hr)) {
- hr = topology->AddNode(node);
- if (SUCCEEDED(hr))
- return node;
- }
- }
- }
- node->Release();
- }
- return NULL;
-}
-
-IMFTopologyNode* MFPlayerSession::addOutputNode(MediaType mediaType, IMFTopology* topology, DWORD sinkID)
-{
- IMFTopologyNode *node = NULL;
- if (FAILED(MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node)))
- return NULL;
-
- IMFActivate *activate = NULL;
- if (mediaType == Audio) {
- if (m_audioOutput) {
- HRESULT hr = MFCreateAudioRendererActivate(&activate);
- if (FAILED(hr)) {
- qWarning() << "Failed to create audio renderer activate";
- node->Release();
- return NULL;
- }
-
- auto id = m_audioOutput->device.id();
- if (!id.isEmpty()) {
- QString s = QString::fromUtf8(id);
- hr = activate->SetString(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, (LPCWSTR)s.utf16());
- } else {
- //This is the default one that has been inserted in updateEndpoints(),
- //so give the activate a hint that we want to use the device for multimedia playback
- //then the media foundation will choose an appropriate one.
-
- //from MSDN:
- //The ERole enumeration defines constants that indicate the role that the system has assigned to an audio endpoint device.
- //eMultimedia: Music, movies, narration, and live music recording.
- hr = activate->SetUINT32(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, eMultimedia);
- }
-
- if (FAILED(hr)) {
- qWarning() << "Failed to set attribute for audio device" << m_audioOutput->device.description();
- activate->Release();
- node->Release();
- return NULL;
- }
- }
- } else if (mediaType == Video) {
- activate = m_videoRendererControl->createActivate();
- } else {
- // Unknown stream type.
- emit error(QMediaPlayer::FormatError, tr("Unknown stream type."), false);
- }
-
- if (!activate
- || FAILED(node->SetObject(activate))
- || FAILED(node->SetUINT32(MF_TOPONODE_STREAMID, sinkID))
- || FAILED(node->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE))
- || FAILED(topology->AddNode(node))) {
- node->Release();
- node = NULL;
- }
-
- if (activate && mediaType == Audio)
- activate->Release();
-
- return node;
-}
-
-bool MFPlayerSession::addAudioSampleGrabberNode(IMFTopology *topology)
-{
- HRESULT hr = S_OK;
- IMFMediaType *pType = 0;
- IMFActivate *sinkActivate = 0;
- do {
- hr = MFCreateMediaType(&pType);
- if (FAILED(hr))
- break;
-
- hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
- if (FAILED(hr))
- break;
-
- hr = pType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
- if (FAILED(hr))
- break;
-
- hr = MFCreateSampleGrabberSinkActivate(pType, m_audioSampleGrabber, &sinkActivate);
- if (FAILED(hr))
- break;
-
- // Note: Data is distorted if this attribute is enabled
- hr = sinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, FALSE);
- if (FAILED(hr))
- break;
-
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &m_audioSampleGrabberNode);
- if (FAILED(hr))
- break;
-
- hr = m_audioSampleGrabberNode->SetObject(sinkActivate);
- if (FAILED(hr))
- break;
-
- hr = m_audioSampleGrabberNode->SetUINT32(MF_TOPONODE_STREAMID, 0); // Identifier of the stream sink.
- if (FAILED(hr))
- break;
-
- hr = m_audioSampleGrabberNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
- if (FAILED(hr))
- break;
-
- hr = topology->AddNode(m_audioSampleGrabberNode);
- if (FAILED(hr))
- break;
-
- pType->Release();
- sinkActivate->Release();
- return true;
- } while (false);
-
- if (pType)
- pType->Release();
- if (sinkActivate)
- sinkActivate->Release();
- if (m_audioSampleGrabberNode) {
- m_audioSampleGrabberNode->Release();
- m_audioSampleGrabberNode = NULL;
- }
- return false;
-}
-
-bool MFPlayerSession::setupAudioSampleGrabber(IMFTopology *topology, IMFTopologyNode *sourceNode, IMFTopologyNode *outputNode)
-{
- if (!addAudioSampleGrabberNode(topology))
- return false;
-
- HRESULT hr = S_OK;
- IMFTopologyNode *pTeeNode = NULL;
-
- IMFMediaTypeHandler *typeHandler = NULL;
- IMFMediaType *mediaType = NULL;
- do {
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &pTeeNode);
- if (FAILED(hr))
- break;
- hr = sourceNode->ConnectOutput(0, pTeeNode, 0);
- if (FAILED(hr))
- break;
- hr = pTeeNode->ConnectOutput(0, outputNode, 0);
- if (FAILED(hr))
- break;
- hr = pTeeNode->ConnectOutput(1, m_audioSampleGrabberNode, 0);
- if (FAILED(hr))
- break;
- } while (false);
-
- if (pTeeNode)
- pTeeNode->Release();
- if (mediaType)
- mediaType->Release();
- if (typeHandler)
- typeHandler->Release();
- return hr == S_OK;
-}
-
-QAudioFormat MFPlayerSession::audioFormatForMFMediaType(IMFMediaType *mediaType) const
-{
- WAVEFORMATEX *wfx = 0;
- UINT32 size;
- HRESULT hr = MFCreateWaveFormatExFromMFMediaType(mediaType, &wfx, &size, MFWaveFormatExConvertFlag_Normal);
- if (FAILED(hr))
- return QAudioFormat();
-
- if (size < sizeof(WAVEFORMATEX)) {
- CoTaskMemFree(wfx);
- return QAudioFormat();
- }
-
- if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
- CoTaskMemFree(wfx);
- return QAudioFormat();
- }
-
- QAudioFormat format;
- format.setSampleRate(wfx->nSamplesPerSec);
- format.setChannelCount(wfx->nChannels);
- if (wfx->wBitsPerSample == 8)
- format.setSampleFormat(QAudioFormat::UInt8);
- else if (wfx->wBitsPerSample == 16)
- format.setSampleFormat(QAudioFormat::Int16);
- else if (wfx->wBitsPerSample == 32)
- format.setSampleFormat(QAudioFormat::Int32);
-
- CoTaskMemFree(wfx);
- return format;
-}
-
-// BindOutputNode
-// Sets the IMFStreamSink pointer on an output node.
-// IMFActivate pointer in the output node must be converted to an
-// IMFStreamSink pointer before the topology loader resolves the topology.
-HRESULT BindOutputNode(IMFTopologyNode *pNode)
-{
- IUnknown *nodeObject = NULL;
- IMFActivate *activate = NULL;
- IMFStreamSink *stream = NULL;
- IMFMediaSink *sink = NULL;
-
- HRESULT hr = pNode->GetObject(&nodeObject);
- if (FAILED(hr))
- return hr;
-
- hr = nodeObject->QueryInterface(IID_PPV_ARGS(&activate));
- if (SUCCEEDED(hr)) {
- DWORD dwStreamID = 0;
-
- // Try to create the media sink.
- hr = activate->ActivateObject(IID_PPV_ARGS(&sink));
- if (SUCCEEDED(hr))
- dwStreamID = MFGetAttributeUINT32(pNode, MF_TOPONODE_STREAMID, 0);
-
- if (SUCCEEDED(hr)) {
- // First check if the media sink already has a stream sink with the requested ID.
- hr = sink->GetStreamSinkById(dwStreamID, &stream);
- if (FAILED(hr)) {
- // Create the stream sink.
- hr = sink->AddStreamSink(dwStreamID, NULL, &stream);
- }
- }
-
- // Replace the node's object pointer with the stream sink.
- if (SUCCEEDED(hr)) {
- hr = pNode->SetObject(stream);
- }
- } else {
- hr = nodeObject->QueryInterface(IID_PPV_ARGS(&stream));
- }
-
- if (nodeObject)
- nodeObject->Release();
- if (activate)
- activate->Release();
- if (stream)
- stream->Release();
- if (sink)
- sink->Release();
- return hr;
-}
-
-// BindOutputNodes
-// Sets the IMFStreamSink pointers on all of the output nodes in a topology.
-HRESULT BindOutputNodes(IMFTopology *pTopology)
-{
- IMFCollection *collection;
-
- // Get the collection of output nodes.
- HRESULT hr = pTopology->GetOutputNodeCollection(&collection);
-
- // Enumerate all of the nodes in the collection.
- if (SUCCEEDED(hr)) {
- DWORD cNodes;
- hr = collection->GetElementCount(&cNodes);
-
- if (SUCCEEDED(hr)) {
- for (DWORD i = 0; i < cNodes; i++) {
- IUnknown *element;
- hr = collection->GetElement(i, &element);
- if (FAILED(hr))
- break;
-
- IMFTopologyNode *node;
- hr = element->QueryInterface(IID_IMFTopologyNode, (void**)&node);
- element->Release();
- if (FAILED(hr))
- break;
-
- // Bind this node.
- hr = BindOutputNode(node);
- node->Release();
- if (FAILED(hr))
- break;
- }
- }
- collection->Release();
- }
-
- return hr;
-}
-
-// This method binds output nodes to complete the topology,
-// then loads the topology and inserts MFT between the output node
-// and a filter connected to the output node.
-IMFTopology *MFPlayerSession::insertMFT(IMFTopology *topology, TOPOID outputNodeId)
-{
- bool isNewTopology = false;
-
- IMFTopoLoader *topoLoader = 0;
- IMFTopology *resolvedTopology = 0;
- IMFCollection *outputNodes = 0;
-
- do {
- if (FAILED(BindOutputNodes(topology)))
- break;
-
- if (FAILED(MFCreateTopoLoader(&topoLoader)))
- break;
-
- if (FAILED(topoLoader->Load(topology, &resolvedTopology, NULL))) {
- // Topology could not be resolved, adding ourselves a color converter
- // to the topology might solve the problem
- insertColorConverter(topology, outputNodeId);
- if (FAILED(topoLoader->Load(topology, &resolvedTopology, NULL)))
- break;
- }
-
- if (insertResizer(resolvedTopology))
- isNewTopology = true;
-
- // Get all output nodes and search for video output node.
- if (FAILED(resolvedTopology->GetOutputNodeCollection(&outputNodes)))
- break;
-
- DWORD elementCount = 0;
- if (FAILED(outputNodes->GetElementCount(&elementCount)))
- break;
-
- for (DWORD n = 0; n < elementCount; n++) {
- IUnknown *element = 0;
- IMFTopologyNode *node = 0;
- IUnknown *outputObject = 0;
- IMFTopologyNode *inputNode = 0;
- IMFTopologyNode *mftNode = 0;
- bool mftAdded = false;
-
- do {
- if (FAILED(outputNodes->GetElement(n, &element)))
- break;
-
- if (FAILED(element->QueryInterface(IID_IMFTopologyNode, (void**)&node)))
- break;
-
- TOPOID id;
- if (FAILED(node->GetTopoNodeID(&id)))
- break;
-
- if (id != outputNodeId)
- break;
-
- if (FAILED(node->GetObject(&outputObject)))
- break;
-
- m_videoProbeMFT->setVideoSink(outputObject);
-
- // Insert MFT between the output node and the node connected to it.
- DWORD outputIndex = 0;
- if (FAILED(node->GetInput(0, &inputNode, &outputIndex)))
- break;
-
- if (FAILED(MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &mftNode)))
- break;
-
- if (FAILED(mftNode->SetObject(m_videoProbeMFT)))
- break;
-
- if (FAILED(resolvedTopology->AddNode(mftNode)))
- break;
-
- if (FAILED(inputNode->ConnectOutput(0, mftNode, 0)))
- break;
-
- if (FAILED(mftNode->ConnectOutput(0, node, 0)))
- break;
-
- mftAdded = true;
- isNewTopology = true;
- } while (false);
-
- if (mftNode)
- mftNode->Release();
- if (inputNode)
- inputNode->Release();
- if (node)
- node->Release();
- if (element)
- element->Release();
- if (outputObject)
- outputObject->Release();
-
- if (mftAdded)
- break;
- else
- m_videoProbeMFT->setVideoSink(NULL);
- }
- } while (false);
-
- if (outputNodes)
- outputNodes->Release();
-
- if (topoLoader)
- topoLoader->Release();
-
- if (isNewTopology) {
- topology->Release();
- return resolvedTopology;
- }
-
- if (resolvedTopology)
- resolvedTopology->Release();
-
- return topology;
-}
-
-// This method checks if the topology contains a color converter transform (CColorConvertDMO),
-// if it does it inserts a resizer transform (CResizerDMO) to handle dynamic frame size change
-// of the video stream.
-// Returns true if it inserted a resizer
-bool MFPlayerSession::insertResizer(IMFTopology *topology)
-{
- bool inserted = false;
- WORD elementCount = 0;
- IMFTopologyNode *node = 0;
- IUnknown *object = 0;
- IWMColorConvProps *colorConv = 0;
- IMFTransform *resizer = 0;
- IMFTopologyNode *resizerNode = 0;
- IMFTopologyNode *inputNode = 0;
-
- HRESULT hr = topology->GetNodeCount(&elementCount);
- if (FAILED(hr))
- return false;
-
- for (WORD i = 0; i < elementCount; ++i) {
- if (node) {
- node->Release();
- node = 0;
- }
- if (object) {
- object->Release();
- object = 0;
- }
-
- if (FAILED(topology->GetNode(i, &node)))
- break;
-
- MF_TOPOLOGY_TYPE nodeType;
- if (FAILED(node->GetNodeType(&nodeType)))
- break;
-
- if (nodeType != MF_TOPOLOGY_TRANSFORM_NODE)
- continue;
-
- if (FAILED(node->GetObject(&object)))
- break;
-
- if (FAILED(object->QueryInterface(&colorConv)))
- continue;
-
- if (FAILED(CoCreateInstance(CLSID_CResizerDMO, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, (void**)&resizer)))
- break;
-
- if (FAILED(MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &resizerNode)))
- break;
-
- if (FAILED(resizerNode->SetObject(resizer)))
- break;
-
- if (FAILED(topology->AddNode(resizerNode)))
- break;
-
- DWORD outputIndex = 0;
- if (FAILED(node->GetInput(0, &inputNode, &outputIndex))) {
- topology->RemoveNode(resizerNode);
- break;
- }
-
- if (FAILED(inputNode->ConnectOutput(0, resizerNode, 0))) {
- topology->RemoveNode(resizerNode);
- break;
- }
-
- if (FAILED(resizerNode->ConnectOutput(0, node, 0))) {
- inputNode->ConnectOutput(0, node, 0);
- topology->RemoveNode(resizerNode);
- break;
- }
-
- inserted = true;
- break;
- }
-
- if (node)
- node->Release();
- if (object)
- object->Release();
- if (colorConv)
- colorConv->Release();
- if (resizer)
- resizer->Release();
- if (resizerNode)
- resizerNode->Release();
- if (inputNode)
- inputNode->Release();
-
- return inserted;
-}
-
-// This method inserts a color converter (CColorConvertDMO) in the topology,
-// typically to convert to RGB format.
-// Usually this converter is automatically inserted when the topology is resolved but
-// for some reason it fails to do so in some cases, we then do it ourselves.
-void MFPlayerSession::insertColorConverter(IMFTopology *topology, TOPOID outputNodeId)
-{
- IMFCollection *outputNodes = 0;
-
- if (FAILED(topology->GetOutputNodeCollection(&outputNodes)))
- return;
-
- DWORD elementCount = 0;
- if (FAILED(outputNodes->GetElementCount(&elementCount)))
- goto done;
-
- for (DWORD n = 0; n < elementCount; n++) {
- IUnknown *element = 0;
- IMFTopologyNode *node = 0;
- IMFTopologyNode *inputNode = 0;
- IMFTopologyNode *mftNode = 0;
- IMFTransform *converter = 0;
-
- do {
- if (FAILED(outputNodes->GetElement(n, &element)))
- break;
-
- if (FAILED(element->QueryInterface(IID_IMFTopologyNode, (void**)&node)))
- break;
-
- TOPOID id;
- if (FAILED(node->GetTopoNodeID(&id)))
- break;
-
- if (id != outputNodeId)
- break;
-
- DWORD outputIndex = 0;
- if (FAILED(node->GetInput(0, &inputNode, &outputIndex)))
- break;
-
- if (FAILED(MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &mftNode)))
- break;
-
- if (FAILED(CoCreateInstance(CLSID_CColorConvertDMO, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, (void**)&converter)))
- break;
-
- if (FAILED(mftNode->SetObject(converter)))
- break;
-
- if (FAILED(topology->AddNode(mftNode)))
- break;
-
- if (FAILED(inputNode->ConnectOutput(0, mftNode, 0)))
- break;
-
- if (FAILED(mftNode->ConnectOutput(0, node, 0)))
- break;
-
- } while (false);
-
- if (mftNode)
- mftNode->Release();
- if (inputNode)
- inputNode->Release();
- if (node)
- node->Release();
- if (element)
- element->Release();
- if (converter)
- converter->Release();
- }
-
-done:
- if (outputNodes)
- outputNodes->Release();
-}
-
-void MFPlayerSession::stop(bool immediate)
-{
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "stop";
-#endif
- if (!immediate && m_pendingState != NoPending) {
- m_request.setCommand(CmdStop);
- } else {
- if (m_state.command == CmdStop)
- return;
-
- if (m_scrubbing)
- scrub(false);
-
- if (SUCCEEDED(m_session->Stop())) {
-
- m_state.setCommand(CmdStop);
- m_pendingState = CmdPending;
- if (m_status != QMediaPlayer::EndOfMedia) {
- m_position = 0;
- }
- } else {
- emit error(QMediaPlayer::ResourceError, tr("Failed to stop."), true);
- }
- }
-}
-
-void MFPlayerSession::start()
-{
- if (m_status == QMediaPlayer::EndOfMedia)
- m_position = 0; // restart from the beginning
-
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "start";
-#endif
-
- if (m_pendingState != NoPending) {
- m_request.setCommand(CmdStart);
- } else {
- if (m_state.command == CmdStart)
- return;
-
- if (m_scrubbing)
- scrub(false);
-
- if (m_restorePosition >= 0) {
- m_position = m_restorePosition;
- if (!m_updatingTopology)
- m_restorePosition = -1;
- }
-
- PROPVARIANT varStart;
- InitPropVariantFromInt64(m_position, &varStart);
-
- if (SUCCEEDED(m_session->Start(&GUID_NULL, &varStart))) {
- m_state.setCommand(CmdStart);
- m_pendingState = CmdPending;
- } else {
- emit error(QMediaPlayer::ResourceError, tr("failed to start playback"), true);
- }
- PropVariantClear(&varStart);
- }
-}
-
-void MFPlayerSession::pause()
-{
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "pause";
-#endif
- if (m_pendingState != NoPending) {
- m_request.setCommand(CmdPause);
- } else {
- if (m_state.command == CmdPause)
- return;
-
- if (SUCCEEDED(m_session->Pause())) {
- m_state.setCommand(CmdPause);
- m_pendingState = CmdPending;
- } else {
- emit error(QMediaPlayer::ResourceError, tr("Failed to pause."), false);
- }
- }
-}
-
-void MFPlayerSession::changeStatus(QMediaPlayer::MediaStatus newStatus)
-{
- if (m_status == newStatus)
- return;
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MFPlayerSession::changeStatus" << newStatus;
-#endif
- m_status = newStatus;
- emit statusChanged();
-}
-
-QMediaPlayer::MediaStatus MFPlayerSession::status() const
-{
- return m_status;
-}
-
-void MFPlayerSession::createSession()
-{
- close();
-
- m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- m_sourceResolver = new SourceResolver();
- QObject::connect(m_sourceResolver, SIGNAL(mediaSourceReady()), this, SLOT(handleMediaSourceReady()));
- QObject::connect(m_sourceResolver, SIGNAL(error(long)), this, SLOT(handleSourceError(long)));
-
- m_videoProbeMFT = new MFTransform;
-// for (int i = 0; i < m_videoProbes.size(); ++i)
-// m_videoProbeMFT->addProbe(m_videoProbes.at(i));
-
- Q_ASSERT(m_session == NULL);
- HRESULT hr = MFCreateMediaSession(NULL, &m_session);
- if (FAILED(hr)) {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Unable to create mediasession."), true);
- }
-
- hr = m_session->BeginGetEvent(this, m_session);
-
- if (FAILED(hr)) {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::ResourceError, tr("Unable to pull session events."), false);
- }
-
- m_position = 0;
-}
-
-qint64 MFPlayerSession::position()
-{
- if (m_request.command == CmdSeek || m_request.command == CmdSeekResume)
- return m_request.start;
-
- if (m_pendingState == SeekPending)
- return m_state.start;
-
- if (m_state.command == CmdStop) {
- return m_position / 10000;
- }
-
- if (m_presentationClock) {
- MFTIME time, sysTime;
- if (FAILED(m_presentationClock->GetCorrelatedTime(0, &time, &sysTime)))
- return 0;
- return qint64(time / 10000);
- }
- return 0;
-}
-
-void MFPlayerSession::setPosition(qint64 position)
-{
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "setPosition";
-#endif
- if (m_pendingState != NoPending) {
- m_request.setCommand(CmdSeek);
- m_request.start = position;
- } else {
- setPositionInternal(position, CmdNone);
- }
-}
-
-void MFPlayerSession::setPositionInternal(qint64 position, Command requestCmd)
-{
- if (m_status == QMediaPlayer::EndOfMedia)
- changeStatus(QMediaPlayer::LoadedMedia);
- if (m_state.command == CmdStop && requestCmd != CmdSeekResume) {
- m_position = position * 10000;
- // Even though the position is not actually set on the session yet,
- // report it to have changed anyway for UI controls to be updated
- emit positionChanged(this->position());
- return;
- }
-
- if (m_state.command == CmdPause)
- scrub(true);
-
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "setPositionInternal";
-#endif
-
- PROPVARIANT varStart;
- varStart.vt = VT_I8;
- varStart.hVal.QuadPart = LONGLONG(position * 10000);
- if (SUCCEEDED(m_session->Start(NULL, &varStart)))
- {
- PropVariantClear(&varStart);
- // Store the pending state.
- m_state.setCommand(CmdStart);
- m_state.start = position;
- m_pendingState = SeekPending;
- } else {
- emit error(QMediaPlayer::ResourceError, tr("Failed to seek."), true);
- }
-}
-
-qreal MFPlayerSession::playbackRate() const
-{
- if (m_scrubbing)
- return m_restoreRate;
- return m_state.rate;
-}
-
-void MFPlayerSession::setPlaybackRate(qreal rate)
-{
- if (m_scrubbing) {
- m_restoreRate = rate;
- emit playbackRateChanged(rate);
- return;
- }
- setPlaybackRateInternal(rate);
-}
-
-void MFPlayerSession::setPlaybackRateInternal(qreal rate)
-{
- if (rate == m_request.rate)
- return;
-
- m_pendingRate = rate;
- if (!m_rateSupport)
- return;
-
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "setPlaybackRate";
-#endif
- BOOL isThin = FALSE;
-
- //from MSDN http://msdn.microsoft.com/en-us/library/aa965220%28v=vs.85%29.aspx
- //Thinning applies primarily to video streams.
- //In thinned mode, the source drops delta frames and deliver only key frames.
- //At very high playback rates, the source might skip some key frames (for example, deliver every other key frame).
-
- if (FAILED(m_rateSupport->IsRateSupported(FALSE, rate, NULL))) {
- isThin = TRUE;
- if (FAILED(m_rateSupport->IsRateSupported(isThin, rate, NULL))) {
- qWarning() << "unable to set playbackrate = " << rate;
- m_pendingRate = m_request.rate = m_state.rate;
- return;
- }
- }
- if (m_pendingState != NoPending) {
- m_request.rate = rate;
- m_request.isThin = isThin;
- // Remember the current transport state (play, paused, etc), so that we
- // can restore it after the rate change, if necessary. However, if
- // anothercommand is already pending, that one takes precedent.
- if (m_request.command == CmdNone)
- m_request.setCommand(m_state.command);
- } else {
- //No pending operation. Commit the new rate.
- commitRateChange(rate, isThin);
- }
-}
-
-void MFPlayerSession::commitRateChange(qreal rate, BOOL isThin)
-{
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "commitRateChange";
-#endif
- Q_ASSERT(m_pendingState == NoPending);
- MFTIME hnsSystemTime = 0;
- MFTIME hnsClockTime = 0;
- Command cmdNow = m_state.command;
- bool resetPosition = false;
- // Allowed rate transitions:
- // Positive <-> negative: Stopped
- // Negative <-> zero: Stopped
- // Postive <-> zero: Paused or stopped
- if ((rate > 0 && m_state.rate <= 0) || (rate < 0 && m_state.rate >= 0)) {
- if (cmdNow == CmdStart) {
- // Get the current clock position. This will be the restart time.
- m_presentationClock->GetCorrelatedTime(0, &hnsClockTime, &hnsSystemTime);
- Q_ASSERT(hnsSystemTime != 0);
-
- if (rate < 0 || m_state.rate < 0)
- m_request.setCommand(CmdSeekResume);
- else if (isThin || m_state.isThin)
- m_request.setCommand(CmdStartAndSeek);
- else
- m_request.setCommand(CmdStart);
-
- // We need to stop only when dealing with negative rates
- if (rate >= 0 && m_state.rate >= 0)
- pause();
- else
- stop();
-
- // If we deal with negative rates, we stopped the session and consequently
- // reset the position to zero. We then need to resume to the current position.
- m_request.start = hnsClockTime / 10000;
- } else if (cmdNow == CmdPause) {
- if (rate < 0 || m_state.rate < 0) {
- // The current state is paused.
- // For this rate change, the session must be stopped. However, the
- // session cannot transition back from stopped to paused.
- // Therefore, this rate transition is not supported while paused.
- qWarning() << "Unable to change rate from positive to negative or vice versa in paused state";
- rate = m_state.rate;
- isThin = m_state.isThin;
- goto done;
- }
-
- // This happens when resuming playback after scrubbing in pause mode.
- // This transition requires the session to be paused. Even though our
- // internal state is set to paused, the session might not be so we need
- // to enforce it
- if (rate > 0 && m_state.rate == 0) {
- m_state.setCommand(CmdNone);
- pause();
- }
- }
- } else if (rate == 0 && m_state.rate > 0) {
- if (cmdNow != CmdPause) {
- // Transition to paused.
- // This transisition requires the paused state.
- // Pause and set the rate.
- pause();
-
- // Request: Switch back to current state.
- m_request.setCommand(cmdNow);
- }
- } else if (rate == 0 && m_state.rate < 0) {
- // Changing rate from negative to zero requires to stop the session
- m_presentationClock->GetCorrelatedTime(0, &hnsClockTime, &hnsSystemTime);
-
- m_request.setCommand(CmdSeekResume);
-
- stop();
-
- // Resume to the current position (stop() will reset the position to 0)
- m_request.start = hnsClockTime / 10000;
- } else if (!isThin && m_state.isThin) {
- if (cmdNow == CmdStart) {
- // When thinning, only key frames are read and presented. Going back
- // to normal playback requires to reset the current position to force
- // the pipeline to decode the actual frame at the current position
- // (which might be earlier than the last decoded key frame)
- resetPosition = true;
- } else if (cmdNow == CmdPause) {
- // If paused, don't reset the position until we resume, otherwise
- // a new frame will be rendered
- m_presentationClock->GetCorrelatedTime(0, &hnsClockTime, &hnsSystemTime);
- m_request.setCommand(CmdSeekResume);
- m_request.start = hnsClockTime / 10000;
- }
-
- }
-
- // Set the rate.
- if (FAILED(m_rateControl->SetRate(isThin, rate))) {
- qWarning() << "failed to set playbackrate = " << rate;
- rate = m_state.rate;
- isThin = m_state.isThin;
- goto done;
- }
-
- if (resetPosition) {
- m_presentationClock->GetCorrelatedTime(0, &hnsClockTime, &hnsSystemTime);
- setPosition(hnsClockTime / 10000);
- }
-
-done:
- // Adjust our current rate and requested rate.
- m_pendingRate = m_request.rate = m_state.rate = rate;
- if (rate != 0)
- m_state.isThin = isThin;
- emit playbackRateChanged(rate);
-}
-
-void MFPlayerSession::scrub(bool enableScrub)
-{
- if (m_scrubbing == enableScrub)
- return;
-
- m_scrubbing = enableScrub;
-
- if (!canScrub()) {
- if (!enableScrub)
- m_pendingRate = m_restoreRate;
- return;
- }
-
- if (enableScrub) {
- // Enter scrubbing mode. Cache the rate.
- m_restoreRate = m_request.rate;
- setPlaybackRateInternal(0.0f);
- } else {
- // Leaving scrubbing mode. Restore the old rate.
- setPlaybackRateInternal(m_restoreRate);
- }
-}
-
-void MFPlayerSession::setVolume(float volume)
-{
- if (m_volume == volume)
- return;
- m_volume = volume;
-
- if (!m_muted)
- setVolumeInternal(volume);
-}
-
-void MFPlayerSession::setMuted(bool muted)
-{
- if (m_muted == muted)
- return;
- m_muted = muted;
-
- setVolumeInternal(muted ? 0 : m_volume);
-}
-
-void MFPlayerSession::setVolumeInternal(float volume)
-{
- if (m_volumeControl) {
- quint32 channelCount = 0;
- if (!SUCCEEDED(m_volumeControl->GetChannelCount(&channelCount))
- || channelCount == 0)
- return;
-
- for (quint32 i = 0; i < channelCount; ++i)
- m_volumeControl->SetChannelVolume(i, volume);
- }
-}
-
-float MFPlayerSession::bufferProgress()
-{
- if (!m_netsourceStatistics)
- return 0;
- PROPVARIANT var;
- PropVariantInit(&var);
- PROPERTYKEY key;
- key.fmtid = MFNETSOURCE_STATISTICS;
- key.pid = MFNETSOURCE_BUFFERPROGRESS_ID;
- int progress = -1;
- // GetValue returns S_FALSE if the property is not available, which has
- // a value > 0. We therefore can't use the SUCCEEDED macro here.
- if (m_netsourceStatistics->GetValue(key, &var) == S_OK) {
- progress = var.lVal;
- PropVariantClear(&var);
- }
-
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "bufferProgress: progress = " << progress;
-#endif
-
- return progress/100.;
-}
-
-QMediaTimeRange MFPlayerSession::availablePlaybackRanges()
-{
- // defaults to the whole media
- qint64 start = 0;
- qint64 end = qint64(m_duration / 10000);
-
- if (m_netsourceStatistics) {
- PROPVARIANT var;
- PropVariantInit(&var);
- PROPERTYKEY key;
- key.fmtid = MFNETSOURCE_STATISTICS;
- key.pid = MFNETSOURCE_SEEKRANGESTART_ID;
- // GetValue returns S_FALSE if the property is not available, which has
- // a value > 0. We therefore can't use the SUCCEEDED macro here.
- if (m_netsourceStatistics->GetValue(key, &var) == S_OK) {
- start = qint64(var.uhVal.QuadPart / 10000);
- PropVariantClear(&var);
- PropVariantInit(&var);
- key.pid = MFNETSOURCE_SEEKRANGEEND_ID;
- if (m_netsourceStatistics->GetValue(key, &var) == S_OK) {
- end = qint64(var.uhVal.QuadPart / 10000);
- PropVariantClear(&var);
- }
- }
- }
-
- return QMediaTimeRange(start, end);
-}
-
-HRESULT MFPlayerSession::QueryInterface(REFIID riid, void** ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFAsyncCallback) {
- *ppvObject = static_cast<IMFAsyncCallback*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- return S_OK;
-}
-
-ULONG MFPlayerSession::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-ULONG MFPlayerSession::Release(void)
-{
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- this->deleteLater();
- return cRef;
-}
-
-HRESULT MFPlayerSession::Invoke(IMFAsyncResult *pResult)
-{
- if (pResult->GetStateNoAddRef() != m_session)
- return S_OK;
-
- IMFMediaEvent *pEvent = NULL;
- // Get the event from the event queue.
- HRESULT hr = m_session->EndGetEvent(pResult, &pEvent);
- if (FAILED(hr)) {
- return S_OK;
- }
-
- MediaEventType meType = MEUnknown;
- hr = pEvent->GetType(&meType);
- if (FAILED(hr)) {
- pEvent->Release();
- return S_OK;
- }
-
- if (meType == MESessionClosed) {
- SetEvent(m_hCloseEvent);
- pEvent->Release();
- return S_OK;
- } else {
- hr = m_session->BeginGetEvent(this, m_session);
- if (FAILED(hr)) {
- pEvent->Release();
- return S_OK;
- }
- }
-
- if (!m_closing) {
- emit sessionEvent(pEvent);
- } else {
- pEvent->Release();
- }
- return S_OK;
-}
-
-void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
-{
- HRESULT hrStatus = S_OK;
- HRESULT hr = sessionEvent->GetStatus(&hrStatus);
- if (FAILED(hr) || !m_session) {
- sessionEvent->Release();
- return;
- }
-
- MediaEventType meType = MEUnknown;
- hr = sessionEvent->GetType(&meType);
-
-#ifdef DEBUG_MEDIAFOUNDATION
- if (FAILED(hrStatus))
- qDebug() << "handleSessionEvent: MediaEventType = " << meType << "Failed";
- else
- qDebug() << "handleSessionEvent: MediaEventType = " << meType;
-#endif
-
- switch (meType) {
- case MENonFatalError: {
- PROPVARIANT var;
- PropVariantInit(&var);
- sessionEvent->GetValue(&var);
- qWarning() << "handleSessionEvent: non fatal error = " << var.ulVal;
- PropVariantClear(&var);
- emit error(QMediaPlayer::ResourceError, tr("Media session non-fatal error."), false);
- }
- break;
- case MESourceUnknown:
- changeStatus(QMediaPlayer::InvalidMedia);
- break;
- case MEError:
- changeStatus(QMediaPlayer::InvalidMedia);
- qWarning() << "handleSessionEvent: serious error = " << hrStatus;
- emit error(QMediaPlayer::ResourceError, tr("Media session serious error."), true);
- break;
- case MESessionRateChanged:
- // If the rate change succeeded, we've already got the rate
- // cached. If it failed, try to get the actual rate.
- if (FAILED(hrStatus)) {
- PROPVARIANT var;
- PropVariantInit(&var);
- if (SUCCEEDED(sessionEvent->GetValue(&var)) && (var.vt == VT_R4)) {
- m_state.rate = var.fltVal;
- }
- emit playbackRateChanged(playbackRate());
- }
- break;
- case MESessionScrubSampleComplete :
- if (m_scrubbing)
- updatePendingCommands(CmdStart);
- break;
- case MESessionStarted:
- if (m_status == QMediaPlayer::EndOfMedia
- || m_status == QMediaPlayer::LoadedMedia) {
- // If the session started, then enough data is buffered to play
- changeStatus(QMediaPlayer::BufferedMedia);
- }
-
- updatePendingCommands(CmdStart);
- // playback started, we can now set again the procAmpValues if they have been
- // changed previously (these are lost when loading a new media)
-// if (m_playerService->videoWindowControl()) {
-// m_playerService->videoWindowControl()->applyImageControls();
-// }
- m_signalPositionChangeTimer.start();
- break;
- case MESessionStopped:
- if (m_status != QMediaPlayer::EndOfMedia) {
- m_position = 0;
-
- // Reset to Loaded status unless we are loading a new media
- // or changing the playback rate to negative values (stop required)
- if (m_status != QMediaPlayer::LoadingMedia && m_request.command != CmdSeekResume)
- changeStatus(QMediaPlayer::LoadedMedia);
- }
- updatePendingCommands(CmdStop);
- m_signalPositionChangeTimer.stop();
- break;
- case MESessionPaused:
- m_position = position() * 10000;
- updatePendingCommands(CmdPause);
- m_signalPositionChangeTimer.stop();
- break;
- case MEReconnectStart:
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MEReconnectStart" << ((hrStatus == S_OK) ? "OK" : "Failed");
-#endif
- break;
- case MEReconnectEnd:
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MEReconnectEnd" << ((hrStatus == S_OK) ? "OK" : "Failed");
-#endif
- break;
- case MESessionTopologySet:
- if (FAILED(hrStatus)) {
- changeStatus(QMediaPlayer::InvalidMedia);
- emit error(QMediaPlayer::FormatError, tr("Unsupported media, a codec is missing."), true);
- } else {
- if (m_audioSampleGrabberNode) {
- IUnknown *obj = 0;
- if (SUCCEEDED(m_audioSampleGrabberNode->GetObject(&obj))) {
- IMFStreamSink *streamSink = 0;
- if (SUCCEEDED(obj->QueryInterface(IID_PPV_ARGS(&streamSink)))) {
- IMFMediaTypeHandler *typeHandler = 0;
- if (SUCCEEDED(streamSink->GetMediaTypeHandler((&typeHandler)))) {
- IMFMediaType *mediaType = 0;
- if (SUCCEEDED(typeHandler->GetCurrentMediaType(&mediaType))) {
- m_audioSampleGrabber->setFormat(audioFormatForMFMediaType(mediaType));
- mediaType->Release();
- }
- typeHandler->Release();
- }
- streamSink->Release();
- }
- obj->Release();
- }
- }
-
- // Topology is resolved and successfuly set, this happens only after loading a new media.
- // Make sure we always start the media from the beginning
- m_position = 0;
-
- changeStatus(QMediaPlayer::LoadedMedia);
- }
- break;
- }
-
- if (FAILED(hrStatus)) {
- sessionEvent->Release();
- return;
- }
-
- switch (meType) {
- case MEBufferingStarted:
- changeStatus(QMediaPlayer::StalledMedia);
- emit bufferProgressChanged(bufferProgress());
- break;
- case MEBufferingStopped:
- changeStatus(QMediaPlayer::BufferedMedia);
- emit bufferProgressChanged(bufferProgress());
- break;
- case MESessionEnded:
- m_pendingState = NoPending;
- m_state.command = CmdStop;
- m_state.prevCmd = CmdNone;
- m_request.command = CmdNone;
- m_request.prevCmd = CmdNone;
-
- //keep reporting the final position after end of media
- m_position = qint64(m_duration);
- emit positionChanged(position());
-
- changeStatus(QMediaPlayer::EndOfMedia);
- break;
- case MEEndOfPresentationSegment:
- break;
- case MESessionTopologyStatus: {
- UINT32 status;
- if (SUCCEEDED(sessionEvent->GetUINT32(MF_EVENT_TOPOLOGY_STATUS, &status))) {
- if (status == MF_TOPOSTATUS_READY) {
- IMFClock* clock;
- if (SUCCEEDED(m_session->GetClock(&clock))) {
- clock->QueryInterface(IID_IMFPresentationClock, (void**)(&m_presentationClock));
- clock->Release();
- }
-
- if (SUCCEEDED(MFGetService(m_session, MF_RATE_CONTROL_SERVICE, IID_PPV_ARGS(&m_rateControl)))) {
- if (SUCCEEDED(MFGetService(m_session, MF_RATE_CONTROL_SERVICE, IID_PPV_ARGS(&m_rateSupport)))) {
- if ((m_mediaTypes & Video) == Video
- && SUCCEEDED(m_rateSupport->IsRateSupported(TRUE, 0, NULL)))
- m_canScrub = true;
- }
- BOOL isThin = FALSE;
- float rate = 1;
- if (SUCCEEDED(m_rateControl->GetRate(&isThin, &rate))) {
- if (m_pendingRate != rate) {
- m_state.rate = m_request.rate = rate;
- setPlaybackRate(m_pendingRate);
- }
- }
- }
- MFGetService(m_session, MFNETSOURCE_STATISTICS_SERVICE, IID_PPV_ARGS(&m_netsourceStatistics));
-
- if (SUCCEEDED(MFGetService(m_session, MR_STREAM_VOLUME_SERVICE, IID_PPV_ARGS(&m_volumeControl))))
- setVolumeInternal(m_muted ? 0 : m_volume);
-
- m_updatingTopology = false;
- stop();
- }
- }
- }
- break;
- default:
- break;
- }
-
- sessionEvent->Release();
-}
-
-void MFPlayerSession::updatePendingCommands(Command command)
-{
- emit positionChanged(position());
- if (m_state.command != command || m_pendingState == NoPending)
- return;
-
- // Seek while paused completed
- if (m_pendingState == SeekPending && m_state.prevCmd == CmdPause) {
- m_pendingState = NoPending;
- // A seek operation actually restarts playback. If scrubbing is possible, playback rate
- // is set to 0.0 at this point and we just need to reset the current state to Pause.
- // If scrubbing is not possible, the playback rate was not changed and we explicitly need
- // to re-pause playback.
- if (!canScrub())
- pause();
- else
- m_state.setCommand(CmdPause);
- }
-
- m_pendingState = NoPending;
-
- //First look for rate changes.
- if (m_request.rate != m_state.rate) {
- commitRateChange(m_request.rate, m_request.isThin);
- }
-
- // Now look for new requests.
- if (m_pendingState == NoPending) {
- switch (m_request.command) {
- case CmdStart:
- start();
- break;
- case CmdPause:
- pause();
- break;
- case CmdStop:
- stop();
- break;
- case CmdSeek:
- case CmdSeekResume:
- setPositionInternal(m_request.start, m_request.command);
- break;
- case CmdStartAndSeek:
- start();
- setPositionInternal(m_request.start, m_request.command);
- break;
- }
- m_request.setCommand(CmdNone);
- }
-
-}
-
-bool MFPlayerSession::canScrub() const
-{
- return m_canScrub && m_rateSupport && m_rateControl;
-}
-
-void MFPlayerSession::clear()
-{
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MFPlayerSession::clear";
-#endif
- m_mediaTypes = 0;
- m_canScrub = false;
-
- m_pendingState = NoPending;
- m_state.command = CmdStop;
- m_state.prevCmd = CmdNone;
- m_request.command = CmdNone;
- m_request.prevCmd = CmdNone;
-
- for (int i = 0; i < QPlatformMediaPlayer::NTrackTypes; ++i) {
- m_trackInfo[i].metaData.clear();
- m_trackInfo[i].nativeIndexes.clear();
- m_trackInfo[i].currentIndex = -1;
- m_trackInfo[i].sourceNodeId = -1;
- m_trackInfo[i].outputNodeId = -1;
- }
-
- if (!m_metaData.isEmpty()) {
- m_metaData.clear();
- emit metaDataChanged();
- }
-
- if (m_presentationClock) {
- m_presentationClock->Release();
- m_presentationClock = NULL;
- }
- if (m_rateControl) {
- m_rateControl->Release();
- m_rateControl = NULL;
- }
- if (m_rateSupport) {
- m_rateSupport->Release();
- m_rateSupport = NULL;
- }
- if (m_volumeControl) {
- m_volumeControl->Release();
- m_volumeControl = NULL;
- }
- if (m_netsourceStatistics) {
- m_netsourceStatistics->Release();
- m_netsourceStatistics = NULL;
- }
- if (m_audioSampleGrabberNode) {
- m_audioSampleGrabberNode->Release();
- m_audioSampleGrabberNode = NULL;
- }
-}
-
-void MFPlayerSession::setAudioOutput(QPlatformAudioOutput *device)
-{
- if (m_audioOutput == device)
- return;
-
- if (m_audioOutput)
- m_audioOutput->q->disconnect(this);
-
- m_audioOutput = device;
- if (m_audioOutput) {
- setMuted(m_audioOutput->q->isMuted());
- setVolume(m_audioOutput->q->volume());
- updateOutputRouting();
- connect(m_audioOutput->q, &QAudioOutput::deviceChanged, this, &MFPlayerSession::updateOutputRouting);
- connect(m_audioOutput->q, &QAudioOutput::volumeChanged, this, &MFPlayerSession::setVolume);
- connect(m_audioOutput->q, &QAudioOutput::mutedChanged, this, &MFPlayerSession::setMuted);
- }
-}
-
-void MFPlayerSession::updateOutputRouting()
-{
- int currentAudioTrack = m_trackInfo[QPlatformMediaPlayer::AudioStream].currentIndex;
- if (currentAudioTrack > -1)
- setActiveTrack(QPlatformMediaPlayer::AudioStream, currentAudioTrack);
-}
-
-void MFPlayerSession::setVideoSink(QVideoSink *sink)
-{
- m_videoRendererControl->setSink(sink);
-}
-
-void MFPlayerSession::setActiveTrack(QPlatformMediaPlayer::TrackType type, int index)
-{
- if (!m_session)
- return;
-
- // Only audio track selection is currently supported.
- if (type != QPlatformMediaPlayer::AudioStream)
- return;
-
- const auto &nativeIndexes = m_trackInfo[type].nativeIndexes;
-
- if (index < -1 || index >= nativeIndexes.count())
- return;
-
- IMFTopology *topology = nullptr;
-
- if (SUCCEEDED(m_session->GetFullTopology(MFSESSION_GETFULLTOPOLOGY_CURRENT, 0, &topology))) {
-
- m_restorePosition = position() * 10000;
-
- if (m_state.command == CmdStart)
- stop();
-
- if (m_trackInfo[type].outputNodeId != -1) {
- IMFTopologyNode *node = nullptr;
- if (SUCCEEDED(topology->GetNodeByID(m_trackInfo[type].outputNodeId, &node))) {
- topology->RemoveNode(node);
- node->Release();
- m_trackInfo[type].outputNodeId = -1;
- }
- }
- if (m_trackInfo[type].sourceNodeId != -1) {
- IMFTopologyNode *node = nullptr;
- if (SUCCEEDED(topology->GetNodeByID(m_trackInfo[type].sourceNodeId, &node))) {
- topology->RemoveNode(node);
- node->Release();
- m_trackInfo[type].sourceNodeId = -1;
- }
- }
-
- IMFMediaSource *mediaSource = m_sourceResolver->mediaSource();
-
- IMFPresentationDescriptor *sourcePD = nullptr;
- if (SUCCEEDED(mediaSource->CreatePresentationDescriptor(&sourcePD))) {
-
- if (m_trackInfo[type].currentIndex >= 0 && m_trackInfo[type].currentIndex < nativeIndexes.count())
- sourcePD->DeselectStream(nativeIndexes.at(m_trackInfo[type].currentIndex));
-
- m_trackInfo[type].currentIndex = index;
-
- if (index == -1) {
- m_session->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
- } else {
- int nativeIndex = nativeIndexes.at(index);
- sourcePD->SelectStream(nativeIndex);
-
- IMFStreamDescriptor *streamDesc = nullptr;
- BOOL selected = FALSE;
-
- if (SUCCEEDED(sourcePD->GetStreamDescriptorByIndex(nativeIndex, &selected, &streamDesc))) {
- IMFTopologyNode *sourceNode = addSourceNode(topology, mediaSource, sourcePD, streamDesc);
- if (sourceNode) {
- IMFTopologyNode *outputNode = addOutputNode(MFPlayerSession::Audio, topology, 0);
- if (outputNode) {
- if (SUCCEEDED(sourceNode->ConnectOutput(0, outputNode, 0))) {
- sourceNode->GetTopoNodeID(&m_trackInfo[type].sourceNodeId);
- outputNode->GetTopoNodeID(&m_trackInfo[type].outputNodeId);
- m_session->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
- }
- outputNode->Release();
- }
- sourceNode->Release();
- }
- streamDesc->Release();
- }
- }
- m_updatingTopology = true;
- sourcePD->Release();
- }
- topology->Release();
- }
-}
-
-int MFPlayerSession::activeTrack(QPlatformMediaPlayer::TrackType type)
-{
- if (type < 0 || type >= QPlatformMediaPlayer::NTrackTypes)
- return -1;
- return m_trackInfo[type].currentIndex;
-}
-
-int MFPlayerSession::trackCount(QPlatformMediaPlayer::TrackType type)
-{
- if (type < 0 || type >= QPlatformMediaPlayer::NTrackTypes)
- return -1;
- return m_trackInfo[type].metaData.count();
-}
-
-QMediaMetaData MFPlayerSession::trackMetaData(QPlatformMediaPlayer::TrackType type, int trackNumber)
-{
- if (type < 0 || type >= QPlatformMediaPlayer::NTrackTypes)
- return {};
-
- if (trackNumber < 0 || trackNumber >= m_trackInfo[type].metaData.count())
- return {};
-
- return m_trackInfo[type].metaData.at(trackNumber);
-}
-
diff --git a/src/multimedia/platform/windows/player/mfplayersession_p.h b/src/multimedia/platform/windows/player/mfplayersession_p.h
deleted file mode 100644
index 3aafedb86..000000000
--- a/src/multimedia/platform/windows/player/mfplayersession_p.h
+++ /dev/null
@@ -1,275 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFPLAYERSESSION_H
-#define MFPLAYERSESSION_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 <mfapi.h>
-#include <mfidl.h>
-
-#include "qmediaplayer.h"
-#include "qmediatimerange.h"
-
-#include <QtCore/qcoreevent.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qwaitcondition.h>
-#include <QtMultimedia/qaudioformat.h>
-#include <QtMultimedia/qvideoframeformat.h>
-#include <qaudiodevice.h>
-#include <qtimer.h>
-#include "mfplayercontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-class QUrl;
-QT_END_NAMESPACE
-
-QT_USE_NAMESPACE
-
-class SourceResolver;
-class MFVideoRendererControl;
-class MFPlayerControl;
-class MFPlayerService;
-class AudioSampleGrabberCallback;
-class MFTransform;
-
-class MFPlayerSession : public QObject, public IMFAsyncCallback
-{
- Q_OBJECT
- friend class SourceResolver;
-public:
- MFPlayerSession(MFPlayerControl *playerControl = 0);
- ~MFPlayerSession();
-
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
-
- STDMETHODIMP_(ULONG) AddRef(void);
-
- STDMETHODIMP_(ULONG) Release(void);
-
- STDMETHODIMP Invoke(IMFAsyncResult *pResult);
-
- STDMETHODIMP GetParameters(DWORD *pdwFlags, DWORD *pdwQueue)
- {
- Q_UNUSED(pdwFlags);
- Q_UNUSED(pdwQueue);
- return E_NOTIMPL;
- }
-
- void load(const QUrl &media, QIODevice *stream);
- void stop(bool immediate = false);
- void start();
- void pause();
-
- QMediaPlayer::MediaStatus status() const;
- qint64 position();
- void setPosition(qint64 position);
- qreal playbackRate() const;
- void setPlaybackRate(qreal rate);
- float bufferProgress();
- QMediaTimeRange availablePlaybackRanges();
-
- void changeStatus(QMediaPlayer::MediaStatus newStatus);
-
- void close();
-
- void setAudioOutput(QPlatformAudioOutput *device);
-
- QMediaMetaData metaData() const { return m_metaData; }
-
- void setVideoSink(QVideoSink *sink);
-
- void setActiveTrack(QPlatformMediaPlayer::TrackType type, int index);
- int activeTrack(QPlatformMediaPlayer::TrackType type);
- int trackCount(QPlatformMediaPlayer::TrackType);
- QMediaMetaData trackMetaData(QPlatformMediaPlayer::TrackType type, int trackNumber);
-
- void statusChanged() { if (m_playerControl) m_playerControl->handleStatusChanged(); }
- void tracksChanged() { if (m_playerControl) m_playerControl->handleTracksChanged(); }
- void audioAvailable() { if (m_playerControl) m_playerControl->handleAudioAvailable(); }
- void videoAvailable() { if (m_playerControl) m_playerControl->handleVideoAvailable(); }
- void durationUpdate(qint64 duration) { if (m_playerControl) m_playerControl->handleDurationUpdate(duration); }
- void seekableUpdate(bool seekable) { if (m_playerControl) m_playerControl->handleSeekableUpdate(seekable); }
- void error(QMediaPlayer::Error error, QString errorString, bool isFatal) { if (m_playerControl) m_playerControl->handleError(error, errorString, isFatal); }
- void playbackRateChanged(qreal rate) { if (m_playerControl) m_playerControl->playbackRateChanged(rate); }
- void bufferProgressChanged(float percentFilled) { if (m_playerControl) m_playerControl->bufferProgressChanged(percentFilled); }
- void metaDataChanged() { if (m_playerControl) m_playerControl->metaDataChanged(); }
- void positionChanged(qint64 position) { if (m_playerControl) m_playerControl->positionChanged(position); }
-
-public Q_SLOTS:
- void setVolume(float volume);
- void setMuted(bool muted);
-
-Q_SIGNALS:
- void sessionEvent(IMFMediaEvent *sessionEvent);
-
-private Q_SLOTS:
- void handleMediaSourceReady();
- void handleSessionEvent(IMFMediaEvent *sessionEvent);
- void handleSourceError(long hr);
- void updateOutputRouting();
-
-private:
- long m_cRef;
- MFPlayerControl *m_playerControl = nullptr;
- MFVideoRendererControl *m_videoRendererControl = nullptr;
- IMFMediaSession *m_session;
- IMFPresentationClock *m_presentationClock;
- IMFRateControl *m_rateControl;
- IMFRateSupport *m_rateSupport;
- IMFAudioStreamVolume *m_volumeControl;
- IPropertyStore *m_netsourceStatistics;
- qint64 m_position = 0;
- qint64 m_restorePosition = -1;
- UINT64 m_duration = 0;
- bool m_updatingTopology = false;
-
- enum Command
- {
- CmdNone = 0,
- CmdStop,
- CmdStart,
- CmdPause,
- CmdSeek,
- CmdSeekResume,
- CmdStartAndSeek
- };
-
- void clear();
- void setPositionInternal(qint64 position, Command requestCmd);
- void setPlaybackRateInternal(qreal rate);
- void commitRateChange(qreal rate, BOOL isThin);
- bool canScrub() const;
- void scrub(bool enableScrub);
- bool m_scrubbing;
- float m_restoreRate;
-
- SourceResolver *m_sourceResolver;
- HANDLE m_hCloseEvent;
- bool m_closing;
-
- enum MediaType
- {
- Unknown = 0,
- Audio = 1,
- Video = 2,
- };
- DWORD m_mediaTypes;
-
- enum PendingState
- {
- NoPending = 0,
- CmdPending,
- SeekPending,
- };
-
- struct SeekState
- {
- void setCommand(Command cmd) {
- prevCmd = command;
- command = cmd;
- }
- Command command;
- Command prevCmd;
- float rate; // Playback rate
- BOOL isThin; // Thinned playback?
- qint64 start; // Start position
- };
- SeekState m_state; // Current nominal state.
- SeekState m_request; // Pending request.
- PendingState m_pendingState;
- float m_pendingRate;
- void updatePendingCommands(Command command);
-
- struct TrackInfo
- {
- QList<QMediaMetaData> metaData;
- QList<int> nativeIndexes;
- int currentIndex = -1;
- TOPOID sourceNodeId = -1;
- TOPOID outputNodeId = -1;
- };
- TrackInfo m_trackInfo[QPlatformMediaPlayer::NTrackTypes];
-
- QMediaPlayer::MediaStatus m_status;
- bool m_canScrub;
- float m_volume = 1.;
- bool m_muted = false;
-
- QPlatformAudioOutput *m_audioOutput = nullptr;
- QMediaMetaData m_metaData;
-
- void setVolumeInternal(float volume);
-
- void createSession();
- void setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD);
- bool getStreamInfo(IMFStreamDescriptor *stream, MFPlayerSession::MediaType *type, QString *name, QString *language) const;
- IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source,
- IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc);
- IMFTopologyNode* addOutputNode(MediaType mediaType, IMFTopology* topology, DWORD sinkID);
-
- bool addAudioSampleGrabberNode(IMFTopology* topology);
- bool setupAudioSampleGrabber(IMFTopology *topology, IMFTopologyNode *sourceNode, IMFTopologyNode *outputNode);
- QAudioFormat audioFormatForMFMediaType(IMFMediaType *mediaType) const;
- // ### Below can be used to monitor the audio channel. Currently unused.
- AudioSampleGrabberCallback *m_audioSampleGrabber;
- IMFTopologyNode *m_audioSampleGrabberNode;
-
- IMFTopology *insertMFT(IMFTopology *topology, TOPOID outputNodeId);
- bool insertResizer(IMFTopology *topology);
- void insertColorConverter(IMFTopology *topology, TOPOID outputNodeId);
- // ### Below can be used to monitor the video channel. Functionality currently unused.
- MFTransform *m_videoProbeMFT;
-
- QTimer m_signalPositionChangeTimer;
-};
-
-
-#endif
diff --git a/src/multimedia/platform/windows/player/mftvideo.cpp b/src/multimedia/platform/windows/player/mftvideo.cpp
deleted file mode 100644
index 5028bd053..000000000
--- a/src/multimedia/platform/windows/player/mftvideo.cpp
+++ /dev/null
@@ -1,725 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mftvideo_p.h"
-#include <private/qmemoryvideobuffer_p.h>
-#include <private/qwindowsmultimediautils_p.h>
-#include <mferror.h>
-#include <strmif.h>
-#include <uuids.h>
-#include <InitGuid.h>
-#include <d3d9.h>
-#include <qdebug.h>
-
-// This MFT sends all samples it processes to connected video probes.
-// Sample is sent to probes in ProcessInput.
-// In ProcessOutput this MFT simply returns the original sample.
-
-// The implementation is based on a boilerplate from the MF SDK example.
-
-MFTransform::MFTransform():
- m_cRef(1),
- m_inputType(0),
- m_outputType(0),
- m_sample(0),
- m_videoSinkTypeHandler(0),
- m_bytesPerLine(0)
-{
-}
-
-MFTransform::~MFTransform()
-{
- if (m_inputType)
- m_inputType->Release();
-
- if (m_outputType)
- m_outputType->Release();
-
- if (m_videoSinkTypeHandler)
- m_videoSinkTypeHandler->Release();
-}
-
-//void MFTransform::addProbe(MFVideoProbeControl *probe)
-//{
-// QMutexLocker locker(&m_videoProbeMutex);
-
-// if (m_videoProbes.contains(probe))
-// return;
-
-// m_videoProbes.append(probe);
-//}
-
-//void MFTransform::removeProbe(MFVideoProbeControl *probe)
-//{
-// QMutexLocker locker(&m_videoProbeMutex);
-// m_videoProbes.removeOne(probe);
-//}
-
-void MFTransform::setVideoSink(IUnknown *videoSink)
-{
- // This transform supports the same input types as the video sink.
- // Store its type handler interface in order to report the correct supported types.
-
- if (m_videoSinkTypeHandler) {
- m_videoSinkTypeHandler->Release();
- m_videoSinkTypeHandler = NULL;
- }
-
- if (videoSink)
- videoSink->QueryInterface(IID_PPV_ARGS(&m_videoSinkTypeHandler));
-}
-
-STDMETHODIMP MFTransform::QueryInterface(REFIID riid, void** ppv)
-{
- if (!ppv)
- return E_POINTER;
- if (riid == IID_IMFTransform) {
- *ppv = static_cast<IMFTransform*>(this);
- } else if (riid == IID_IUnknown) {
- *ppv = static_cast<IUnknown*>(this);
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) MFTransform::AddRef()
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) MFTransform::Release()
-{
- ULONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0) {
- delete this;
- }
- return cRef;
-}
-
-STDMETHODIMP MFTransform::GetStreamLimits(DWORD *pdwInputMinimum, DWORD *pdwInputMaximum, DWORD *pdwOutputMinimum, DWORD *pdwOutputMaximum)
-{
- if (!pdwInputMinimum || !pdwInputMaximum || !pdwOutputMinimum || !pdwOutputMaximum)
- return E_POINTER;
- *pdwInputMinimum = 1;
- *pdwInputMaximum = 1;
- *pdwOutputMinimum = 1;
- *pdwOutputMaximum = 1;
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::GetStreamCount(DWORD *pcInputStreams, DWORD *pcOutputStreams)
-{
- if (!pcInputStreams || !pcOutputStreams)
- return E_POINTER;
-
- *pcInputStreams = 1;
- *pcOutputStreams = 1;
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::GetStreamIDs(DWORD dwInputIDArraySize, DWORD *pdwInputIDs, DWORD dwOutputIDArraySize, DWORD *pdwOutputIDs)
-{
- // streams are numbered consecutively
- Q_UNUSED(dwInputIDArraySize);
- Q_UNUSED(pdwInputIDs);
- Q_UNUSED(dwOutputIDArraySize);
- Q_UNUSED(pdwOutputIDs);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::GetInputStreamInfo(DWORD dwInputStreamID, MFT_INPUT_STREAM_INFO *pStreamInfo)
-{
- QMutexLocker locker(&m_mutex);
-
- if (dwInputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (!pStreamInfo)
- return E_POINTER;
-
- pStreamInfo->cbSize = 0;
- pStreamInfo->hnsMaxLatency = 0;
- pStreamInfo->cbMaxLookahead = 0;
- pStreamInfo->cbAlignment = 0;
- pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES
- | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
- | MFT_INPUT_STREAM_PROCESSES_IN_PLACE;
-
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::GetOutputStreamInfo(DWORD dwOutputStreamID, MFT_OUTPUT_STREAM_INFO *pStreamInfo)
-{
- QMutexLocker locker(&m_mutex);
-
- if (dwOutputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (!pStreamInfo)
- return E_POINTER;
-
- pStreamInfo->cbSize = 0;
- pStreamInfo->cbAlignment = 0;
- pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES
- | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
- | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
- | MFT_OUTPUT_STREAM_DISCARDABLE;
-
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::GetAttributes(IMFAttributes **pAttributes)
-{
- // This MFT does not support attributes.
- Q_UNUSED(pAttributes);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::GetInputStreamAttributes(DWORD dwInputStreamID, IMFAttributes **pAttributes)
-{
- // This MFT does not support input stream attributes.
- Q_UNUSED(dwInputStreamID);
- Q_UNUSED(pAttributes);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::GetOutputStreamAttributes(DWORD dwOutputStreamID, IMFAttributes **pAttributes)
-{
- // This MFT does not support output stream attributes.
- Q_UNUSED(dwOutputStreamID);
- Q_UNUSED(pAttributes);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::DeleteInputStream(DWORD dwStreamID)
-{
- // This MFT has a fixed number of input streams.
- Q_UNUSED(dwStreamID);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::AddInputStreams(DWORD cStreams, DWORD *adwStreamIDs)
-{
- // This MFT has a fixed number of input streams.
- Q_UNUSED(cStreams);
- Q_UNUSED(adwStreamIDs);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::GetInputAvailableType(DWORD dwInputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
-{
- // We support the same input types as the video sink
- if (!m_videoSinkTypeHandler)
- return E_NOTIMPL;
-
- if (dwInputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (!ppType)
- return E_POINTER;
-
- return m_videoSinkTypeHandler->GetMediaTypeByIndex(dwTypeIndex, ppType);
-}
-
-STDMETHODIMP MFTransform::GetOutputAvailableType(DWORD dwOutputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
-{
- // Since we don't modify the samples, the output type must be the same as the input type.
- // Report our input type as the only available output type.
-
- if (dwOutputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (!ppType)
- return E_POINTER;
-
- // Input type must be set first
- if (!m_inputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- if (dwTypeIndex > 0)
- return MF_E_NO_MORE_TYPES;
-
- // Return a copy to make sure our type is not modified
- if (FAILED(MFCreateMediaType(ppType)))
- return E_OUTOFMEMORY;
-
- return m_inputType->CopyAllItems(*ppType);
-}
-
-STDMETHODIMP MFTransform::SetInputType(DWORD dwInputStreamID, IMFMediaType *pType, DWORD dwFlags)
-{
- if (dwInputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- QMutexLocker locker(&m_mutex);
-
- if (m_sample)
- return MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
-
- if (!isMediaTypeSupported(pType))
- return MF_E_INVALIDMEDIATYPE;
-
- if (dwFlags == MFT_SET_TYPE_TEST_ONLY)
- return pType ? S_OK : E_POINTER;
-
- if (m_inputType) {
- m_inputType->Release();
- // Input type has changed, discard output type (if it's set) so it's reset later on
- DWORD flags = 0;
- if (m_outputType && m_outputType->IsEqual(pType, &flags) != S_OK) {
- m_outputType->Release();
- m_outputType = 0;
- }
- }
-
- m_inputType = pType;
-
- if (m_inputType)
- m_inputType->AddRef();
-
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::SetOutputType(DWORD dwOutputStreamID, IMFMediaType *pType, DWORD dwFlags)
-{
- if (dwOutputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (dwFlags == MFT_SET_TYPE_TEST_ONLY && !pType)
- return E_POINTER;
-
- QMutexLocker locker(&m_mutex);
-
- // Input type must be set first
- if (!m_inputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- if (m_sample)
- return MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
-
- DWORD flags = 0;
- if (pType && m_inputType->IsEqual(pType, &flags) != S_OK)
- return MF_E_INVALIDMEDIATYPE;
-
- if (dwFlags == MFT_SET_TYPE_TEST_ONLY)
- return pType ? S_OK : E_POINTER;
-
- if (m_outputType)
- m_outputType->Release();
-
- m_outputType = pType;
-
- if (m_outputType) {
- m_outputType->AddRef();
- m_format = videoFormatForMFMediaType(m_outputType, &m_bytesPerLine);
- }
-
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::GetInputCurrentType(DWORD dwInputStreamID, IMFMediaType **ppType)
-{
- if (dwInputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (ppType == NULL)
- return E_POINTER;
-
- QMutexLocker locker(&m_mutex);
-
- if (!m_inputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- // Return a copy to make sure our type is not modified
- if (FAILED(MFCreateMediaType(ppType)))
- return E_OUTOFMEMORY;
-
- return m_inputType->CopyAllItems(*ppType);
-}
-
-STDMETHODIMP MFTransform::GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaType **ppType)
-{
- if (dwOutputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (ppType == NULL)
- return E_POINTER;
-
- QMutexLocker locker(&m_mutex);
-
- if (!m_outputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- // Return a copy to make sure our type is not modified
- if (FAILED(MFCreateMediaType(ppType)))
- return E_OUTOFMEMORY;
-
- return m_outputType->CopyAllItems(*ppType);
-}
-
-STDMETHODIMP MFTransform::GetInputStatus(DWORD dwInputStreamID, DWORD *pdwFlags)
-{
- if (dwInputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (!pdwFlags)
- return E_POINTER;
-
- QMutexLocker locker(&m_mutex);
-
- if (!m_inputType || !m_outputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- if (m_sample)
- *pdwFlags = 0;
- else
- *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;
-
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::GetOutputStatus(DWORD *pdwFlags)
-{
- if (!pdwFlags)
- return E_POINTER;
-
- QMutexLocker locker(&m_mutex);
-
- if (!m_inputType || !m_outputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- if (m_sample)
- *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
- else
- *pdwFlags = 0;
-
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::SetOutputBounds(LONGLONG hnsLowerBound, LONGLONG hnsUpperBound)
-{
- Q_UNUSED(hnsLowerBound);
- Q_UNUSED(hnsUpperBound);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::ProcessEvent(DWORD dwInputStreamID, IMFMediaEvent *pEvent)
-{
- // This MFT ignores all events, and the pipeline should send all events downstream.
- Q_UNUSED(dwInputStreamID);
- Q_UNUSED(pEvent);
- return E_NOTIMPL;
-}
-
-STDMETHODIMP MFTransform::ProcessMessage(MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam)
-{
- Q_UNUSED(ulParam);
-
- HRESULT hr = S_OK;
-
- switch (eMessage)
- {
- case MFT_MESSAGE_COMMAND_FLUSH:
- hr = OnFlush();
- break;
-
- case MFT_MESSAGE_COMMAND_DRAIN:
- // Drain: Tells the MFT not to accept any more input until
- // all of the pending output has been processed. That is our
- // default behevior already, so there is nothing to do.
- break;
-
- case MFT_MESSAGE_SET_D3D_MANAGER:
- // The pipeline should never send this message unless the MFT
- // has the MF_SA_D3D_AWARE attribute set to TRUE. However, if we
- // do get this message, it's invalid and we don't implement it.
- hr = E_NOTIMPL;
- break;
-
- // The remaining messages do not require any action from this MFT.
- case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
- case MFT_MESSAGE_NOTIFY_END_STREAMING:
- case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
- case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
- break;
- }
-
- return hr;
-}
-
-STDMETHODIMP MFTransform::ProcessInput(DWORD dwInputStreamID, IMFSample *pSample, DWORD dwFlags)
-{
- if (dwInputStreamID > 0)
- return MF_E_INVALIDSTREAMNUMBER;
-
- if (dwFlags != 0)
- return E_INVALIDARG; // dwFlags is reserved and must be zero.
-
- QMutexLocker locker(&m_mutex);
-
- if (!m_inputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- if (m_sample)
- return MF_E_NOTACCEPTING;
-
- // Validate the number of buffers. There should only be a single buffer to hold the video frame.
- DWORD dwBufferCount = 0;
- HRESULT hr = pSample->GetBufferCount(&dwBufferCount);
- if (FAILED(hr))
- return hr;
-
- if (dwBufferCount == 0)
- return E_FAIL;
-
- if (dwBufferCount > 1)
- return MF_E_SAMPLE_HAS_TOO_MANY_BUFFERS;
-
- m_sample = pSample;
- m_sample->AddRef();
-
- QMutexLocker lockerProbe(&m_videoProbeMutex);
-
-// if (!m_videoProbes.isEmpty()) {
-// QVideoFrame frame = makeVideoFrame();
-
-// for (MFVideoProbeControl* probe : qAsConst(m_videoProbes))
-// probe->bufferProbed(frame);
-// }
-
- return S_OK;
-}
-
-STDMETHODIMP MFTransform::ProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER *pOutputSamples, DWORD *pdwStatus)
-{
- if (pOutputSamples == NULL || pdwStatus == NULL)
- return E_POINTER;
-
- if (cOutputBufferCount != 1)
- return E_INVALIDARG;
-
- QMutexLocker locker(&m_mutex);
-
- if (!m_inputType)
- return MF_E_TRANSFORM_TYPE_NOT_SET;
-
- if (!m_outputType) {
- pOutputSamples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
- return MF_E_TRANSFORM_STREAM_CHANGE;
- }
-
- IMFMediaBuffer *input = NULL;
- IMFMediaBuffer *output = NULL;
-
- if (dwFlags == MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER)
- goto done;
- else if (dwFlags != 0)
- return E_INVALIDARG;
-
- if (!m_sample)
- return MF_E_TRANSFORM_NEED_MORE_INPUT;
-
- // Since the MFT_OUTPUT_STREAM_PROVIDES_SAMPLES flag is set, the client
- // should not be providing samples here
- if (pOutputSamples[0].pSample != NULL)
- return E_INVALIDARG;
-
- pOutputSamples[0].pSample = m_sample;
- pOutputSamples[0].pSample->AddRef();
-
- // Send video frame to probes
- // We do it here (instead of inside ProcessInput) to make sure samples discarded by the renderer
- // are not sent.
- m_videoProbeMutex.lock();
-// if (!m_videoProbes.isEmpty()) {
-// QVideoFrame frame = makeVideoFrame();
-
-// for (MFVideoProbeControl* probe : qAsConst(m_videoProbes))
-// probe->bufferProbed(frame);
-// }
- m_videoProbeMutex.unlock();
-
-done:
- pOutputSamples[0].dwStatus = 0;
- *pdwStatus = 0;
-
- m_sample->Release();
- m_sample = 0;
-
- if (input)
- input->Release();
- if (output)
- output->Release();
-
- return S_OK;
-}
-
-HRESULT MFTransform::OnFlush()
-{
- QMutexLocker locker(&m_mutex);
-
- if (m_sample) {
- m_sample->Release();
- m_sample = 0;
- }
- return S_OK;
-}
-
-QVideoFrameFormat MFTransform::videoFormatForMFMediaType(IMFMediaType *mediaType, int *bytesPerLine)
-{
- UINT32 stride;
- if (FAILED(mediaType->GetUINT32(MF_MT_DEFAULT_STRIDE, &stride))) {
- *bytesPerLine = 0;
- return QVideoFrameFormat();
- }
-
- *bytesPerLine = (int)stride;
-
- QSize size;
- UINT32 width, height;
- if (FAILED(MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height)))
- return QVideoFrameFormat();
-
- size.setWidth(width);
- size.setHeight(height);
-
- GUID subtype = GUID_NULL;
- if (FAILED(mediaType->GetGUID(MF_MT_SUBTYPE, &subtype)))
- return QVideoFrameFormat();
-
- QVideoFrameFormat::PixelFormat pixelFormat =
- QWindowsMultimediaUtils::pixelFormatFromMediaSubtype(subtype);
- QVideoFrameFormat format(size, pixelFormat);
-
- quint32 num, den;
- if (SUCCEEDED(MFGetAttributeRatio(mediaType, MF_MT_FRAME_RATE, &num, &den))) {
- format.setFrameRate(qreal(num)/den);
- }
-
- return format;
-}
-
-QVideoFrame MFTransform::makeVideoFrame()
-{
- QVideoFrame frame;
-
- if (!m_format.isValid())
- return frame;
-
- IMFMediaBuffer *buffer = 0;
-
- do {
- if (FAILED(m_sample->ConvertToContiguousBuffer(&buffer)))
- break;
-
- QByteArray array = dataFromBuffer(buffer, m_format.frameHeight(), &m_bytesPerLine);
- if (array.isEmpty())
- break;
-
- // Wrapping IMFSample or IMFMediaBuffer in a QVideoFrame is not possible because we cannot hold
- // IMFSample for a "long" time without affecting the rest of the topology.
- // If IMFSample is held for more than 5 frames decoder starts to reuse it even though it hasn't been released it yet.
- // That is why we copy data from IMFMediaBuffer here.
- frame = QVideoFrame(new QMemoryVideoBuffer(array, m_bytesPerLine), m_format);
-
- // WMF uses 100-nanosecond units, Qt uses microseconds
- LONGLONG startTime = -1;
- if (SUCCEEDED(m_sample->GetSampleTime(&startTime))) {
- frame.setStartTime(startTime * 0.1);
-
- LONGLONG duration = -1;
- if (SUCCEEDED(m_sample->GetSampleDuration(&duration)))
- frame.setEndTime((startTime + duration) * 0.1);
- }
- } while (false);
-
- if (buffer)
- buffer->Release();
-
- return frame;
-}
-
-QByteArray MFTransform::dataFromBuffer(IMFMediaBuffer *buffer, int height, int *bytesPerLine)
-{
- QByteArray array;
- BYTE *bytes;
- DWORD length;
- HRESULT hr = buffer->Lock(&bytes, NULL, &length);
- if (SUCCEEDED(hr)) {
- array = QByteArray((const char *)bytes, (int)length);
- buffer->Unlock();
- } else {
- // try to lock as Direct3DSurface
- IDirect3DSurface9 *surface = 0;
- do {
- if (FAILED(MFGetService(buffer, MR_BUFFER_SERVICE, IID_IDirect3DSurface9, (void**)&surface)))
- break;
-
- D3DLOCKED_RECT rect;
- if (FAILED(surface->LockRect(&rect, NULL, D3DLOCK_READONLY)))
- break;
-
- if (bytesPerLine)
- *bytesPerLine = (int)rect.Pitch;
-
- array = QByteArray((const char *)rect.pBits, rect.Pitch * height);
- surface->UnlockRect();
- } while (false);
-
- if (surface) {
- surface->Release();
- surface = 0;
- }
- }
-
- return array;
-}
-
-bool MFTransform::isMediaTypeSupported(IMFMediaType *type)
-{
- // If we don't have the video sink's type handler,
- // assume it supports anything...
- if (!m_videoSinkTypeHandler || !type)
- return true;
-
- return m_videoSinkTypeHandler->IsMediaTypeSupported(type, NULL) == S_OK;
-}
diff --git a/src/multimedia/platform/windows/player/mftvideo_p.h b/src/multimedia/platform/windows/player/mftvideo_p.h
deleted file mode 100644
index a8a0337cc..000000000
--- a/src/multimedia/platform/windows/player/mftvideo_p.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFTRANSFORM_H
-#define MFTRANSFORM_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 <mfapi.h>
-#include <mfidl.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmutex.h>
-#include <QtMultimedia/qvideoframeformat.h>
-
-QT_USE_NAMESPACE
-
-class MFVideoProbeControl;
-
-QT_BEGIN_NAMESPACE
-class QVideoFrame;
-QT_END_NAMESPACE
-
-class MFTransform: public IMFTransform
-{
-public:
- MFTransform();
- ~MFTransform();
-
- void addProbe(MFVideoProbeControl* probe);
- void removeProbe(MFVideoProbeControl* probe);
-
- void setVideoSink(IUnknown *videoSink);
-
- // IUnknown methods
- STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
-
- // IMFTransform methods
- STDMETHODIMP GetStreamLimits(DWORD *pdwInputMinimum, DWORD *pdwInputMaximum, DWORD *pdwOutputMinimum, DWORD *pdwOutputMaximum);
- STDMETHODIMP GetStreamCount(DWORD *pcInputStreams, DWORD *pcOutputStreams);
- STDMETHODIMP GetStreamIDs(DWORD dwInputIDArraySize, DWORD *pdwInputIDs, DWORD dwOutputIDArraySize, DWORD *pdwOutputIDs);
- STDMETHODIMP GetInputStreamInfo(DWORD dwInputStreamID, MFT_INPUT_STREAM_INFO *pStreamInfo);
- STDMETHODIMP GetOutputStreamInfo(DWORD dwOutputStreamID, MFT_OUTPUT_STREAM_INFO *pStreamInfo);
- STDMETHODIMP GetAttributes(IMFAttributes **pAttributes);
- STDMETHODIMP GetInputStreamAttributes(DWORD dwInputStreamID, IMFAttributes **pAttributes);
- STDMETHODIMP GetOutputStreamAttributes(DWORD dwOutputStreamID, IMFAttributes **pAttributes);
- STDMETHODIMP DeleteInputStream(DWORD dwStreamID);
- STDMETHODIMP AddInputStreams(DWORD cStreams, DWORD *adwStreamIDs);
- STDMETHODIMP GetInputAvailableType(DWORD dwInputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType);
- STDMETHODIMP GetOutputAvailableType(DWORD dwOutputStreamID,DWORD dwTypeIndex, IMFMediaType **ppType);
- STDMETHODIMP SetInputType(DWORD dwInputStreamID, IMFMediaType *pType, DWORD dwFlags);
- STDMETHODIMP SetOutputType(DWORD dwOutputStreamID, IMFMediaType *pType, DWORD dwFlags);
- STDMETHODIMP GetInputCurrentType(DWORD dwInputStreamID, IMFMediaType **ppType);
- STDMETHODIMP GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaType **ppType);
- STDMETHODIMP GetInputStatus(DWORD dwInputStreamID, DWORD *pdwFlags);
- STDMETHODIMP GetOutputStatus(DWORD *pdwFlags);
- STDMETHODIMP SetOutputBounds(LONGLONG hnsLowerBound, LONGLONG hnsUpperBound);
- STDMETHODIMP ProcessEvent(DWORD dwInputStreamID, IMFMediaEvent *pEvent);
- STDMETHODIMP ProcessMessage(MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam);
- STDMETHODIMP ProcessInput(DWORD dwInputStreamID, IMFSample *pSample, DWORD dwFlags);
- STDMETHODIMP ProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER *pOutputSamples, DWORD *pdwStatus);
-
-private:
- HRESULT OnFlush();
- static QVideoFrameFormat videoFormatForMFMediaType(IMFMediaType *mediaType, int *bytesPerLine);
- QVideoFrame makeVideoFrame();
- QByteArray dataFromBuffer(IMFMediaBuffer *buffer, int height, int *bytesPerLine);
- bool isMediaTypeSupported(IMFMediaType *type);
-
- long m_cRef;
- IMFMediaType *m_inputType;
- IMFMediaType *m_outputType;
- IMFSample *m_sample;
- QMutex m_mutex;
-
- IMFMediaTypeHandler *m_videoSinkTypeHandler;
-
-// QList<MFVideoProbeControl*> m_videoProbes;
- QMutex m_videoProbeMutex;
-
- QVideoFrameFormat m_format;
- int m_bytesPerLine;
-};
-
-#endif
diff --git a/src/multimedia/platform/windows/player/mfvideorenderercontrol.cpp b/src/multimedia/platform/windows/player/mfvideorenderercontrol.cpp
deleted file mode 100644
index a2a83d1cb..000000000
--- a/src/multimedia/platform/windows/player/mfvideorenderercontrol.cpp
+++ /dev/null
@@ -1,2318 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mfvideorenderercontrol_p.h"
-#include "mfactivate_p.h"
-
-#include "evrcustompresenter_p.h"
-
-#include <private/qplatformvideosink_p.h>
-#include <private/qabstractvideobuffer_p.h>
-#include <qvideosink.h>
-#include <qvideoframeformat.h>
-#include <qtcore/qtimer.h>
-#include <qtcore/qmutex.h>
-#include <qtcore/qcoreevent.h>
-#include <qtcore/qcoreapplication.h>
-#include <qtcore/qthread.h>
-#include "guiddef.h"
-#include <qtcore/qdebug.h>
-
-//#define DEBUG_MEDIAFOUNDATION
-#define PAD_TO_DWORD(x) (((x) + 3) & ~3)
-
-namespace
-{
- class MediaSampleVideoBuffer : public QAbstractVideoBuffer
- {
- public:
- MediaSampleVideoBuffer(IMFMediaBuffer *buffer, int bytesPerLine)
- : QAbstractVideoBuffer(QVideoFrame::NoHandle)
- , m_buffer(buffer)
- , m_bytesPerLine(bytesPerLine)
- , m_mapMode(QVideoFrame::NotMapped)
- {
- buffer->AddRef();
- }
-
- ~MediaSampleVideoBuffer()
- {
- m_buffer->Release();
- }
-
- MapData map(QVideoFrame::MapMode mode) override
- {
- MapData mapData;
- if (m_mapMode == QVideoFrame::NotMapped && mode != QVideoFrame::NotMapped) {
- BYTE *bytes;
- DWORD length;
- HRESULT hr = m_buffer->Lock(&bytes, NULL, &length);
- if (SUCCEEDED(hr)) {
- mapData.nPlanes = 1;
- mapData.bytesPerLine[0] = m_bytesPerLine;
- mapData.data[0] = reinterpret_cast<uchar *>(bytes);
- mapData.size[0] = qsizetype(length);
- m_mapMode = mode;
- } else {
- qWarning("Faild to lock mf buffer!");
- }
- }
- return mapData;
- }
-
- void unmap() override
- {
- if (m_mapMode == QVideoFrame::NotMapped)
- return;
- m_mapMode = QVideoFrame::NotMapped;
- m_buffer->Unlock();
- }
-
- QVideoFrame::MapMode mapMode() const override
- {
- return m_mapMode;
- }
-
- private:
- IMFMediaBuffer *m_buffer;
- int m_bytesPerLine;
- QVideoFrame::MapMode m_mapMode;
- };
-
- // Custom interface for handling IMFStreamSink::PlaceMarker calls asynchronously.
- MIDL_INTERFACE("a3ff32de-1031-438a-8b47-82f8acda59b7")
- IMarker : public IUnknown
- {
- virtual STDMETHODIMP GetMarkerType(MFSTREAMSINK_MARKER_TYPE *pType) = 0;
- virtual STDMETHODIMP GetMarkerValue(PROPVARIANT *pvar) = 0;
- virtual STDMETHODIMP GetContext(PROPVARIANT *pvar) = 0;
- };
-
- class Marker : public IMarker
- {
- public:
- static HRESULT Create(
- MFSTREAMSINK_MARKER_TYPE eMarkerType,
- const PROPVARIANT* pvarMarkerValue, // Can be NULL.
- const PROPVARIANT* pvarContextValue, // Can be NULL.
- IMarker **ppMarker)
- {
- if (ppMarker == NULL)
- return E_POINTER;
-
- HRESULT hr = S_OK;
- Marker *pMarker = new Marker(eMarkerType);
- if (pMarker == NULL)
- hr = E_OUTOFMEMORY;
-
- // Copy the marker data.
- if (SUCCEEDED(hr) && pvarMarkerValue)
- hr = PropVariantCopy(&pMarker->m_varMarkerValue, pvarMarkerValue);
-
- if (SUCCEEDED(hr) && pvarContextValue)
- hr = PropVariantCopy(&pMarker->m_varContextValue, pvarContextValue);
-
- if (SUCCEEDED(hr)) {
- *ppMarker = pMarker;
- (*ppMarker)->AddRef();
- }
-
- if (pMarker)
- pMarker->Release();
-
- return hr;
- }
-
- // IUnknown methods.
- STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
- {
- if (!ppv)
- return E_POINTER;
- if (iid == IID_IUnknown) {
- *ppv = static_cast<IUnknown*>(this);
- } else if (iid == __uuidof(IMarker)) {
- *ppv = static_cast<IMarker*>(this);
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef()
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- STDMETHODIMP_(ULONG) Release()
- {
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return cRef;
- }
-
- STDMETHODIMP GetMarkerType(MFSTREAMSINK_MARKER_TYPE *pType)
- {
- if (pType == NULL)
- return E_POINTER;
- *pType = m_eMarkerType;
- return S_OK;
- }
-
- STDMETHODIMP GetMarkerValue(PROPVARIANT *pvar)
- {
- if (pvar == NULL)
- return E_POINTER;
- return PropVariantCopy(pvar, &m_varMarkerValue);
- }
-
- STDMETHODIMP GetContext(PROPVARIANT *pvar)
- {
- if (pvar == NULL)
- return E_POINTER;
- return PropVariantCopy(pvar, &m_varContextValue);
- }
-
- protected:
- MFSTREAMSINK_MARKER_TYPE m_eMarkerType;
- PROPVARIANT m_varMarkerValue;
- PROPVARIANT m_varContextValue;
-
- private:
- long m_cRef;
-
- Marker(MFSTREAMSINK_MARKER_TYPE eMarkerType) : m_cRef(1), m_eMarkerType(eMarkerType)
- {
- PropVariantInit(&m_varMarkerValue);
- PropVariantInit(&m_varContextValue);
- }
-
- virtual ~Marker()
- {
- PropVariantClear(&m_varMarkerValue);
- PropVariantClear(&m_varContextValue);
- }
- };
-
- class MediaStream : public QObject, public IMFStreamSink, public IMFMediaTypeHandler
- {
- Q_OBJECT
- friend class MFVideoRendererControl;
- public:
- static const DWORD DEFAULT_MEDIA_STREAM_ID = 0x0;
-
- MediaStream(IMFMediaSink *parent, MFVideoRendererControl *rendererControl)
- : m_cRef(1)
- , m_eventQueue(0)
- , m_shutdown(false)
- , m_videoSink(0)
- , m_state(State_TypeNotSet)
- , m_currentFormatIndex(-1)
- , m_bytesPerLine(0)
- , m_workQueueId(0)
- , m_workQueueCB(this, &MediaStream::onDispatchWorkItem)
- , m_finalizeResult(0)
- , m_scheduledBuffer(0)
- , m_bufferStartTime(-1)
- , m_bufferDuration(-1)
- , m_presentationClock(0)
- , m_sampleRequested(false)
- , m_currentMediaType(0)
- , m_prerolling(false)
- , m_prerollTargetTime(0)
- , m_startTime(0)
- , m_rendererControl(rendererControl)
- , m_rate(1.f)
- {
- m_sink = parent;
-
- if (FAILED(MFCreateEventQueue(&m_eventQueue)))
- qWarning("Failed to create mf event queue!");
- if (FAILED(MFAllocateWorkQueue(&m_workQueueId)))
- qWarning("Failed to allocated mf work queue!");
- }
-
- ~MediaStream()
- {
- Q_ASSERT(m_shutdown);
- }
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)
- {
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFStreamSink) {
- *ppvObject = static_cast<IMFStreamSink*>(this);
- } else if (riid == IID_IMFMediaEventGenerator) {
- *ppvObject = static_cast<IMFMediaEventGenerator*>(this);
- } else if (riid == IID_IMFMediaTypeHandler) {
- *ppvObject = static_cast<IMFMediaTypeHandler*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(static_cast<IMFStreamSink*>(this));
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef(void)
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- STDMETHODIMP_(ULONG) Release(void)
- {
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return cRef;
- }
-
- //from IMFMediaEventGenerator
- STDMETHODIMP GetEvent(
- DWORD dwFlags,
- IMFMediaEvent **ppEvent)
- {
- // GetEvent can block indefinitely, so we don't hold the lock.
- // This requires some juggling with the event queue pointer.
- HRESULT hr = S_OK;
- IMFMediaEventQueue *queue = NULL;
-
- m_mutex.lock();
- if (m_shutdown)
- hr = MF_E_SHUTDOWN;
- if (SUCCEEDED(hr)) {
- queue = m_eventQueue;
- queue->AddRef();
- }
- m_mutex.unlock();
-
- // Now get the event.
- if (SUCCEEDED(hr)) {
- hr = queue->GetEvent(dwFlags, ppEvent);
- queue->Release();
- }
-
- return hr;
- }
-
- STDMETHODIMP BeginGetEvent(
- IMFAsyncCallback *pCallback,
- IUnknown *punkState)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_eventQueue->BeginGetEvent(pCallback, punkState);
- }
-
- STDMETHODIMP EndGetEvent(
- IMFAsyncResult *pResult,
- IMFMediaEvent **ppEvent)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_eventQueue->EndGetEvent(pResult, ppEvent);
- }
-
- STDMETHODIMP QueueEvent(
- MediaEventType met,
- REFGUID guidExtendedType,
- HRESULT hrStatus,
- const PROPVARIANT *pvValue)
- {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MediaStream::QueueEvent" << met;
-#endif
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_eventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue);
- }
-
- //from IMFStreamSink
- STDMETHODIMP GetMediaSink(
- IMFMediaSink **ppMediaSink)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- else if (!ppMediaSink)
- return E_INVALIDARG;
-
- m_sink->AddRef();
- *ppMediaSink = m_sink;
- return S_OK;
- }
-
- STDMETHODIMP GetIdentifier(
- DWORD *pdwIdentifier)
- {
- *pdwIdentifier = MediaStream::DEFAULT_MEDIA_STREAM_ID;
- return S_OK;
- }
-
- STDMETHODIMP GetMediaTypeHandler(
- IMFMediaTypeHandler **ppHandler)
- {
- LPVOID handler = NULL;
- HRESULT hr = QueryInterface(IID_IMFMediaTypeHandler, &handler);
- *ppHandler = (IMFMediaTypeHandler*)(handler);
- return hr;
- }
-
- STDMETHODIMP ProcessSample(
- IMFSample *pSample)
- {
- if (pSample == NULL)
- return E_INVALIDARG;
- HRESULT hr = S_OK;
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- if (!m_prerolling) {
- hr = validateOperation(OpProcessSample);
- if (FAILED(hr))
- return hr;
- }
-
- pSample->AddRef();
- m_sampleQueue.push_back(pSample);
-
- // Unless we are paused, start an async operation to dispatch the next sample.
- if (m_state != State_Paused)
- hr = queueAsyncOperation(OpProcessSample);
-
- return hr;
- }
-
- STDMETHODIMP PlaceMarker(
- MFSTREAMSINK_MARKER_TYPE eMarkerType,
- const PROPVARIANT *pvarMarkerValue,
- const PROPVARIANT *pvarContextValue)
- {
- HRESULT hr = S_OK;
- QMutexLocker locker(&m_mutex);
- IMarker *pMarker = NULL;
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- hr = validateOperation(OpPlaceMarker);
- if (FAILED(hr))
- return hr;
-
- // Create a marker object and put it on the sample queue.
- hr = Marker::Create(eMarkerType, pvarMarkerValue, pvarContextValue, &pMarker);
- if (FAILED(hr))
- return hr;
-
- m_sampleQueue.push_back(pMarker);
-
- // Unless we are paused, start an async operation to dispatch the next sample/marker.
- if (m_state != State_Paused)
- hr = queueAsyncOperation(OpPlaceMarker); // Increments ref count on pOp.
- return hr;
- }
-
- STDMETHODIMP Flush( void)
- {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MediaStream::Flush";
-#endif
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- // Note: Even though we are flushing data, we still need to send
- // any marker events that were queued.
- clearBufferCache();
- return processSamplesFromQueue(DropSamples);
- }
-
- //from IMFMediaTypeHandler
- STDMETHODIMP IsMediaTypeSupported(
- IMFMediaType *pMediaType,
- IMFMediaType **ppMediaType)
- {
- if (ppMediaType)
- *ppMediaType = NULL;
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- int index = getMediaTypeIndex(pMediaType);
- if (index < 0) {
- if (ppMediaType && m_mediaTypes.size() > 0) {
- *ppMediaType = m_mediaTypes[0];
- (*ppMediaType)->AddRef();
- }
- return MF_E_INVALIDMEDIATYPE;
- }
-
- BOOL compressed = TRUE;
- pMediaType->IsCompressedFormat(&compressed);
- if (compressed) {
- if (ppMediaType && (SUCCEEDED(MFCreateMediaType(ppMediaType)))) {
- (*ppMediaType)->CopyAllItems(pMediaType);
- (*ppMediaType)->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE);
- (*ppMediaType)->SetUINT32(MF_MT_COMPRESSED, FALSE);
- (*ppMediaType)->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
- }
- return MF_E_INVALIDMEDIATYPE;
- }
-
- return S_OK;
- }
-
- STDMETHODIMP GetMediaTypeCount(
- DWORD *pdwTypeCount)
- {
- if (pdwTypeCount == NULL)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- *pdwTypeCount = DWORD(m_mediaTypes.size());
- return S_OK;
- }
-
- STDMETHODIMP GetMediaTypeByIndex(
- DWORD dwIndex,
- IMFMediaType **ppType)
- {
- if (ppType == NULL)
- return E_INVALIDARG;
- HRESULT hr = S_OK;
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- hr = MF_E_SHUTDOWN;
-
- if (SUCCEEDED(hr)) {
- if (dwIndex >= DWORD(m_mediaTypes.size()))
- hr = MF_E_NO_MORE_TYPES;
- }
-
- if (SUCCEEDED(hr)) {
- *ppType = m_mediaTypes[dwIndex];
- (*ppType)->AddRef();
- }
- return hr;
- }
-
- STDMETHODIMP SetCurrentMediaType(
- IMFMediaType *pMediaType)
- {
- HRESULT hr = S_OK;
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- DWORD flag = MF_MEDIATYPE_EQUAL_MAJOR_TYPES |
- MF_MEDIATYPE_EQUAL_FORMAT_TYPES |
- MF_MEDIATYPE_EQUAL_FORMAT_DATA;
-
- if (m_currentMediaType && (m_currentMediaType->IsEqual(pMediaType, &flag) == S_OK))
- return S_OK;
-
- hr = validateOperation(OpSetMediaType);
-
- if (SUCCEEDED(hr)) {
- int index = getMediaTypeIndex(pMediaType);
- if (index >= 0) {
- UINT64 size;
- hr = pMediaType->GetUINT64(MF_MT_FRAME_SIZE, &size);
- if (SUCCEEDED(hr)) {
- m_currentFormatIndex = index;
- int width = int(HI32(size));
- int height = int(LO32(size));
- QVideoFrameFormat format(QSize(width, height), m_pixelFormats[index]);
- m_surfaceFormat = format;
-
- MFVideoArea viewport;
- if (SUCCEEDED(pMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
- reinterpret_cast<UINT8*>(&viewport),
- sizeof(MFVideoArea),
- NULL))) {
-
- m_surfaceFormat.setViewport(QRect(viewport.OffsetX.value,
- viewport.OffsetY.value,
- viewport.Area.cx,
- viewport.Area.cy));
- }
-
- if (FAILED(pMediaType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&m_bytesPerLine))) {
- m_bytesPerLine = getBytesPerLine(format);
- }
-
- m_state = State_Ready;
- if (m_currentMediaType)
- m_currentMediaType->Release();
- m_currentMediaType = pMediaType;
- pMediaType->AddRef();
- }
- } else {
- hr = MF_E_INVALIDREQUEST;
- }
- }
- return hr;
- }
-
- STDMETHODIMP GetCurrentMediaType(
- IMFMediaType **ppMediaType)
- {
- if (ppMediaType == NULL)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- if (m_currentFormatIndex < 0)
- return MF_E_NOT_INITIALIZED;
- *ppMediaType = m_currentMediaType;
- (*ppMediaType)->AddRef();
- return S_OK;
- }
-
- STDMETHODIMP GetMajorType(
- GUID *pguidMajorType)
- {
- if (pguidMajorType == NULL)
- return E_INVALIDARG;
- *pguidMajorType = MFMediaType_Video;
- return S_OK;
- }
-
- //
- void setSink(QVideoSink *sink)
- {
- m_mutex.lock();
- m_videoSink = sink;
- m_mutex.unlock();
- supportedFormatsChanged();
- }
-
- void setClock(IMFPresentationClock *presentationClock)
- {
- QMutexLocker locker(&m_mutex);
- if (!m_shutdown) {
- if (m_presentationClock)
- m_presentationClock->Release();
- m_presentationClock = presentationClock;
- if (m_presentationClock)
- m_presentationClock->AddRef();
- }
- }
-
- void shutdown()
- {
- QMutexLocker locker(&m_mutex);
- Q_ASSERT(!m_shutdown);
-
- if (m_currentMediaType) {
- m_currentMediaType->Release();
- m_currentMediaType = NULL;
- m_currentFormatIndex = -1;
- }
-
- if (m_eventQueue)
- m_eventQueue->Shutdown();
-
- MFUnlockWorkQueue(m_workQueueId);
-
- if (m_presentationClock) {
- m_presentationClock->Release();
- m_presentationClock = NULL;
- }
-
- clearMediaTypes();
- clearSampleQueue();
- clearBufferCache();
-
- if (m_eventQueue) {
- m_eventQueue->Release();
- m_eventQueue = NULL;
- }
-
- m_shutdown = true;
- }
-
- HRESULT startPreroll(MFTIME hnsUpcomingStartTime)
- {
- QMutexLocker locker(&m_mutex);
- HRESULT hr = validateOperation(OpPreroll);
- if (SUCCEEDED(hr)) {
- m_state = State_Prerolling;
- m_prerollTargetTime = hnsUpcomingStartTime;
- hr = queueAsyncOperation(OpPreroll);
- }
- return hr;
- }
-
- HRESULT finalize(IMFAsyncCallback *pCallback, IUnknown *punkState)
- {
- QMutexLocker locker(&m_mutex);
- HRESULT hr = S_OK;
- hr = validateOperation(OpFinalize);
- if (SUCCEEDED(hr) && m_finalizeResult != NULL)
- hr = MF_E_INVALIDREQUEST; // The operation is already pending.
-
- // Create and store the async result object.
- if (SUCCEEDED(hr))
- hr = MFCreateAsyncResult(NULL, pCallback, punkState, &m_finalizeResult);
-
- if (SUCCEEDED(hr)) {
- m_state = State_Finalized;
- hr = queueAsyncOperation(OpFinalize);
- }
- return hr;
- }
-
- HRESULT start(MFTIME start)
- {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MediaStream::start" << start;
-#endif
- HRESULT hr = S_OK;
- QMutexLocker locker(&m_mutex);
- if (m_rate != 0)
- hr = validateOperation(OpStart);
-
- if (SUCCEEDED(hr)) {
- MFTIME sysTime;
- if (start != PRESENTATION_CURRENT_POSITION)
- m_startTime = start; // Cache the start time.
- else
- m_presentationClock->GetCorrelatedTime(0, &m_startTime, &sysTime);
- m_state = State_Started;
- hr = queueAsyncOperation(OpStart);
- }
- return hr;
- }
-
- HRESULT restart()
- {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MediaStream::restart";
-#endif
- QMutexLocker locker(&m_mutex);
- HRESULT hr = validateOperation(OpRestart);
- if (SUCCEEDED(hr)) {
- m_state = State_Started;
- hr = queueAsyncOperation(OpRestart);
- }
- return hr;
- }
-
- HRESULT stop()
- {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MediaStream::stop";
-#endif
- QMutexLocker locker(&m_mutex);
- HRESULT hr = validateOperation(OpStop);
- if (SUCCEEDED(hr)) {
- m_state = State_Stopped;
- hr = queueAsyncOperation(OpStop);
- }
- return hr;
- }
-
- HRESULT pause()
- {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MediaStream::pause";
-#endif
- QMutexLocker locker(&m_mutex);
- HRESULT hr = validateOperation(OpPause);
- if (SUCCEEDED(hr)) {
- m_state = State_Paused;
- hr = queueAsyncOperation(OpPause);
- }
- return hr;
- }
-
- HRESULT setRate(float rate)
- {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "MediaStream::setRate" << rate;
-#endif
- QMutexLocker locker(&m_mutex);
- HRESULT hr = validateOperation(OpSetRate);
- if (SUCCEEDED(hr)) {
- m_rate = rate;
- hr = queueAsyncOperation(OpSetRate);
- }
- return hr;
- }
-
- void supportedFormatsChanged()
- {
- QMutexLocker locker(&m_mutex);
- m_pixelFormats.clear();
- clearMediaTypes();
- if (!m_videoSink)
- return;
- for (int f = 0; f < QVideoFrameFormat::NPixelFormats; ++f) {
- QVideoFrameFormat::PixelFormat format = QVideoFrameFormat::PixelFormat(f);
- IMFMediaType *mediaType;
- if (FAILED(MFCreateMediaType(&mediaType))) {
- qWarning("Failed to create mf media type!");
- continue;
- }
- mediaType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE);
- mediaType->SetUINT32(MF_MT_COMPRESSED, FALSE);
- mediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
- mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
- switch (format) {
- case QVideoFrameFormat::Format_BGRA8888:
- case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
- mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32);
- break;
- case QVideoFrameFormat::Format_BGRX8888:
- mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
- break;
- case QVideoFrameFormat::Format_AYUV:
- case QVideoFrameFormat::Format_AYUV_Premultiplied:
- mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_AYUV);
- break;
- case QVideoFrameFormat::Format_YUV420P:
- mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_I420);
- break;
- case QVideoFrameFormat::Format_UYVY:
- mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_UYVY);
- break;
- case QVideoFrameFormat::Format_YV12:
- mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12);
- break;
- case QVideoFrameFormat::Format_NV12:
- mediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
- break;
- default:
- mediaType->Release();
- continue;
- }
- // #### QAbstractVideoSurface::supportedPixelFormats() returns formats in descending
- // order of preference, while IMFMediaTypeHandler is supposed to return supported
- // formats in ascending order of preference. We need to reverse the list.
- m_pixelFormats.prepend(format);
- m_mediaTypes.prepend(mediaType);
- }
- }
-
- void present()
- {
- QMutexLocker locker(&m_mutex);
- if (!m_scheduledBuffer)
- return;
- QVideoFrame frame = QVideoFrame(
- new MediaSampleVideoBuffer(m_scheduledBuffer, m_bytesPerLine), m_surfaceFormat);
- frame.setStartTime(m_bufferStartTime * 0.1);
- frame.setEndTime((m_bufferStartTime + m_bufferDuration) * 0.1);
- m_videoSink->platformVideoSink()->setVideoFrame(frame);
- m_scheduledBuffer->Release();
- m_scheduledBuffer = NULL;
- if (m_rate != 0)
- schedulePresentation(true);
- }
-
- void clearScheduledFrame()
- {
- QMutexLocker locker(&m_mutex);
- if (m_scheduledBuffer) {
- m_scheduledBuffer->Release();
- m_scheduledBuffer = NULL;
- schedulePresentation(true);
- }
- }
-
- enum
- {
- PresentSurface
- };
-
- class PresentEvent : public QEvent
- {
- public:
- PresentEvent(MFTIME targetTime)
- : QEvent(QEvent::Type(PresentSurface))
- , m_time(targetTime)
- {
- }
-
- MFTIME targetTime()
- {
- return m_time;
- }
-
- private:
- MFTIME m_time;
- };
-
- protected:
- HRESULT m_startResult;
-
- private:
- enum FlushState
- {
- DropSamples = 0,
- WriteSamples
- };
-
- // State enum: Defines the current state of the stream.
- enum State
- {
- State_TypeNotSet = 0, // No media type is set
- State_Ready, // Media type is set, Start has never been called.
- State_Prerolling,
- State_Started,
- State_Paused,
- State_Stopped,
- State_WaitForSurfaceStart,
- State_Finalized,
- State_Count = State_Finalized + 1 // Number of states
- };
-
- // StreamOperation: Defines various operations that can be performed on the stream.
- enum StreamOperation
- {
- OpSetMediaType = 0,
- OpStart,
- OpPreroll,
- OpRestart,
- OpPause,
- OpStop,
- OpSetRate,
- OpProcessSample,
- OpPlaceMarker,
- OpFinalize,
-
- Op_Count = OpFinalize + 1 // Number of operations
- };
-
- // AsyncOperation:
- // Used to queue asynchronous operations. When we call MFPutWorkItem, we use this
- // object for the callback state (pState). Then, when the callback is invoked,
- // we can use the object to determine which asynchronous operation to perform.
- class AsyncOperation : public IUnknown
- {
- public:
- AsyncOperation(StreamOperation op)
- :m_cRef(1), m_op(op)
- {
- }
-
- StreamOperation m_op; // The operation to perform.
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
- {
- if (!ppv)
- return E_POINTER;
- if (iid == IID_IUnknown) {
- *ppv = static_cast<IUnknown*>(this);
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
- STDMETHODIMP_(ULONG) AddRef()
- {
- return InterlockedIncrement(&m_cRef);
- }
- STDMETHODIMP_(ULONG) Release()
- {
- ULONG uCount = InterlockedDecrement(&m_cRef);
- if (uCount == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return uCount;
- }
-
- private:
- long m_cRef;
- virtual ~AsyncOperation()
- {
- Q_ASSERT(m_cRef == 0);
- }
- };
-
- // ValidStateMatrix: Defines a look-up table that says which operations
- // are valid from which states.
- static BOOL ValidStateMatrix[State_Count][Op_Count];
-
- long m_cRef;
- QMutex m_mutex;
-
- IMFMediaType *m_currentMediaType;
- State m_state;
- IMFMediaSink *m_sink;
- IMFMediaEventQueue *m_eventQueue;
- DWORD m_workQueueId;
- AsyncCallback<MediaStream> m_workQueueCB;
- QList<IUnknown*> m_sampleQueue;
- IMFAsyncResult *m_finalizeResult; // Result object for Finalize operation.
- MFTIME m_startTime; // Presentation time when the clock started.
-
- bool m_shutdown;
- QList<IMFMediaType*> m_mediaTypes;
- QList<QVideoFrameFormat::PixelFormat> m_pixelFormats;
- int m_currentFormatIndex;
- int m_bytesPerLine;
- QVideoFrameFormat m_surfaceFormat;
- QVideoSink *m_videoSink;
- MFVideoRendererControl *m_rendererControl;
-
- void clearMediaTypes()
- {
- for (IMFMediaType* mediaType : qAsConst(m_mediaTypes))
- mediaType->Release();
- m_mediaTypes.clear();
- }
-
- int getMediaTypeIndex(IMFMediaType *mt)
- {
- GUID majorType;
- if (FAILED(mt->GetMajorType(&majorType)))
- return -1;
- if (majorType != MFMediaType_Video)
- return -1;
-
- GUID subType;
- if (FAILED(mt->GetGUID(MF_MT_SUBTYPE, &subType)))
- return -1;
-
- for (int index = 0; index < m_mediaTypes.size(); ++index) {
- GUID st;
- m_mediaTypes[index]->GetGUID(MF_MT_SUBTYPE, &st);
- if (st == subType)
- return index;
- }
- return -1;
- }
-
- int getBytesPerLine(const QVideoFrameFormat &format)
- {
- switch (format.pixelFormat()) {
- // 32 bpp packed formats.
- case QVideoFrameFormat::Format_XBGR8888:
- case QVideoFrameFormat::Format_BGRX8888:
- case QVideoFrameFormat::Format_XRGB8888:
- case QVideoFrameFormat::Format_RGBX8888:
- case QVideoFrameFormat::Format_AYUV:
- return format.frameWidth() * 4;
- // 16 bpp packed formats.
- case QVideoFrameFormat::Format_YUYV:
- case QVideoFrameFormat::Format_UYVY:
- return PAD_TO_DWORD(format.frameWidth() * 2);
- // Planar formats.
- case QVideoFrameFormat::Format_IMC1:
- case QVideoFrameFormat::Format_IMC2:
- case QVideoFrameFormat::Format_IMC3:
- case QVideoFrameFormat::Format_IMC4:
- case QVideoFrameFormat::Format_YV12:
- case QVideoFrameFormat::Format_NV12:
- case QVideoFrameFormat::Format_YUV420P:
- return PAD_TO_DWORD(format.frameWidth());
- default:
- return 0;
- }
- }
-
- // Callback for MFPutWorkItem.
- HRESULT onDispatchWorkItem(IMFAsyncResult* pAsyncResult)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- HRESULT hr = S_OK;
- IUnknown *pState = NULL;
- hr = pAsyncResult->GetState(&pState);
- if (SUCCEEDED(hr)) {
- // The state object is an AsncOperation object.
- AsyncOperation *pOp = (AsyncOperation*)pState;
- StreamOperation op = pOp->m_op;
- switch (op) {
- case OpStart:
- endPreroll(S_FALSE);
- schedulePresentation(true);
- case OpRestart:
- endPreroll(S_FALSE);
- if (SUCCEEDED(hr)) {
- // Send MEStreamSinkStarted.
- hr = queueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL);
- // Kick things off by requesting samples...
- schedulePresentation(true);
- // There might be samples queue from earlier (ie, while paused).
- if (SUCCEEDED(hr))
- hr = processSamplesFromQueue(WriteSamples);
- }
- break;
- case OpPreroll:
- beginPreroll();
- break;
- case OpStop:
- // Drop samples from queue.
- hr = processSamplesFromQueue(DropSamples);
- clearBufferCache();
- // Send the event even if the previous call failed.
- hr = queueEvent(MEStreamSinkStopped, GUID_NULL, hr, NULL);
- break;
- case OpPause:
- hr = queueEvent(MEStreamSinkPaused, GUID_NULL, hr, NULL);
- break;
- case OpSetRate:
- hr = queueEvent(MEStreamSinkRateChanged, GUID_NULL, S_OK, NULL);
- break;
- case OpProcessSample:
- case OpPlaceMarker:
- hr = dispatchProcessSample(pOp);
- break;
- case OpFinalize:
- endPreroll(S_FALSE);
- hr = dispatchFinalize(pOp);
- break;
- }
- }
-
- if (pState)
- pState->Release();
- return hr;
- }
-
-
- HRESULT queueEvent(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT* pvValue)
- {
- HRESULT hr = S_OK;
- if (m_shutdown)
- hr = MF_E_SHUTDOWN;
- if (SUCCEEDED(hr))
- hr = m_eventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue);
- return hr;
- }
-
- HRESULT validateOperation(StreamOperation op)
- {
- Q_ASSERT(!m_shutdown);
- if (ValidStateMatrix[m_state][op])
- return S_OK;
- else
- return MF_E_INVALIDREQUEST;
- }
-
- HRESULT queueAsyncOperation(StreamOperation op)
- {
- HRESULT hr = S_OK;
- AsyncOperation *asyncOp = new AsyncOperation(op);
- if (asyncOp == NULL)
- hr = E_OUTOFMEMORY;
-
- if (SUCCEEDED(hr))
- hr = MFPutWorkItem(m_workQueueId, &m_workQueueCB, asyncOp);
-
- if (asyncOp)
- asyncOp->Release();
-
- return hr;
- }
-
- HRESULT processSamplesFromQueue(FlushState bFlushData)
- {
- HRESULT hr = S_OK;
- QList<IUnknown*>::Iterator pos = m_sampleQueue.begin();
- // Enumerate all of the samples/markers in the queue.
- while (pos != m_sampleQueue.end()) {
- IUnknown *pUnk = NULL;
- IMarker *pMarker = NULL;
- IMFSample *pSample = NULL;
- pUnk = *pos;
- // Figure out if this is a marker or a sample.
- if (SUCCEEDED(hr)) {
- hr = pUnk->QueryInterface(__uuidof(IMarker), (void**)&pMarker);
- if (hr == E_NOINTERFACE)
- hr = pUnk->QueryInterface(IID_IMFSample, (void**)&pSample);
- }
-
- // Now handle the sample/marker appropriately.
- if (SUCCEEDED(hr)) {
- if (pMarker) {
- hr = sendMarkerEvent(pMarker, bFlushData);
- } else {
- Q_ASSERT(pSample != NULL); // Not a marker, must be a sample
- if (bFlushData == WriteSamples)
- hr = processSampleData(pSample);
- }
- }
- if (pMarker)
- pMarker->Release();
- if (pSample)
- pSample->Release();
-
- if (FAILED(hr))
- break;
-
- pos++;
- }
-
- clearSampleQueue();
- return hr;
- }
-
- void beginPreroll()
- {
- if (m_prerolling)
- return;
- m_prerolling = true;
- clearSampleQueue();
- clearBufferCache();
- queueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
- }
-
- void endPreroll(HRESULT hrStatus)
- {
- if (!m_prerolling)
- return;
- m_prerolling = false;
- queueEvent(MEStreamSinkPrerolled, GUID_NULL, hrStatus, NULL);
- }
- MFTIME m_prerollTargetTime;
- bool m_prerolling;
-
- void clearSampleQueue() {
- for (IUnknown* sample : qAsConst(m_sampleQueue))
- sample->Release();
- m_sampleQueue.clear();
- }
-
- HRESULT sendMarkerEvent(IMarker *pMarker, FlushState FlushState)
- {
- HRESULT hr = S_OK;
- HRESULT hrStatus = S_OK; // Status code for marker event.
- if (FlushState == DropSamples)
- hrStatus = E_ABORT;
-
- PROPVARIANT var;
- PropVariantInit(&var);
-
- // Get the context data.
- hr = pMarker->GetContext(&var);
-
- if (SUCCEEDED(hr))
- hr = queueEvent(MEStreamSinkMarker, GUID_NULL, hrStatus, &var);
-
- PropVariantClear(&var);
- return hr;
- }
-
- HRESULT dispatchProcessSample(AsyncOperation* pOp)
- {
- HRESULT hr = S_OK;
- Q_ASSERT(pOp != NULL);
- Q_UNUSED(pOp);
- hr = processSamplesFromQueue(WriteSamples);
- // We are in the middle of an asynchronous operation, so if something failed, send an error.
- if (FAILED(hr))
- hr = queueEvent(MEError, GUID_NULL, hr, NULL);
-
- return hr;
- }
-
- HRESULT dispatchFinalize(AsyncOperation*)
- {
- HRESULT hr = S_OK;
- // Write any samples left in the queue...
- hr = processSamplesFromQueue(WriteSamples);
-
- // Set the async status and invoke the callback.
- m_finalizeResult->SetStatus(hr);
- hr = MFInvokeCallback(m_finalizeResult);
- return hr;
- }
-
- HRESULT processSampleData(IMFSample *pSample)
- {
- m_sampleRequested = false;
-
- LONGLONG time, duration = -1;
- HRESULT hr = pSample->GetSampleTime(&time);
- if (SUCCEEDED(hr))
- pSample->GetSampleDuration(&duration);
-
- if (m_prerolling) {
- if (SUCCEEDED(hr) && ((time - m_prerollTargetTime) * m_rate) >= 0) {
- IMFMediaBuffer *pBuffer = NULL;
- hr = pSample->ConvertToContiguousBuffer(&pBuffer);
- if (SUCCEEDED(hr)) {
- SampleBuffer sb;
- sb.m_buffer = pBuffer;
- sb.m_time = time;
- sb.m_duration = duration;
- m_bufferCache.push_back(sb);
- endPreroll(S_OK);
- }
- } else {
- queueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
- }
- } else {
- bool requestSample = true;
- // If the time stamp is too early, just discard this sample.
- if (SUCCEEDED(hr) && ((time - m_startTime) * m_rate) >= 0) {
- IMFMediaBuffer *pBuffer = NULL;
- hr = pSample->ConvertToContiguousBuffer(&pBuffer);
- if (SUCCEEDED(hr)) {
- SampleBuffer sb;
- sb.m_buffer = pBuffer;
- sb.m_time = time;
- sb.m_duration = duration;
- m_bufferCache.push_back(sb);
- }
- if (m_rate == 0)
- requestSample = false;
- }
- schedulePresentation(requestSample);
- }
- return hr;
- }
-
- class SampleBuffer
- {
- public:
- IMFMediaBuffer *m_buffer;
- LONGLONG m_time;
- LONGLONG m_duration;
- };
- QList<SampleBuffer> m_bufferCache;
- static const int BUFFER_CACHE_SIZE = 2;
-
- void clearBufferCache()
- {
- for (SampleBuffer sb : qAsConst(m_bufferCache))
- sb.m_buffer->Release();
- m_bufferCache.clear();
-
- if (m_scheduledBuffer) {
- m_scheduledBuffer->Release();
- m_scheduledBuffer = NULL;
- }
- }
-
- void schedulePresentation(bool requestSample)
- {
- if (m_state == State_Paused || m_state == State_Prerolling)
- return;
- if (!m_scheduledBuffer) {
- //get time from presentation time
- MFTIME currentTime = m_startTime, sysTime;
- bool timeOK = true;
- if (m_rate != 0) {
- if (FAILED(m_presentationClock->GetCorrelatedTime(0, &currentTime, &sysTime)))
- timeOK = false;
- }
- while (!m_bufferCache.isEmpty()) {
- SampleBuffer sb = m_bufferCache.takeFirst();
- if (timeOK && ((sb.m_time - currentTime) * m_rate) < 0) {
- sb.m_buffer->Release();
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "currentPresentTime =" << float(currentTime / 10000) * 0.001f << " and sampleTime is" << float(sb.m_time / 10000) * 0.001f;
-#endif
- continue;
- }
- m_scheduledBuffer = sb.m_buffer;
- m_bufferStartTime = sb.m_time;
- m_bufferDuration = sb.m_duration;
- QCoreApplication::postEvent(m_rendererControl, new PresentEvent(sb.m_time));
- if (m_rate == 0)
- queueEvent(MEStreamSinkScrubSampleComplete, GUID_NULL, S_OK, NULL);
- break;
- }
- }
- if (requestSample && !m_sampleRequested && m_bufferCache.size() < BUFFER_CACHE_SIZE) {
- m_sampleRequested = true;
- queueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
- }
- }
- IMFMediaBuffer *m_scheduledBuffer;
- MFTIME m_bufferStartTime;
- MFTIME m_bufferDuration;
- IMFPresentationClock *m_presentationClock;
- bool m_sampleRequested;
- float m_rate;
- };
-
- BOOL MediaStream::ValidStateMatrix[MediaStream::State_Count][MediaStream::Op_Count] =
- {
- // States: Operations:
- // SetType Start Preroll, Restart Pause Stop SetRate Sample Marker Finalize
- /* NotSet */ TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
-
- /* Ready */ TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
-
- /* Prerolling */ TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
-
- /* Start */ FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
-
- /* Pause */ FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
-
- /* Stop */ FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE,
-
- /*WaitForSurfaceStart*/ FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE,
-
- /* Final */ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
-
- // Note about states:
- // 1. OnClockRestart should only be called from paused state.
- // 2. While paused, the sink accepts samples but does not process them.
- };
-
- class MediaSink : public IMFFinalizableMediaSink,
- public IMFClockStateSink,
- public IMFMediaSinkPreroll,
- public IMFGetService,
- public IMFRateSupport
- {
- public:
- MediaSink(MFVideoRendererControl *rendererControl)
- : m_cRef(1)
- , m_shutdown(false)
- , m_presentationClock(0)
- , m_playRate(1)
- {
- m_stream = new MediaStream(this, rendererControl);
- }
-
- ~MediaSink()
- {
- Q_ASSERT(m_shutdown);
- }
-
- void setSurface(QVideoSink *surface)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return;
- m_stream->setSink(surface);
- }
-
- void present()
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return;
- m_stream->present();
- }
-
- void clearScheduledFrame()
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return;
- m_stream->clearScheduledFrame();
- }
-
- MFTIME getTime()
- {
- QMutexLocker locker(&m_mutex);
- if (!m_presentationClock)
- return 0;
- MFTIME time, sysTime;
- m_presentationClock->GetCorrelatedTime(0, &time, &sysTime);
- return time;
- }
-
- float getPlayRate()
- {
- QMutexLocker locker(&m_mutex);
- return m_playRate;
- }
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)
- {
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFMediaSink) {
- *ppvObject = static_cast<IMFMediaSink*>(this);
- } else if (riid == IID_IMFGetService) {
- *ppvObject = static_cast<IMFGetService*>(this);
- } else if (riid == IID_IMFMediaSinkPreroll) {
- *ppvObject = static_cast<IMFMediaSinkPreroll*>(this);
- } else if (riid == IID_IMFClockStateSink) {
- *ppvObject = static_cast<IMFClockStateSink*>(this);
- } else if (riid == IID_IMFRateSupport) {
- *ppvObject = static_cast<IMFRateSupport*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(static_cast<IMFFinalizableMediaSink*>(this));
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef(void)
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- STDMETHODIMP_(ULONG) Release(void)
- {
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return cRef;
- }
-
- // IMFGetService methods
- STDMETHODIMP GetService(const GUID &guidService,
- const IID &riid,
- LPVOID *ppvObject)
- {
- if (!ppvObject)
- return E_POINTER;
-
- if (guidService != MF_RATE_CONTROL_SERVICE)
- return MF_E_UNSUPPORTED_SERVICE;
-
- return QueryInterface(riid, ppvObject);
- }
-
- //IMFMediaSinkPreroll
- STDMETHODIMP NotifyPreroll(MFTIME hnsUpcomingStartTime)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_stream->startPreroll(hnsUpcomingStartTime);
- }
-
- //from IMFFinalizableMediaSink
- STDMETHODIMP BeginFinalize(IMFAsyncCallback *pCallback, IUnknown *punkState)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_stream->finalize(pCallback, punkState);
- }
-
- STDMETHODIMP EndFinalize(IMFAsyncResult *pResult)
- {
- HRESULT hr = S_OK;
- // Return the status code from the async result.
- if (pResult == NULL)
- hr = E_INVALIDARG;
- else
- hr = pResult->GetStatus();
- return hr;
- }
-
- //from IMFMediaSink
- STDMETHODIMP GetCharacteristics(
- DWORD *pdwCharacteristics)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- *pdwCharacteristics = MEDIASINK_FIXED_STREAMS | MEDIASINK_CAN_PREROLL;
- return S_OK;
- }
-
- STDMETHODIMP AddStreamSink(
- DWORD,
- IMFMediaType *,
- IMFStreamSink **)
- {
- QMutexLocker locker(&m_mutex);
- return m_shutdown ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
- }
-
- STDMETHODIMP RemoveStreamSink(
- DWORD)
- {
- QMutexLocker locker(&m_mutex);
- return m_shutdown ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
- }
-
- STDMETHODIMP GetStreamSinkCount(
- DWORD *pcStreamSinkCount)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- *pcStreamSinkCount = 1;
- return S_OK;
- }
-
- STDMETHODIMP GetStreamSinkByIndex(
- DWORD dwIndex,
- IMFStreamSink **ppStreamSink)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- if (dwIndex != 0)
- return MF_E_INVALIDINDEX;
-
- *ppStreamSink = m_stream;
- m_stream->AddRef();
- return S_OK;
- }
-
- STDMETHODIMP GetStreamSinkById(
- DWORD dwStreamSinkIdentifier,
- IMFStreamSink **ppStreamSink)
- {
- if (ppStreamSink == NULL)
- return E_INVALIDARG;
- if (dwStreamSinkIdentifier != MediaStream::DEFAULT_MEDIA_STREAM_ID)
- return MF_E_INVALIDSTREAMNUMBER;
-
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- *ppStreamSink = m_stream;
- m_stream->AddRef();
- return S_OK;
- }
-
- STDMETHODIMP SetPresentationClock(
- IMFPresentationClock *pPresentationClock)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- if (m_presentationClock) {
- m_presentationClock->RemoveClockStateSink(this);
- m_presentationClock->Release();
- }
- m_presentationClock = pPresentationClock;
- if (m_presentationClock) {
- m_presentationClock->AddRef();
- m_presentationClock->AddClockStateSink(this);
- }
- m_stream->setClock(m_presentationClock);
- return S_OK;
- }
-
- STDMETHODIMP GetPresentationClock(
- IMFPresentationClock **ppPresentationClock)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- *ppPresentationClock = m_presentationClock;
- if (m_presentationClock) {
- m_presentationClock->AddRef();
- return S_OK;
- }
- return MF_E_NO_CLOCK;
- }
-
- STDMETHODIMP Shutdown(void)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
-
- m_stream->shutdown();
- if (m_presentationClock) {
- m_presentationClock->Release();
- m_presentationClock = NULL;
- }
- m_stream->Release();
- m_stream = NULL;
- m_shutdown = true;
- return S_OK;
- }
-
- // IMFClockStateSink methods
- STDMETHODIMP OnClockStart(MFTIME, LONGLONG llClockStartOffset)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_stream->start(llClockStartOffset);
- }
-
- STDMETHODIMP OnClockStop(MFTIME)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_stream->stop();
- }
-
- STDMETHODIMP OnClockPause(MFTIME)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_stream->pause();
- }
-
- STDMETHODIMP OnClockRestart(MFTIME)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- return m_stream->restart();
- }
-
- STDMETHODIMP OnClockSetRate(MFTIME, float flRate)
- {
- QMutexLocker locker(&m_mutex);
- if (m_shutdown)
- return MF_E_SHUTDOWN;
- m_playRate = flRate;
- return m_stream->setRate(flRate);
- }
-
- // IMFRateSupport methods
- STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection,
- BOOL fThin,
- float *pflRate)
- {
- if (!pflRate)
- return E_POINTER;
-
- *pflRate = (fThin ? 8.f : 2.0f) * (eDirection == MFRATE_FORWARD ? 1 : -1) ;
-
- return S_OK;
- }
-
- STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection,
- BOOL fThin,
- float *pflRate)
- {
- Q_UNUSED(eDirection);
- Q_UNUSED(fThin);
-
- if (!pflRate)
- return E_POINTER;
-
- // we support any rate
- *pflRate = 0.f;
-
- return S_OK;
- }
-
- STDMETHODIMP IsRateSupported(BOOL fThin,
- float flRate,
- float *pflNearestSupportedRate)
- {
- HRESULT hr = S_OK;
-
- if (!qFuzzyIsNull(flRate)) {
- MFRATE_DIRECTION direction = flRate > 0.f ? MFRATE_FORWARD
- : MFRATE_REVERSE;
-
- float fastestRate = 0.f;
- float slowestRate = 0.f;
- GetFastestRate(direction, fThin, &fastestRate);
- GetSlowestRate(direction, fThin, &slowestRate);
-
- if (direction == MFRATE_REVERSE)
- qSwap(fastestRate, slowestRate);
-
- if (flRate < slowestRate || flRate > fastestRate) {
- hr = MF_E_UNSUPPORTED_RATE;
- if (pflNearestSupportedRate) {
- *pflNearestSupportedRate = qBound(slowestRate,
- flRate,
- fastestRate);
- }
- }
- } else if (pflNearestSupportedRate) {
- *pflNearestSupportedRate = flRate;
- }
-
- return hr;
- }
-
- private:
- long m_cRef;
- QMutex m_mutex;
- bool m_shutdown;
- IMFPresentationClock *m_presentationClock;
- MediaStream *m_stream;
- float m_playRate;
- };
-
- class VideoRendererActivate : public IMFActivate
- {
- public:
- VideoRendererActivate(MFVideoRendererControl *rendererControl)
- : m_cRef(1)
- , m_sink(0)
- , m_rendererControl(rendererControl)
- , m_attributes(0)
- , m_videoSink(0)
- {
- MFCreateAttributes(&m_attributes, 0);
- m_sink = new MediaSink(rendererControl);
- }
-
- ~VideoRendererActivate()
- {
- m_attributes->Release();
- }
-
- //from IUnknown
- STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)
- {
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IMFActivate) {
- *ppvObject = static_cast<IMFActivate*>(this);
- } else if (riid == IID_IMFAttributes) {
- *ppvObject = static_cast<IMFAttributes*>(this);
- } else if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(static_cast<IMFActivate*>(this));
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
- }
-
- STDMETHODIMP_(ULONG) AddRef(void)
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- STDMETHODIMP_(ULONG) Release(void)
- {
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return cRef;
- }
-
- //from IMFActivate
- STDMETHODIMP ActivateObject(REFIID riid, void **ppv)
- {
- if (!ppv)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- if (!m_sink) {
- m_sink = new MediaSink(m_rendererControl);
- if (m_videoSink)
- m_sink->setSurface(m_videoSink);
- }
- return m_sink->QueryInterface(riid, ppv);
- }
-
- STDMETHODIMP ShutdownObject(void)
- {
- QMutexLocker locker(&m_mutex);
- HRESULT hr = S_OK;
- if (m_sink) {
- hr = m_sink->Shutdown();
- m_sink->Release();
- m_sink = NULL;
- }
- return hr;
- }
-
- STDMETHODIMP DetachObject(void)
- {
- QMutexLocker locker(&m_mutex);
- if (m_sink) {
- m_sink->Release();
- m_sink = NULL;
- }
- return S_OK;
- }
-
- //from IMFAttributes
- STDMETHODIMP GetItem(
- REFGUID guidKey,
- PROPVARIANT *pValue)
- {
- return m_attributes->GetItem(guidKey, pValue);
- }
-
- STDMETHODIMP GetItemType(
- REFGUID guidKey,
- MF_ATTRIBUTE_TYPE *pType)
- {
- return m_attributes->GetItemType(guidKey, pType);
- }
-
- STDMETHODIMP CompareItem(
- REFGUID guidKey,
- REFPROPVARIANT Value,
- BOOL *pbResult)
- {
- return m_attributes->CompareItem(guidKey, Value, pbResult);
- }
-
- STDMETHODIMP Compare(
- IMFAttributes *pTheirs,
- MF_ATTRIBUTES_MATCH_TYPE MatchType,
- BOOL *pbResult)
- {
- return m_attributes->Compare(pTheirs, MatchType, pbResult);
- }
-
- STDMETHODIMP GetUINT32(
- REFGUID guidKey,
- UINT32 *punValue)
- {
- return m_attributes->GetUINT32(guidKey, punValue);
- }
-
- STDMETHODIMP GetUINT64(
- REFGUID guidKey,
- UINT64 *punValue)
- {
- return m_attributes->GetUINT64(guidKey, punValue);
- }
-
- STDMETHODIMP GetDouble(
- REFGUID guidKey,
- double *pfValue)
- {
- return m_attributes->GetDouble(guidKey, pfValue);
- }
-
- STDMETHODIMP GetGUID(
- REFGUID guidKey,
- GUID *pguidValue)
- {
- return m_attributes->GetGUID(guidKey, pguidValue);
- }
-
- STDMETHODIMP GetStringLength(
- REFGUID guidKey,
- UINT32 *pcchLength)
- {
- return m_attributes->GetStringLength(guidKey, pcchLength);
- }
-
- STDMETHODIMP GetString(
- REFGUID guidKey,
- LPWSTR pwszValue,
- UINT32 cchBufSize,
- UINT32 *pcchLength)
- {
- return m_attributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
- }
-
- STDMETHODIMP GetAllocatedString(
- REFGUID guidKey,
- LPWSTR *ppwszValue,
- UINT32 *pcchLength)
- {
- return m_attributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
- }
-
- STDMETHODIMP GetBlobSize(
- REFGUID guidKey,
- UINT32 *pcbBlobSize)
- {
- return m_attributes->GetBlobSize(guidKey, pcbBlobSize);
- }
-
- STDMETHODIMP GetBlob(
- REFGUID guidKey,
- UINT8 *pBuf,
- UINT32 cbBufSize,
- UINT32 *pcbBlobSize)
- {
- return m_attributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
- }
-
- STDMETHODIMP GetAllocatedBlob(
- REFGUID guidKey,
- UINT8 **ppBuf,
- UINT32 *pcbSize)
- {
- return m_attributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
- }
-
- STDMETHODIMP GetUnknown(
- REFGUID guidKey,
- REFIID riid,
- LPVOID *ppv)
- {
- return m_attributes->GetUnknown(guidKey, riid, ppv);
- }
-
- STDMETHODIMP SetItem(
- REFGUID guidKey,
- REFPROPVARIANT Value)
- {
- return m_attributes->SetItem(guidKey, Value);
- }
-
- STDMETHODIMP DeleteItem(
- REFGUID guidKey)
- {
- return m_attributes->DeleteItem(guidKey);
- }
-
- STDMETHODIMP DeleteAllItems(void)
- {
- return m_attributes->DeleteAllItems();
- }
-
- STDMETHODIMP SetUINT32(
- REFGUID guidKey,
- UINT32 unValue)
- {
- return m_attributes->SetUINT32(guidKey, unValue);
- }
-
- STDMETHODIMP SetUINT64(
- REFGUID guidKey,
- UINT64 unValue)
- {
- return m_attributes->SetUINT64(guidKey, unValue);
- }
-
- STDMETHODIMP SetDouble(
- REFGUID guidKey,
- double fValue)
- {
- return m_attributes->SetDouble(guidKey, fValue);
- }
-
- STDMETHODIMP SetGUID(
- REFGUID guidKey,
- REFGUID guidValue)
- {
- return m_attributes->SetGUID(guidKey, guidValue);
- }
-
- STDMETHODIMP SetString(
- REFGUID guidKey,
- LPCWSTR wszValue)
- {
- return m_attributes->SetString(guidKey, wszValue);
- }
-
- STDMETHODIMP SetBlob(
- REFGUID guidKey,
- const UINT8 *pBuf,
- UINT32 cbBufSize)
- {
- return m_attributes->SetBlob(guidKey, pBuf, cbBufSize);
- }
-
- STDMETHODIMP SetUnknown(
- REFGUID guidKey,
- IUnknown *pUnknown)
- {
- return m_attributes->SetUnknown(guidKey, pUnknown);
- }
-
- STDMETHODIMP LockStore(void)
- {
- return m_attributes->LockStore();
- }
-
- STDMETHODIMP UnlockStore(void)
- {
- return m_attributes->UnlockStore();
- }
-
- STDMETHODIMP GetCount(
- UINT32 *pcItems)
- {
- return m_attributes->GetCount(pcItems);
- }
-
- STDMETHODIMP GetItemByIndex(
- UINT32 unIndex,
- GUID *pguidKey,
- PROPVARIANT *pValue)
- {
- return m_attributes->GetItemByIndex(unIndex, pguidKey, pValue);
- }
-
- STDMETHODIMP CopyAllItems(
- IMFAttributes *pDest)
- {
- return m_attributes->CopyAllItems(pDest);
- }
-
- /////////////////////////////////
- void setSink(QVideoSink *sink)
- {
- QMutexLocker locker(&m_mutex);
- if (m_videoSink == sink)
- return;
-
- m_videoSink = sink;
-
- if (!m_sink)
- return;
- m_sink->setSurface(m_videoSink);
- }
-
- void present()
- {
- QMutexLocker locker(&m_mutex);
- if (!m_sink)
- return;
- m_sink->present();
- }
-
- void clearScheduledFrame()
- {
- QMutexLocker locker(&m_mutex);
- if (!m_sink)
- return;
- m_sink->clearScheduledFrame();
- }
-
- MFTIME getTime()
- {
- if (m_sink)
- return m_sink->getTime();
- return 0;
- }
-
- float getPlayRate()
- {
- if (m_sink)
- return m_sink->getPlayRate();
- return 1;
- }
-
- private:
- long m_cRef;
- bool m_shutdown;
- MediaSink *m_sink;
- MFVideoRendererControl *m_rendererControl;
- IMFAttributes *m_attributes;
- QVideoSink *m_videoSink;
- QMutex m_mutex;
- };
-}
-
-
-class EVRCustomPresenterActivate : public MFAbstractActivate
-{
-public:
- EVRCustomPresenterActivate();
- ~EVRCustomPresenterActivate()
- { }
-
- STDMETHODIMP ActivateObject(REFIID riid, void **ppv);
- STDMETHODIMP ShutdownObject();
- STDMETHODIMP DetachObject();
-
- void setSink(QVideoSink *sink);
-
-private:
- EVRCustomPresenter *m_presenter;
- QVideoSink *m_videoSink;
- QMutex m_mutex;
-};
-
-
-MFVideoRendererControl::MFVideoRendererControl(QObject *parent)
- : QObject(parent)
-{
-}
-
-MFVideoRendererControl::~MFVideoRendererControl()
-{
- clear();
-}
-
-void MFVideoRendererControl::clear()
-{
- if (m_sink)
- m_sink->platformVideoSink()->setVideoFrame(QVideoFrame());
-
- if (m_presenterActivate) {
- m_presenterActivate->ShutdownObject();
- m_presenterActivate->Release();
- m_presenterActivate = NULL;
- }
-
- if (m_currentActivate) {
- m_currentActivate->ShutdownObject();
- m_currentActivate->Release();
- }
- m_currentActivate = NULL;
-}
-
-void MFVideoRendererControl::releaseActivate()
-{
- clear();
-}
-
-QVideoSink *MFVideoRendererControl::sink() const
-{
- return m_sink;
-}
-
-void MFVideoRendererControl::setSink(QVideoSink *sink)
-{
- m_sink = sink;
-
- if (m_presenterActivate)
- m_presenterActivate->setSink(m_sink);
- else if (m_currentActivate)
- static_cast<VideoRendererActivate*>(m_currentActivate)->setSink(m_sink);
-}
-
-void MFVideoRendererControl::customEvent(QEvent *event)
-{
- if (m_presenterActivate)
- return;
-
- if (!m_currentActivate)
- return;
-
- if (event->type() == MediaStream::PresentSurface) {
- MFTIME targetTime = static_cast<MediaStream::PresentEvent*>(event)->targetTime();
- MFTIME currentTime = static_cast<VideoRendererActivate*>(m_currentActivate)->getTime();
- float playRate = static_cast<VideoRendererActivate*>(m_currentActivate)->getPlayRate();
- if (!qFuzzyIsNull(playRate) && targetTime != currentTime) {
- // If the scheduled frame is too late, skip it
- const int interval = ((targetTime - currentTime) / 10000) / playRate;
- if (interval < 0)
- static_cast<VideoRendererActivate*>(m_currentActivate)->clearScheduledFrame();
- else
- QTimer::singleShot(interval, this, SLOT(present()));
- } else {
- present();
- }
- return;
- }
- QObject::customEvent(event);
-}
-
-void MFVideoRendererControl::present()
-{
- if (m_presenterActivate)
- return;
-
- if (m_currentActivate)
- static_cast<VideoRendererActivate*>(m_currentActivate)->present();
-}
-
-IMFActivate* MFVideoRendererControl::createActivate()
-{
- clear();
-
- if (m_sink) {
- // Create the EVR media sink, but replace the presenter with our own
- if (SUCCEEDED(MFCreateVideoRendererActivate(::GetShellWindow(), &m_currentActivate))) {
- m_presenterActivate = new EVRCustomPresenterActivate;
- m_currentActivate->SetUnknown(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, m_presenterActivate);
- } else {
- m_currentActivate = new VideoRendererActivate(this);
- }
- }
-
- setSink(m_sink);
-
- return m_currentActivate;
-}
-
-
-EVRCustomPresenterActivate::EVRCustomPresenterActivate()
- : MFAbstractActivate()
- , m_presenter(0)
- , m_videoSink(0)
-{ }
-
-HRESULT EVRCustomPresenterActivate::ActivateObject(REFIID riid, void **ppv)
-{
- if (!ppv)
- return E_INVALIDARG;
- QMutexLocker locker(&m_mutex);
- if (!m_presenter) {
- m_presenter = new EVRCustomPresenter;
- if (m_videoSink)
- m_presenter->setSink(m_videoSink);
- }
- return m_presenter->QueryInterface(riid, ppv);
-}
-
-HRESULT EVRCustomPresenterActivate::ShutdownObject()
-{
- // The presenter does not implement IMFShutdown so
- // this function is the same as DetachObject()
- return DetachObject();
-}
-
-HRESULT EVRCustomPresenterActivate::DetachObject()
-{
- QMutexLocker locker(&m_mutex);
- if (m_presenter) {
- m_presenter->Release();
- m_presenter = 0;
- }
- return S_OK;
-}
-
-void EVRCustomPresenterActivate::setSink(QVideoSink *sink)
-{
- QMutexLocker locker(&m_mutex);
- if (m_videoSink == sink)
- return;
-
- m_videoSink = sink;
-
- if (m_presenter)
- m_presenter->setSink(sink);
-}
-
-#include "moc_mfvideorenderercontrol_p.cpp"
-#include "mfvideorenderercontrol.moc"
diff --git a/src/multimedia/platform/windows/player/mfvideorenderercontrol_p.h b/src/multimedia/platform/windows/player/mfvideorenderercontrol_p.h
deleted file mode 100644
index b4bb2d92d..000000000
--- a/src/multimedia/platform/windows/player/mfvideorenderercontrol_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MFVIDEORENDERERCONTROL_H
-#define MFVIDEORENDERERCONTROL_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 <mfapi.h>
-#include <mfidl.h>
-
-QT_USE_NAMESPACE
-
-class EVRCustomPresenterActivate;
-
-QT_BEGIN_NAMESPACE
-class QVideoSink;
-QT_END_NAMESPACE
-
-class MFVideoRendererControl : public QObject
-{
- Q_OBJECT
-public:
- MFVideoRendererControl(QObject *parent = 0);
- ~MFVideoRendererControl();
-
- QVideoSink *sink() const;
- void setSink(QVideoSink *surface);
-
- IMFActivate* createActivate();
- void releaseActivate();
-
-protected:
- void customEvent(QEvent *event);
-
-private Q_SLOTS:
- void present();
-
-private:
- void clear();
-
- QVideoSink *m_sink = nullptr;
- IMFActivate *m_currentActivate = nullptr;
- IMFSampleGrabberSinkCallback *m_callback = nullptr;
-
- EVRCustomPresenterActivate *m_presenterActivate = nullptr;
-};
-
-#endif
diff --git a/src/multimedia/platform/windows/player/samplegrabber.cpp b/src/multimedia/platform/windows/player/samplegrabber.cpp
deleted file mode 100644
index ef039a902..000000000
--- a/src/multimedia/platform/windows/player/samplegrabber.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "samplegrabber_p.h"
-
-STDMETHODIMP SampleGrabberCallback::QueryInterface(REFIID riid, void** ppv)
-{
- if (!ppv)
- return E_POINTER;
- if (riid == IID_IMFSampleGrabberSinkCallback) {
- *ppv = static_cast<IMFSampleGrabberSinkCallback*>(this);
- } else if (riid == IID_IMFClockStateSink) {
- *ppv = static_cast<IMFClockStateSink*>(this);
- } else if (riid == IID_IUnknown) {
- *ppv = static_cast<IUnknown*>(this);
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) SampleGrabberCallback::AddRef()
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) SampleGrabberCallback::Release()
-{
- ULONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0) {
- delete this;
- }
- return cRef;
-
-}
-
-// IMFClockStateSink methods.
-
-STDMETHODIMP SampleGrabberCallback::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
-{
- Q_UNUSED(hnsSystemTime);
- Q_UNUSED(llClockStartOffset);
- return S_OK;
-}
-
-STDMETHODIMP SampleGrabberCallback::OnClockStop(MFTIME hnsSystemTime)
-{
- Q_UNUSED(hnsSystemTime);
- return S_OK;
-}
-
-STDMETHODIMP SampleGrabberCallback::OnClockPause(MFTIME hnsSystemTime)
-{
- Q_UNUSED(hnsSystemTime);
- return S_OK;
-}
-
-STDMETHODIMP SampleGrabberCallback::OnClockRestart(MFTIME hnsSystemTime)
-{
- Q_UNUSED(hnsSystemTime);
- return S_OK;
-}
-
-STDMETHODIMP SampleGrabberCallback::OnClockSetRate(MFTIME hnsSystemTime, float flRate)
-{
- Q_UNUSED(hnsSystemTime);
- Q_UNUSED(flRate);
- return S_OK;
-}
-
-// IMFSampleGrabberSink methods.
-
-STDMETHODIMP SampleGrabberCallback::OnSetPresentationClock(IMFPresentationClock* pClock)
-{
- Q_UNUSED(pClock);
- return S_OK;
-}
-
-STDMETHODIMP SampleGrabberCallback::OnShutdown()
-{
- return S_OK;
-}
-
-//void AudioSampleGrabberCallback::addProbe(MFAudioProbeControl* probe)
-//{
-// QMutexLocker locker(&m_audioProbeMutex);
-
-// if (m_audioProbes.contains(probe))
-// return;
-
-// m_audioProbes.append(probe);
-//}
-
-//void AudioSampleGrabberCallback::removeProbe(MFAudioProbeControl* probe)
-//{
-// QMutexLocker locker(&m_audioProbeMutex);
-// m_audioProbes.removeOne(probe);
-//}
-
-void AudioSampleGrabberCallback::setFormat(const QAudioFormat& format)
-{
- m_format = format;
-}
-
-STDMETHODIMP AudioSampleGrabberCallback::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
- LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
- DWORD dwSampleSize)
-{
- Q_UNUSED(dwSampleFlags);
- Q_UNUSED(llSampleTime);
- Q_UNUSED(llSampleDuration);
-
- if (guidMajorMediaType != GUID_NULL && guidMajorMediaType != MFMediaType_Audio)
- return S_OK;
-
- QMutexLocker locker(&m_audioProbeMutex);
-
-// if (m_audioProbes.isEmpty())
- return S_OK;
-
- // Check if sample has a presentation time
- if (llSampleTime == _I64_MAX) {
- // Set default QAudioBuffer start time
- llSampleTime = -1;
- } else {
- // WMF uses 100-nanosecond units, Qt uses microseconds
- llSampleTime /= 10;
- }
-
-// for (MFAudioProbeControl* probe : qAsConst(m_audioProbes))
-// probe->bufferProbed((const char*)pSampleBuffer, dwSampleSize, m_format, llSampleTime);
-
- return S_OK;
-}
diff --git a/src/multimedia/platform/windows/player/samplegrabber_p.h b/src/multimedia/platform/windows/player/samplegrabber_p.h
deleted file mode 100644
index 31e00987c..000000000
--- a/src/multimedia/platform/windows/player/samplegrabber_p.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef SAMPLEGRABBER_H
-#define SAMPLEGRABBER_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/qmutex.h>
-#include <QtCore/qlist.h>
-#include <QtMultimedia/qaudioformat.h>
-#include <mfapi.h>
-#include <mfidl.h>
-
-class SampleGrabberCallback : public IMFSampleGrabberSinkCallback
-{
-public:
- // IUnknown methods
- STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
-
- // IMFClockStateSink methods
- STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset);
- STDMETHODIMP OnClockStop(MFTIME hnsSystemTime);
- STDMETHODIMP OnClockPause(MFTIME hnsSystemTime);
- STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime);
- STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate);
-
- // IMFSampleGrabberSinkCallback methods
- STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock);
- STDMETHODIMP OnShutdown();
-
-protected:
- SampleGrabberCallback() : m_cRef(1) {}
-
-public:
- virtual ~SampleGrabberCallback() {}
-
-private:
- long m_cRef;
-};
-
-class AudioSampleGrabberCallback: public SampleGrabberCallback {
-public:
- void setFormat(const QAudioFormat& format);
-
- STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
- LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
- DWORD dwSampleSize);
-
-private:
-// QList<MFAudioProbeControl*> m_audioProbes;
- QMutex m_audioProbeMutex;
- QAudioFormat m_format;
-};
-
-#endif // SAMPLEGRABBER_H
diff --git a/src/multimedia/platform/windows/qwindowsformatinfo.cpp b/src/multimedia/platform/windows/qwindowsformatinfo.cpp
deleted file mode 100644
index 85c362b29..000000000
--- a/src/multimedia/platform/windows/qwindowsformatinfo.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsformatinfo_p.h"
-
-
-QT_BEGIN_NAMESPACE
-
-QWindowsFormatInfo::QWindowsFormatInfo()
-{
- decoders = {
- { QMediaFormat::MPEG4,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3, },
- { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
- { QMediaFormat::QuickTime,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3, },
- { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
- { QMediaFormat::AAC,
- { QMediaFormat::AudioCodec::AAC },
- {} },
- { QMediaFormat::MP3,
- { QMediaFormat::AudioCodec::MP3 },
- {} },
- { QMediaFormat::FLAC,
- { QMediaFormat::AudioCodec::FLAC },
- {} },
- { QMediaFormat::Mpeg4Audio,
- { QMediaFormat::AudioCodec::AAC },
- {} },
- { QMediaFormat::WMA,
- { QMediaFormat::AudioCodec::WMA },
- {} },
- { QMediaFormat::WMV,
- { QMediaFormat::AudioCodec::WMA },
- { QMediaFormat::VideoCodec::WMV } }
- };
-
- encoders = {
- { QMediaFormat::MPEG4,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3 },
- { QMediaFormat::VideoCodec::H264 } },
- { QMediaFormat::AAC,
- { QMediaFormat::AudioCodec::AAC },
- {} },
- { QMediaFormat::MP3,
- { QMediaFormat::AudioCodec::MP3 },
- {} },
- { QMediaFormat::Mpeg4Audio,
- { QMediaFormat::AudioCodec::AAC },
- {} },
- { QMediaFormat::WMA,
- { QMediaFormat::AudioCodec::WMA },
- {} },
- { QMediaFormat::WMV,
- { QMediaFormat::AudioCodec::WMA },
- { QMediaFormat::VideoCodec::WMV } }
- };
-
- // ####
- imageFormats = { QImageCapture::JPEG, QImageCapture::PNG };
-
-}
-
-QWindowsFormatInfo::~QWindowsFormatInfo()
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/qwindowsformatinfo_p.h b/src/multimedia/platform/windows/qwindowsformatinfo_p.h
deleted file mode 100644
index 355aea7d7..000000000
--- a/src/multimedia/platform/windows/qwindowsformatinfo_p.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSFORMATSINFO_H
-#define QWINDOWSFORMATSINFO_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaformatinfo_p.h>
-#include <qhash.h>
-#include <qlist.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsFormatInfo : public QPlatformMediaFormatInfo
-{
-public:
- QWindowsFormatInfo();
- ~QWindowsFormatInfo();
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/windows/qwindowsintegration.cpp b/src/multimedia/platform/windows/qwindowsintegration.cpp
deleted file mode 100644
index b224a8937..000000000
--- a/src/multimedia/platform/windows/qwindowsintegration.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsintegration_p.h"
-#include <private/qwindowsmediadevices_p.h>
-#include <private/qwindowsformatinfo_p.h>
-#include <private/qwindowsmediacapture_p.h>
-#include <private/qwindowsimagecapture_p.h>
-#include <private/qwindowscamera_p.h>
-#include <private/qwindowsmediaencoder_p.h>
-#include <private/mfplayercontrol_p.h>
-#include <private/mfaudiodecodercontrol_p.h>
-#include <private/mfevrvideowindowcontrol_p.h>
-
-QT_BEGIN_NAMESPACE
-
-static int g_refCount = 0;
-
-QWindowsMediaIntegration::QWindowsMediaIntegration()
-{
- g_refCount++;
- if (g_refCount == 1) {
- CoInitialize(NULL);
- MFStartup(MF_VERSION);
- }
-}
-
-QWindowsMediaIntegration::~QWindowsMediaIntegration()
-{
- delete m_devices;
- delete m_formatInfo;
-
- g_refCount--;
- if (g_refCount == 0) {
- // ### This currently crashes on exit
-// MFShutdown();
-// CoUninitialize();
- }
-}
-
-QPlatformMediaDevices *QWindowsMediaIntegration::devices()
-{
- if (!m_devices)
- m_devices = new QWindowsMediaDevices();
- return m_devices;
-}
-
-QPlatformMediaFormatInfo *QWindowsMediaIntegration::formatInfo()
-{
- if (!m_formatInfo)
- m_formatInfo = new QWindowsFormatInfo();
- return m_formatInfo;
-}
-
-QPlatformMediaCaptureSession *QWindowsMediaIntegration::createCaptureSession()
-{
- return new QWindowsMediaCaptureService();
-}
-
-QPlatformAudioDecoder *QWindowsMediaIntegration::createAudioDecoder(QAudioDecoder *decoder)
-{
- return new MFAudioDecoderControl(decoder);
-}
-
-QPlatformMediaPlayer *QWindowsMediaIntegration::createPlayer(QMediaPlayer *parent)
-{
- return new MFPlayerControl(parent);
-}
-
-QPlatformCamera *QWindowsMediaIntegration::createCamera(QCamera *camera)
-{
- return new QWindowsCamera(camera);
-}
-
-QPlatformMediaEncoder *QWindowsMediaIntegration::createEncoder(QMediaRecorder *encoder)
-{
- return new QWindowsMediaEncoder(encoder);
-}
-
-QPlatformImageCapture *QWindowsMediaIntegration::createImageCapture(QImageCapture *imageCapture)
-{
- return new QWindowsImageCapture(imageCapture);
-}
-
-QPlatformVideoSink *QWindowsMediaIntegration::createVideoSink(QVideoSink *sink)
-{
- return new MFEvrVideoWindowControl(sink);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/qwindowsintegration_p.h b/src/multimedia/platform/windows/qwindowsintegration_p.h
deleted file mode 100644
index 835d502c1..000000000
--- a/src/multimedia/platform/windows/qwindowsintegration_p.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSINTEGRATION_H
-#define QWINDOWSINTEGRATION_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediaintegration_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsMediaDevices;
-class QWindowsFormatInfo;
-
-class QWindowsMediaIntegration : public QPlatformMediaIntegration
-{
-public:
- QWindowsMediaIntegration();
- ~QWindowsMediaIntegration();
-
- void addRefCount();
- void releaseRefCount();
-
- QPlatformMediaDevices *devices() override;
- QPlatformMediaFormatInfo *formatInfo() override;
-
- QPlatformMediaCaptureSession *createCaptureSession() override;
-
- QPlatformAudioDecoder *createAudioDecoder(QAudioDecoder *decoder) override;
- QPlatformMediaPlayer *createPlayer(QMediaPlayer *parent) override;
- QPlatformCamera *createCamera(QCamera *camera) override;
- QPlatformMediaEncoder *createEncoder(QMediaRecorder *encoder) override;
- QPlatformImageCapture *createImageCapture(QImageCapture *imageCapture) override;
-
- QPlatformVideoSink *createVideoSink(QVideoSink *sink) override;
-
- QWindowsMediaDevices *m_devices = nullptr;
- QWindowsFormatInfo *m_formatInfo = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/windows/qwindowsmediadevices.cpp b/src/multimedia/platform/windows/qwindowsmediadevices.cpp
deleted file mode 100644
index 2b1a74a44..000000000
--- a/src/multimedia/platform/windows/qwindowsmediadevices.cpp
+++ /dev/null
@@ -1,532 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowsmediadevices_p.h"
-#include "qmediadevices.h"
-#include "qcameradevice_p.h"
-#include "qvarlengtharray.h"
-
-#include "private/qwindowsaudiosource_p.h"
-#include "private/qwindowsaudiosink_p.h"
-#include "private/qwindowsaudiodevice_p.h"
-#include "private/qwindowsmultimediautils_p.h"
-
-#include <private/mftvideo_p.h>
-
-#include <Dbt.h>
-#include <ks.h>
-
-#include <mmsystem.h>
-#include <mmddk.h>
-#include <mfapi.h>
-#include <mfobjects.h>
-#include <mfidl.h>
-#include <mfreadwrite.h>
-#include <Mferror.h>
-#include <mmdeviceapi.h>
-#include <Functiondiscoverykeys_devpkey.h>
-#include "private/qwindowsaudioutils_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class CMMNotificationClient : public IMMNotificationClient
-{
- LONG m_cRef;
- QWindowsIUPointer<IMMDeviceEnumerator> m_enumerator;
- QWindowsMediaDevices *m_windowsMediaDevices;
- QMap<QString, DWORD> m_deviceState;
-
-public:
- CMMNotificationClient(QWindowsMediaDevices *windowsMediaDevices,
- QWindowsIUPointer<IMMDeviceEnumerator> enumerator,
- QMap<QString, DWORD> &&deviceState) :
- m_cRef(1),
- m_enumerator(enumerator),
- m_windowsMediaDevices(windowsMediaDevices),
- m_deviceState(deviceState)
- {}
-
- virtual ~CMMNotificationClient() {}
-
- // IUnknown methods -- AddRef, Release, and QueryInterface
- ULONG STDMETHODCALLTYPE AddRef()
- {
- return InterlockedIncrement(&m_cRef);
- }
-
- ULONG STDMETHODCALLTYPE Release()
- {
- ULONG ulRef = InterlockedDecrement(&m_cRef);
- if (0 == ulRef) {
- delete this;
- }
- return ulRef;
- }
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface)
- {
- if (IID_IUnknown == riid) {
- AddRef();
- *ppvInterface = (IUnknown*)this;
- } else if (__uuidof(IMMNotificationClient) == riid) {
- AddRef();
- *ppvInterface = (IMMNotificationClient*)this;
- } else {
- *ppvInterface = NULL;
- return E_NOINTERFACE;
- }
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR)
- {
- if (role == ERole::eMultimedia)
- emitAudioDevicesChanged(flow);
-
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR deviceID)
- {
- auto it = m_deviceState.find(QString::fromWCharArray(deviceID));
- if (it == std::end(m_deviceState)) {
- m_deviceState.insert(QString::fromWCharArray(deviceID), DEVICE_STATE_ACTIVE);
- emitAudioDevicesChanged(deviceID);
- }
-
- return S_OK;
- };
-
- HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR deviceID)
- {
- auto key = QString::fromWCharArray(deviceID);
- auto it = m_deviceState.find(key);
- if (it != std::end(m_deviceState)) {
- if (it.value() == DEVICE_STATE_ACTIVE)
- emitAudioDevicesChanged(deviceID);
- m_deviceState.remove(key);
- }
-
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR deviceID, DWORD newState)
- {
- if (auto it = m_deviceState.find(QString::fromWCharArray(deviceID)); it != std::end(m_deviceState)) {
- // If either the old state or the new state is active emit device change
- if ((it.value() == DEVICE_STATE_ACTIVE) != (newState == DEVICE_STATE_ACTIVE)) {
- emitAudioDevicesChanged(deviceID);
- }
- it.value() = newState;
- }
-
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY)
- {
- return S_OK;
- }
-
- void emitAudioDevicesChanged(EDataFlow flow)
- {
- // windowsMediaDevice may be deleted as we are executing the callback
- if (flow == EDataFlow::eCapture) {
- m_windowsMediaDevices->audioInputsChanged();
- } else if (flow == EDataFlow::eRender) {
- m_windowsMediaDevices->audioOutputsChanged();
- }
- }
-
- void emitAudioDevicesChanged(LPCWSTR deviceID)
- {
- QWindowsIUPointer<IMMDevice> device;
- QWindowsIUPointer<IMMEndpoint> endpoint;
- EDataFlow flow;
-
- if (SUCCEEDED(m_enumerator->GetDevice(deviceID, device.address()))
- && SUCCEEDED(device->QueryInterface(__uuidof(IMMEndpoint), (void**)endpoint.address()))
- && SUCCEEDED(endpoint->GetDataFlow(&flow)))
- {
- emitAudioDevicesChanged(flow);
- }
- }
-};
-
-LRESULT deviceNotificationWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- if (message == WM_DEVICECHANGE) {
- auto b = (PDEV_BROADCAST_HDR)lParam;
- if (b && b->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
- auto wmd = reinterpret_cast<QWindowsMediaDevices *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
-
- if (wmd) {
- if (wParam == DBT_DEVICEARRIVAL) {
- wmd->videoInputsChanged();
- } else if (wParam == DBT_DEVICEREMOVECOMPLETE) {
- wmd->videoInputsChanged();
- }
- }
- }
- }
-
- return 1;
-}
-
-static const auto windowClassName = TEXT("QWindowsMediaDevicesMessageWindow");
-
-HWND createMessageOnlyWindow()
-{
- WNDCLASSEX wx = {};
- wx.cbSize = sizeof(WNDCLASSEX);
- wx.lpfnWndProc = deviceNotificationWndProc;
- wx.hInstance = GetModuleHandle(nullptr);
- wx.lpszClassName = windowClassName;
-
- if (!RegisterClassEx(&wx))
- return nullptr;
-
- auto hwnd = CreateWindowEx(0, windowClassName, TEXT("Message"),
- 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
- if (!hwnd) {
- UnregisterClass(windowClassName, GetModuleHandle(nullptr));
- return nullptr;
- }
-
- return hwnd;
-}
-
-QWindowsMediaDevices::QWindowsMediaDevices()
- : QPlatformMediaDevices(),
- m_videoDeviceMsgWindow(nullptr),
- m_videoDeviceNotification(nullptr)
-
-{
- CoInitialize(nullptr);
-
- auto hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
- CLSCTX_INPROC_SERVER,__uuidof(IMMDeviceEnumerator),
- (void**)&m_deviceEnumerator);
-
- if (SUCCEEDED(hr)) {
- QMap<QString, DWORD> devState;
- QWindowsIUPointer<IMMDeviceCollection> devColl;
- UINT count = 0;
-
- if (SUCCEEDED(m_deviceEnumerator->EnumAudioEndpoints(EDataFlow::eAll, DEVICE_STATEMASK_ALL, devColl.address()))
- && SUCCEEDED(devColl->GetCount(&count)))
- {
- for (UINT i = 0; i < count; i++) {
- QWindowsIUPointer<IMMDevice> device;
- DWORD state = 0;
- LPWSTR id = nullptr;
-
- if (SUCCEEDED(devColl->Item(i, device.address()))
- && SUCCEEDED(device->GetState(&state))
- && SUCCEEDED(device->GetId(&id)))
- {
- devState.insert(QString::fromWCharArray(id), state);
- CoTaskMemFree(id);
- }
- }
- }
-
-
- m_notificationClient.reset(new CMMNotificationClient(this, m_deviceEnumerator, std::move(devState)));
- m_deviceEnumerator->RegisterEndpointNotificationCallback(m_notificationClient);
-
- } else {
- qWarning() << "Audio device change notification disabled";
- }
-
- m_videoDeviceMsgWindow = createMessageOnlyWindow();
- if (m_videoDeviceMsgWindow) {
- SetWindowLongPtr(m_videoDeviceMsgWindow, GWLP_USERDATA, (LONG_PTR)this);
-
- DEV_BROADCAST_DEVICEINTERFACE di = { 0 };
- di.dbcc_size = sizeof(di);
- di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
- di.dbcc_classguid = KSCATEGORY_VIDEO_CAMERA;
-
- m_videoDeviceNotification =
- RegisterDeviceNotification(m_videoDeviceMsgWindow, &di, DEVICE_NOTIFY_WINDOW_HANDLE);
- if (!m_videoDeviceNotification) {
- DestroyWindow(m_videoDeviceMsgWindow);
- m_videoDeviceMsgWindow = nullptr;
-
- UnregisterClass(windowClassName, GetModuleHandle(nullptr));
- }
- }
-
- if (!m_videoDeviceNotification) {
- qWarning() << "Video device change notification disabled";
- }
-}
-
-QWindowsMediaDevices::~QWindowsMediaDevices()
-{
- if (m_deviceEnumerator) {
- m_deviceEnumerator->UnregisterEndpointNotificationCallback(m_notificationClient);
- }
-
- m_deviceEnumerator.reset();
- m_notificationClient.reset();
-
- if (m_videoDeviceNotification) {
- UnregisterDeviceNotification(m_videoDeviceNotification);
- }
-
- if (m_videoDeviceMsgWindow) {
- DestroyWindow(m_videoDeviceMsgWindow);
- UnregisterClass(windowClassName, GetModuleHandle(nullptr));
- }
-
- CoUninitialize();
-}
-
-QList<QAudioDevice> QWindowsMediaDevices::availableDevices(QAudioDevice::Mode mode) const
-{
- const auto audioOut = mode == QAudioDevice::Output;
-
- const auto defaultAudioDeviceID = [this, audioOut]{
- const auto dataFlow = audioOut ? EDataFlow::eRender : EDataFlow::eCapture;
- QWindowsIUPointer<IMMDevice> dev;
- LPWSTR id = nullptr;
- QString sid;
-
- if (SUCCEEDED(m_deviceEnumerator->GetDefaultAudioEndpoint(dataFlow, ERole::eMultimedia, dev.address()))
- && SUCCEEDED(dev->GetId(&id))) {
- sid = QString::fromWCharArray(id);
- CoTaskMemFree(id);
- }
- return sid.toUtf8();
- }();
-
- QList<QAudioDevice> devices;
-
- auto waveDevices = audioOut ? waveOutGetNumDevs() : waveInGetNumDevs();
-
- for (auto waveID = 0u; waveID < waveDevices; waveID++) {
- auto wave = IntToPtr(waveID);
- auto waveMessage = [wave, audioOut](UINT msg, auto p0, auto p1) {
- return audioOut ? waveOutMessage((HWAVEOUT)wave, msg, (DWORD_PTR)p0, (DWORD_PTR)p1)
- : waveInMessage((HWAVEIN)wave, msg, (DWORD_PTR)p0, (DWORD_PTR)p1);
- };
-
- size_t len = 0;
- if (waveMessage(DRV_QUERYFUNCTIONINSTANCEIDSIZE, &len, 0) != MMSYSERR_NOERROR)
- continue;
-
- QVarLengthArray<WCHAR> id(len);
- if (waveMessage(DRV_QUERYFUNCTIONINSTANCEID, id.data(), len) != MMSYSERR_NOERROR)
- continue;
-
- QWindowsIUPointer<IMMDevice> device;
- QWindowsIUPointer<IPropertyStore> props;
- if (FAILED(m_deviceEnumerator->GetDevice(id.data(), device.address()))
- || FAILED(device->OpenPropertyStore(STGM_READ, props.address()))) {
- continue;
- }
-
- PROPVARIANT varName;
- PropVariantInit(&varName);
-
- if (SUCCEEDED(props->GetValue(PKEY_Device_FriendlyName, &varName))) {
- auto description = QString::fromWCharArray(varName.pwszVal);
- auto strID = QString::fromWCharArray(id.data()).toUtf8();
-
- auto dev = new QWindowsAudioDeviceInfo(strID, waveID, description, mode);
- dev->isDefault = strID == defaultAudioDeviceID;
-
- devices.append(dev->create());
- }
- PropVariantClear(&varName);
- }
-
- return devices;
-}
-
-QList<QAudioDevice> QWindowsMediaDevices::audioInputs() const
-{
- return availableDevices(QAudioDevice::Input);
-}
-
-QList<QAudioDevice> QWindowsMediaDevices::audioOutputs() const
-{
- return availableDevices(QAudioDevice::Output);
-}
-
-QList<QCameraDevice> QWindowsMediaDevices::videoInputs() const
-{
- QList<QCameraDevice> cameras;
-
- IMFAttributes *pAttributes = NULL;
- IMFActivate **ppDevices = NULL;
-
- // Create an attribute store to specify the enumeration parameters.
- HRESULT hr = MFCreateAttributes(&pAttributes, 1);
- if (SUCCEEDED(hr)) {
- // Source type: video capture devices
- hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
- MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
-
- if (SUCCEEDED(hr)) {
- // Enumerate devices.
- UINT32 count;
- hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
- if (SUCCEEDED(hr)) {
- // Iterate through devices.
- for (int index = 0; index < int(count); index++) {
- QCameraDevicePrivate *info = new QCameraDevicePrivate;
-
- IMFMediaSource *pSource = NULL;
- IMFSourceReader *reader = NULL;
-
- WCHAR *deviceName = NULL;
- UINT32 deviceNameLength = 0;
- UINT32 deviceIdLength = 0;
- WCHAR *deviceId = NULL;
-
- hr = ppDevices[index]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
- &deviceName, &deviceNameLength);
- if (SUCCEEDED(hr))
- info->description = QString::fromWCharArray(deviceName);
- CoTaskMemFree(deviceName);
-
- hr = ppDevices[index]->GetAllocatedString(
- MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &deviceId,
- &deviceIdLength);
- if (SUCCEEDED(hr))
- info->id = QString::fromWCharArray(deviceId).toUtf8();
- CoTaskMemFree(deviceId);
-
- // Create the media source object.
- hr = ppDevices[index]->ActivateObject(
- IID_PPV_ARGS(&pSource));
- // Create the media source reader.
- hr = MFCreateSourceReaderFromMediaSource(pSource, NULL, &reader);
- if (SUCCEEDED(hr)) {
- QList<QSize> photoResolutions;
- QList<QCameraFormat> videoFormats;
-
- DWORD dwMediaTypeIndex = 0;
- IMFMediaType *mediaFormat = NULL;
- GUID subtype = GUID_NULL;
- HRESULT mediaFormatResult = S_OK;
-
- UINT32 frameRateMin = 0u;
- UINT32 frameRateMax = 0u;
- UINT32 denominator = 0u;
- DWORD index = 0u;
- UINT32 width = 0u;
- UINT32 height = 0u;
-
- while (SUCCEEDED(mediaFormatResult)) {
- // Loop through the supported formats for the video device
- mediaFormatResult = reader->GetNativeMediaType(
- (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, dwMediaTypeIndex,
- &mediaFormat);
- if (mediaFormatResult == MF_E_NO_MORE_TYPES)
- break;
- else if (SUCCEEDED(mediaFormatResult)) {
- QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
- QSize resolution;
- float minFr = .0;
- float maxFr = .0;
-
- if (SUCCEEDED(mediaFormat->GetGUID(MF_MT_SUBTYPE, &subtype)))
- pixelFormat = QWindowsMultimediaUtils::pixelFormatFromMediaSubtype(subtype);
-
- if (SUCCEEDED(MFGetAttributeSize(mediaFormat, MF_MT_FRAME_SIZE, &width,
- &height))) {
- resolution.rheight() = (int)height;
- resolution.rwidth() = (int)width;
- photoResolutions << resolution;
- }
-
- if (SUCCEEDED(MFGetAttributeRatio(mediaFormat, MF_MT_FRAME_RATE_RANGE_MIN,
- &frameRateMin, &denominator)))
- minFr = qreal(frameRateMin) / denominator;
- if (SUCCEEDED(MFGetAttributeRatio(mediaFormat, MF_MT_FRAME_RATE_RANGE_MAX,
- &frameRateMax, &denominator)))
- maxFr = qreal(frameRateMax) / denominator;
-
- auto *f = new QCameraFormatPrivate { QSharedData(), pixelFormat,
- resolution, minFr, maxFr };
- videoFormats << f->create();
- }
- ++dwMediaTypeIndex;
- }
- if (mediaFormat)
- mediaFormat->Release();
-
- info->videoFormats = videoFormats;
- info->photoResolutions = photoResolutions;
- }
- if (reader)
- reader->Release();
- cameras.append(info->create());
- }
- }
- for (DWORD i = 0; i < count; i++) {
- if (ppDevices[i])
- ppDevices[i]->Release();
- }
- CoTaskMemFree(ppDevices);
- }
- }
- if (pAttributes)
- pAttributes->Release();
-
- return cameras;
-}
-
-QPlatformAudioSource *QWindowsMediaDevices::createAudioSource(const QAudioDevice &deviceInfo)
-{
- const auto *devInfo = static_cast<const QWindowsAudioDeviceInfo *>(deviceInfo.handle());
- return new QWindowsAudioSource(devInfo->waveId());
-}
-
-QPlatformAudioSink *QWindowsMediaDevices::createAudioSink(const QAudioDevice &deviceInfo)
-{
- const auto *devInfo = static_cast<const QWindowsAudioDeviceInfo *>(deviceInfo.handle());
- return new QWindowsAudioSink(devInfo->waveId());
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/platform/windows/qwindowsmediadevices_p.h b/src/multimedia/platform/windows/qwindowsmediadevices_p.h
deleted file mode 100644
index 29e214d79..000000000
--- a/src/multimedia/platform/windows/qwindowsmediadevices_p.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSMEDIADEVICES_H
-#define QWINDOWSMEDIADEVICES_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qplatformmediadevices_p.h>
-#include <private/qwindowsiupointer_p.h>
-#include <qset.h>
-#include <qaudio.h>
-#include <qaudiodevice.h>
-#include <windows.h>
-
-struct IMMDeviceEnumerator;
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsEngine;
-class CMMNotificationClient;
-
-LRESULT deviceNotificationWndProc(HWND, UINT, WPARAM, LPARAM);
-
-class QWindowsMediaDevices : public QPlatformMediaDevices
-{
-public:
- QWindowsMediaDevices();
- virtual ~QWindowsMediaDevices();
-
- QList<QAudioDevice> audioInputs() const override;
- QList<QAudioDevice> audioOutputs() const override;
- QList<QCameraDevice> videoInputs() const override;
- QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo) override;
- QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo) override;
-
-private:
- QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode) const;
-
- QWindowsIUPointer<IMMDeviceEnumerator> m_deviceEnumerator;
- QWindowsIUPointer<CMMNotificationClient> m_notificationClient;
- HWND m_videoDeviceMsgWindow;
- HDEVNOTIFY m_videoDeviceNotification;
-
- friend CMMNotificationClient;
- friend LRESULT deviceNotificationWndProc(HWND, UINT, WPARAM, LPARAM);
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/windows/sourceresolver.cpp b/src/multimedia/platform/windows/sourceresolver.cpp
deleted file mode 100644
index 93af15a74..000000000
--- a/src/multimedia/platform/windows/sourceresolver.cpp
+++ /dev/null
@@ -1,325 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "mfstream_p.h"
-#include "sourceresolver_p.h"
-#include <mferror.h>
-#include <nserror.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qdebug.h>
-#include <QtMultimedia/qmediaplayer.h>
-
-/*
- SourceResolver is separated from MFPlayerSession to handle the work of resolving a media source
- asynchronously. You call SourceResolver::load to request resolving a media source asynchronously,
- and it will emit mediaSourceReady() when resolving is done. You can call SourceResolver::cancel to
- stop the previous load operation if there is any.
-*/
-
-SourceResolver::SourceResolver()
- : m_cRef(1)
- , m_cancelCookie(0)
- , m_sourceResolver(0)
- , m_mediaSource(0)
- , m_stream(0)
-{
-}
-
-SourceResolver::~SourceResolver()
-{
- shutdown();
- if (m_mediaSource) {
- m_mediaSource->Release();
- m_mediaSource = NULL;
- }
-
- if (m_cancelCookie)
- m_cancelCookie->Release();
- if (m_sourceResolver)
- m_sourceResolver->Release();
-}
-
-STDMETHODIMP SourceResolver::QueryInterface(REFIID riid, LPVOID *ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else if (riid == IID_IMFAsyncCallback) {
- *ppvObject = static_cast<IMFAsyncCallback*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) SourceResolver::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) SourceResolver::Release(void)
-{
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- this->deleteLater();
- return cRef;
-}
-
-HRESULT STDMETHODCALLTYPE SourceResolver::Invoke(IMFAsyncResult *pAsyncResult)
-{
- QMutexLocker locker(&m_mutex);
-
- if (!m_sourceResolver)
- return S_OK;
-
- MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
- IUnknown* pSource = NULL;
- State *state = static_cast<State*>(pAsyncResult->GetStateNoAddRef());
-
- HRESULT hr = S_OK;
- if (state->fromStream())
- hr = m_sourceResolver->EndCreateObjectFromByteStream(pAsyncResult, &ObjectType, &pSource);
- else
- hr = m_sourceResolver->EndCreateObjectFromURL(pAsyncResult, &ObjectType, &pSource);
-
- if (state->sourceResolver() != m_sourceResolver) {
- //This is a cancelled one
- return S_OK;
- }
-
- if (m_cancelCookie) {
- m_cancelCookie->Release();
- m_cancelCookie = NULL;
- }
-
- if (FAILED(hr)) {
- emit error(hr);
- return S_OK;
- }
-
- if (m_mediaSource) {
- m_mediaSource->Release();
- m_mediaSource = NULL;
- }
-
- hr = pSource->QueryInterface(IID_PPV_ARGS(&m_mediaSource));
- pSource->Release();
- if (FAILED(hr)) {
- emit error(hr);
- return S_OK;
- }
-
- emit mediaSourceReady();
-
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE SourceResolver::GetParameters(DWORD*, DWORD*)
-{
- return E_NOTIMPL;
-}
-
-void SourceResolver::load(const QUrl &url, QIODevice* stream)
-{
- QMutexLocker locker(&m_mutex);
- HRESULT hr = S_OK;
- if (!m_sourceResolver)
- hr = MFCreateSourceResolver(&m_sourceResolver);
-
- if (m_stream) {
- m_stream->Release();
- m_stream = NULL;
- }
-
- if (FAILED(hr)) {
- qWarning() << "Failed to create Source Resolver!";
- emit error(hr);
- } else if (stream) {
- QString urlString = url.toString();
- m_stream = new MFStream(stream, false);
- hr = m_sourceResolver->BeginCreateObjectFromByteStream(
- m_stream, urlString.isEmpty() ? 0 : reinterpret_cast<LPCWSTR>(urlString.utf16()),
- MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
- , NULL, &m_cancelCookie, this, new State(m_sourceResolver, true));
- if (FAILED(hr)) {
- qWarning() << "Unsupported stream!";
- emit error(hr);
- }
- } else {
-#ifdef DEBUG_MEDIAFOUNDATION
- qDebug() << "loading :" << url;
- qDebug() << "url path =" << url.path().mid(1);
-#endif
-#ifdef TEST_STREAMING
- //Testing stream function
- if (url.scheme() == QLatin1String("file")) {
- stream = new QFile(url.path().mid(1));
- if (stream->open(QIODevice::ReadOnly)) {
- m_stream = new MFStream(stream, true);
- hr = m_sourceResolver->BeginCreateObjectFromByteStream(
- m_stream, reinterpret_cast<const OLECHAR *>(url.toString().utf16()),
- MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE,
- NULL, &m_cancelCookie, this, new State(m_sourceResolver, true));
- if (FAILED(hr)) {
- qWarning() << "Unsupported stream!";
- emit error(hr);
- }
- } else {
- delete stream;
- emit error(QMediaPlayer::FormatError);
- }
- } else
-#endif
- if (url.scheme() == QLatin1String("qrc")) {
- // If the canonical URL refers to a Qt resource, open with QFile and use
- // the stream playback capability to play.
- stream = new QFile(QLatin1Char(':') + url.path());
- if (stream->open(QIODevice::ReadOnly)) {
- m_stream = new MFStream(stream, true);
- hr = m_sourceResolver->BeginCreateObjectFromByteStream(
- m_stream, reinterpret_cast<const OLECHAR *>(url.toString().utf16()),
- MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE,
- NULL, &m_cancelCookie, this, new State(m_sourceResolver, true));
- if (FAILED(hr)) {
- qWarning() << "Unsupported stream!";
- emit error(hr);
- }
- } else {
- delete stream;
- emit error(QMediaPlayer::FormatError);
- }
- } else {
- hr = m_sourceResolver->BeginCreateObjectFromURL(
- reinterpret_cast<const OLECHAR *>(url.toString().utf16()),
- MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE,
- NULL, &m_cancelCookie, this, new State(m_sourceResolver, false));
- if (FAILED(hr)) {
- qWarning() << "Unsupported url scheme!";
- emit error(hr);
- }
- }
- }
-}
-
-void SourceResolver::cancel()
-{
- QMutexLocker locker(&m_mutex);
- if (m_cancelCookie) {
- m_sourceResolver->CancelObjectCreation(m_cancelCookie);
- m_cancelCookie->Release();
- m_cancelCookie = NULL;
- m_sourceResolver->Release();
- m_sourceResolver = NULL;
- }
-}
-
-void SourceResolver::shutdown()
-{
- if (m_mediaSource) {
- m_mediaSource->Shutdown();
- m_mediaSource->Release();
- m_mediaSource = NULL;
- }
-
- if (m_stream) {
- m_stream->Release();
- m_stream = NULL;
- }
-}
-
-IMFMediaSource* SourceResolver::mediaSource() const
-{
- return m_mediaSource;
-}
-
-/////////////////////////////////////////////////////////////////////////////////
-SourceResolver::State::State(IMFSourceResolver *sourceResolver, bool fromStream)
- : m_cRef(0)
- , m_sourceResolver(sourceResolver)
- , m_fromStream(fromStream)
-{
- sourceResolver->AddRef();
-}
-
-SourceResolver::State::~State()
-{
- m_sourceResolver->Release();
-}
-
-STDMETHODIMP SourceResolver::State::QueryInterface(REFIID riid, LPVOID *ppvObject)
-{
- if (!ppvObject)
- return E_POINTER;
- if (riid == IID_IUnknown) {
- *ppvObject = static_cast<IUnknown*>(this);
- } else {
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return S_OK;
-}
-
-STDMETHODIMP_(ULONG) SourceResolver::State::AddRef(void)
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG) SourceResolver::State::Release(void)
-{
- LONG cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- delete this;
- // For thread safety, return a temporary variable.
- return cRef;
-}
-
-IMFSourceResolver* SourceResolver::State::sourceResolver() const
-{
- return m_sourceResolver;
-}
-
-bool SourceResolver::State::fromStream() const
-{
- return m_fromStream;
-}
-
diff --git a/src/multimedia/platform/windows/sourceresolver_p.h b/src/multimedia/platform/windows/sourceresolver_p.h
deleted file mode 100644
index 07da1d8bd..000000000
--- a/src/multimedia/platform/windows/sourceresolver_p.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef SOURCERESOLVER_H
-#define SOURCERESOLVER_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 "mfstream_p.h"
-#include <QUrl>
-
-class SourceResolver: public QObject, public IMFAsyncCallback
-{
- Q_OBJECT
-public:
- SourceResolver();
-
- ~SourceResolver();
-
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
- STDMETHODIMP_(ULONG) AddRef(void);
- STDMETHODIMP_(ULONG) Release(void);
-
- HRESULT STDMETHODCALLTYPE Invoke(IMFAsyncResult *pAsyncResult);
-
- HRESULT STDMETHODCALLTYPE GetParameters(DWORD*, DWORD*);
-
- void load(const QUrl &url, QIODevice* stream);
-
- void cancel();
-
- void shutdown();
-
- IMFMediaSource* mediaSource() const;
-
-Q_SIGNALS:
- void error(long hr);
- void mediaSourceReady();
-
-private:
- class State : public IUnknown
- {
- public:
- State(IMFSourceResolver *sourceResolver, bool fromStream);
- ~State();
-
- STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
-
- STDMETHODIMP_(ULONG) AddRef(void);
-
- STDMETHODIMP_(ULONG) Release(void);
-
- IMFSourceResolver* sourceResolver() const;
- bool fromStream() const;
-
- private:
- long m_cRef;
- IMFSourceResolver *m_sourceResolver;
- bool m_fromStream;
- };
-
- long m_cRef;
- IUnknown *m_cancelCookie;
- IMFSourceResolver *m_sourceResolver;
- IMFMediaSource *m_mediaSource;
- MFStream *m_stream;
- QMutex m_mutex;
-};
-
-#endif
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index ac44433be..dc8e3dab8 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qmediaplayer_p.h"
+#include <private/qmultimediautils_p.h>
#include <private/qplatformmediaintegration_p.h>
#include <qvideosink.h>
#include <qaudiooutput.h>
@@ -47,10 +12,15 @@
#include <QtCore/qmetaobject.h>
#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
#include <QtCore/qpointer.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qtemporaryfile.h>
-#include <QtCore/qdir.h>
+#include <QtCore/qcoreapplication.h>
+
+#if defined(Q_OS_ANDROID)
+# include <QtCore/qjniobject.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -60,6 +30,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_playback
+ \ingroup multimedia_video
The QMediaPlayer class is a high level media playback class. It can be used
to playback audio of video media files. The content
@@ -72,13 +43,70 @@ QT_BEGIN_NAMESPACE
\sa QVideoWidget
*/
-void QMediaPlayerPrivate::setState(QMediaPlayer::PlaybackState ps)
+/*!
+ \qmltype MediaPlayer
+ \instantiates QMediaPlayer
+ \brief Adds media playback to a scene.
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+ \ingroup multimedia_video_qml
+
+ \qml
+ Text {
+ text: "Click Me!";
+ font.pointSize: 24;
+ width: 150; height: 50;
+
+ MediaPlayer {
+ id: playMusic
+ source: "music.wav"
+ audioOutput: AudioOutput {}
+ }
+ MouseArea {
+ anchors.fill: parent
+ onPressed: { playMusic.play() }
+ }
+ }
+ \endqml
+
+ You can use MediaPlayer together with a MultiMedia::AudioOutput to play audio content, or you can use it
+ in conjunction with a Multimedia::VideoOutput for rendering video.
+
+ \qml
+ Item {
+ MediaPlayer {
+ id: mediaplayer
+ source: "groovy_video.mp4"
+ audioOutput: AudioOutput {}
+ videoOutput: videoOutput
+ }
+
+ VideoOutput {
+ id: videoOutput
+ anchors.fill: parent
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: mediaplayer.play();
+ }
+ }
+ \endqml
+
+ \sa AudioOutput, VideoOutput
+*/
+
+void QMediaPlayerPrivate::setState(QMediaPlayer::PlaybackState toState)
{
Q_Q(QMediaPlayer);
- if (ps != state) {
- state = ps;
- emit q->playbackStateChanged(ps);
+ if (toState != state) {
+ const auto fromState = std::exchange(state, toState);
+ if (toState == QMediaPlayer::PlayingState || fromState == QMediaPlayer::PlayingState)
+ emit q->playingChanged(toState == QMediaPlayer::PlayingState);
+ emit q->playbackStateChanged(toState);
}
}
@@ -89,14 +117,11 @@ void QMediaPlayerPrivate::setStatus(QMediaPlayer::MediaStatus s)
emit q->mediaStatusChanged(s);
}
-void QMediaPlayerPrivate::setError(int error, const QString &errorString)
+void QMediaPlayerPrivate::setError(QMediaPlayer::Error error, const QString &errorString)
{
Q_Q(QMediaPlayer);
- this->error = QMediaPlayer::Error(error);
- this->errorString = errorString;
- emit q->errorChanged();
- emit q->errorOccurred(this->error, errorString);
+ this->error.setAndNotify(error, errorString, *q);
}
void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
@@ -104,7 +129,7 @@ void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
if (!control)
return;
- QScopedPointer<QFile> file;
+ std::unique_ptr<QFile> file;
// Back ends can't play qrc files directly.
// If the back end supports StreamPlayback, we pass a QFile for that resource.
@@ -120,7 +145,7 @@ void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
control->error(QMediaPlayer::ResourceError, QMediaPlayer::tr("Attempting to play invalid Qt resource"));
} else if (control->streamPlaybackSupported()) {
- control->setMedia(media, file.data());
+ control->setMedia(media, file.get());
} else {
#if QT_CONFIG(temporaryfile)
#if defined(Q_OS_ANDROID)
@@ -139,7 +164,14 @@ void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
tempFile->setFileTemplate(tempFile->fileTemplate() + QLatin1Char('.') + suffix);
// Copy the qrc data into the temporary file
- tempFile->open();
+ if (!tempFile->open()) {
+ control->setMedia(QUrl(), nullptr);
+ control->mediaStatusChanged(QMediaPlayer::InvalidMedia);
+ control->error(QMediaPlayer::ResourceError, tempFile->errorString());
+ delete tempFile;
+ qrcFile.reset();
+ return;
+ }
char buffer[4096];
while (true) {
qint64 len = file->read(buffer, sizeof(buffer));
@@ -157,7 +189,13 @@ void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
}
} else {
qrcMedia = QUrl();
- control->setMedia(media, stream);
+ QUrl url = qMediaFromUserInput(media);
+ if (url.scheme() == QLatin1String("content") && !stream) {
+ file.reset(new QFile(media.url()));
+ stream = file.get();
+ }
+
+ control->setMedia(url, stream);
}
qrcFile.swap(file); // Cleans up any previous file
@@ -184,14 +222,14 @@ QMediaPlayer::QMediaPlayer(QObject *parent)
{
Q_D(QMediaPlayer);
- d->control = QPlatformMediaIntegration::instance()->createPlayer(this);
- if (!d->control) { // ### Should this be an assertion?
- d->setError(QMediaPlayer::ResourceError, QMediaPlayer::tr("Platform does not support media playback."));
- return;
+ auto maybeControl = QPlatformMediaIntegration::instance()->createPlayer(this);
+ if (maybeControl) {
+ d->control = maybeControl.value();
+ d->state = d->control->state();
+ } else {
+ qWarning() << "Failed to initialize QMediaPlayer" << maybeControl.error();
+ d->setError(QMediaPlayer::ResourceError, maybeControl.error());
}
- Q_ASSERT(d->control);
-
- d->state = d->control->state();
}
@@ -203,9 +241,14 @@ QMediaPlayer::~QMediaPlayer()
{
Q_D(QMediaPlayer);
- // Disconnect everything to prevent notifying
- // when a receiver is already destroyed.
- disconnect();
+ // prevents emitting audioOutputChanged and videoOutputChanged.
+ QSignalBlocker blocker(this);
+
+ // Reset audio output and video sink to ensure proper unregistering of the source
+ // To be investigated: registering of the source might be removed after switching on the ffmpeg
+ // backend;
+
+ setAudioOutput(nullptr);
d->setVideoSink(nullptr);
delete d->control;
@@ -233,13 +276,20 @@ const QIODevice *QMediaPlayer::sourceDevice() const
return d->stream;
}
+/*!
+ \property QMediaPlayer::playbackState
+
+ Returns the \l{QMediaPlayer::}{PlaybackState}.
+
+ \sa playing
+*/
QMediaPlayer::PlaybackState QMediaPlayer::playbackState() const
{
Q_D(const QMediaPlayer);
// In case if EndOfMedia status is already received
// but state is not.
- if (d->control != nullptr
+ if (d->control
&& d->control->mediaStatus() == QMediaPlayer::EndOfMedia
&& d->state != d->control->state()) {
return d->control->state();
@@ -264,11 +314,7 @@ QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const
qint64 QMediaPlayer::duration() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->duration();
-
- return 0;
+ return d->control ? d->control->duration() : 0;
}
/*!
@@ -281,15 +327,11 @@ qint64 QMediaPlayer::duration() const
qint64 QMediaPlayer::position() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->position();
-
- return 0;
+ return d->control ? d->control->position() : 0;
}
/*!
- Returns a number betwee 0 and 1 when buffering data.
+ Returns a number between 0 and 1 when buffering data.
0 means that there is no buffered data available, playback is usually
stalled in this case. Playback will resume once the buffer reaches 1,
@@ -300,11 +342,7 @@ qint64 QMediaPlayer::position() const
float QMediaPlayer::bufferProgress() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->bufferProgress();
-
- return 0.;
+ return d->control ? d->control->bufferProgress() : 0;
}
/*!
@@ -319,31 +357,39 @@ float QMediaPlayer::bufferProgress() const
QMediaTimeRange QMediaPlayer::bufferedTimeRange() const
{
Q_D(const QMediaPlayer);
+ return d->control ? d->control->availablePlaybackRanges() : QMediaTimeRange{};
+}
- if (d->control)
- return d->control->availablePlaybackRanges();
+/*!
+ \qmlproperty bool QtMultimedia::MediaPlayer::hasAudio
- return {};
-}
+ This property holds whether the media contains audio.
+*/
+/*!
+ \property QMediaPlayer::hasAudio
+ \brief This property holds whether the media contains audio.
+*/
bool QMediaPlayer::hasAudio() const
{
Q_D(const QMediaPlayer);
+ return d->control && d->control->isAudioAvailable();
+}
- if (d->control != nullptr)
- return d->control->isAudioAvailable();
+/*!
+ \qmlproperty bool QtMultimedia::MediaPlayer::hasVideo
- return false;
-}
+ This property holds whether the media contains video.
+*/
+/*!
+ \property QMediaPlayer::hasVideo
+ \brief This property holds whether the media contains video.
+*/
bool QMediaPlayer::hasVideo() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->isVideoAvailable();
-
- return false;
+ return d->control && d->control->isVideoAvailable();
}
/*!
@@ -355,11 +401,13 @@ bool QMediaPlayer::hasVideo() const
bool QMediaPlayer::isSeekable() const
{
Q_D(const QMediaPlayer);
+ return d->control && d->control->isSeekable();
+}
- if (d->control != nullptr)
- return d->control->isSeekable();
-
- return false;
+bool QMediaPlayer::isPlaying() const
+{
+ Q_D(const QMediaPlayer);
+ return d->state == QMediaPlayer::PlayingState;
}
/*!
@@ -368,11 +416,48 @@ bool QMediaPlayer::isSeekable() const
qreal QMediaPlayer::playbackRate() const
{
Q_D(const QMediaPlayer);
+ return d->control ? d->control->playbackRate() : 0.;
+}
+
+/*!
+ \enum QMediaPlayer::Loops
+
+ Some predefined constants for the \l loops property.
+
+ \value Infinite Loop forever.
+ \value Once Play the media once (the default).
+*/
- if (d->control != nullptr)
- return d->control->playbackRate();
+/*!
+ \property QMediaPlayer::loops
+
+ Determines how often the media is played before the player stops.
+ Set to QMediaPlayer::Infinite to loop the current media file forever.
- return 0.0;
+ The default value is \c 1. Setting this property to \c 0 has no effect.
+*/
+
+/*!
+ \qmlproperty int QtMultimedia::MediaPlayer::loops
+
+ Determines how often the media is played before the player stops.
+ Set to MediaPlayer::Infinite to loop the current media file forever.
+
+ The default value is \c 1. Setting this property to \c 0 has no effect.
+*/
+int QMediaPlayer::loops() const
+{
+ Q_D(const QMediaPlayer);
+ return d->control ? d->control->loops() : 1;
+}
+
+void QMediaPlayer::setLoops(int loops)
+{
+ Q_D(QMediaPlayer);
+ if (loops == 0)
+ return;
+ if (d->control)
+ d->control->setLoops(loops);
}
/*!
@@ -380,18 +465,40 @@ qreal QMediaPlayer::playbackRate() const
*/
QMediaPlayer::Error QMediaPlayer::error() const
{
- return d_func()->error;
+ return d_func()->error.code();
}
+/*!
+ \qmlproperty string QtMultimedia::MediaPlayer::errorString
+
+ This property holds a string describing the current error condition in more
+ detail.
+*/
+
+/*!
+ \property QMediaPlayer::errorString
+ \brief This property holds a string describing the current error condition in
+ more detail.
+*/
QString QMediaPlayer::errorString() const
{
- return d_func()->errorString;
+ return d_func()->error.description();
}
/*!
- Start or resume playing the current source.
+ \qmlmethod QtMultimedia::MediaPlayer::play()
+
+ Starts or resumes playback of the media.
+
+ Sets the \l playbackState property to PlayingState, and changes
+ \l playing to \c true.
*/
+/*!
+ Start or resume playing the current source.
+
+ \sa pause(), stop()
+*/
void QMediaPlayer::play()
{
Q_D(QMediaPlayer);
@@ -400,33 +507,52 @@ void QMediaPlayer::play()
return;
// Reset error conditions
- d->error = NoError;
- d->errorString = QString();
+ d->setError(NoError, QString());
d->control->play();
}
/*!
- Pause playing the current source.
+ \qmlmethod QtMultimedia::MediaPlayer::pause()
+
+ Pauses playback of the media.
+
+ Sets the \l playbackState property to PausedState,
+ and changes \l playing to \c false.
*/
+/*!
+ Pause playing the current source.
+
+ \sa play(), stop()
+*/
void QMediaPlayer::pause()
{
Q_D(QMediaPlayer);
- if (d->control != nullptr)
+ if (d->control)
d->control->pause();
}
/*!
- Stop playing, and reset the play position to the beginning.
+ \qmlmethod QtMultimedia::MediaPlayer::stop()
+
+ Stops playback of the media.
+
+ Sets the \l playbackState property to StoppedState,
+ and changes \l playing to \c false.
*/
+/*!
+ Stop playing, and reset the play position to the beginning.
+
+ \sa play(), pause()
+*/
void QMediaPlayer::stop()
{
Q_D(QMediaPlayer);
- if (d->control != nullptr)
+ if (d->control)
d->control->stop();
}
@@ -434,9 +560,10 @@ void QMediaPlayer::setPosition(qint64 position)
{
Q_D(QMediaPlayer);
- if (d->control == nullptr)
+ if (!d->control)
+ return;
+ if (!d->control->isSeekable())
return;
-
d->control->setPosition(qMax(position, 0ll));
}
@@ -444,16 +571,26 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
{
Q_D(QMediaPlayer);
- if (d->control != nullptr)
+ if (d->control)
d->control->setPlaybackRate(rate);
}
/*!
+ \qmlproperty url QtMultimedia::MediaPlayer::source
+
+ This property holds the source URL of the media.
+
+ \snippet multimedia-snippets/qtvideosink.qml complete
+
+ \sa QMediaPlayer::setSource()
+*/
+
+/*!
Sets the current \a source.
Setting the media to a null QUrl will cause the player to discard all
information relating to the current media source and to cease all I/O operations related
- to that media.
+ to that media. Setting the media will stop the playback.
\note This function returns immediately after recording the specified source of the media.
It does not wait for the media to finish loading and does not check for errors. Listen for
@@ -506,21 +643,40 @@ void QMediaPlayer::setSourceDevice(QIODevice *device, const QUrl &sourceUrl)
}
/*!
- Sets the audio \a output device.
+ \qmlproperty AudioOutput QtMultimedia::MediaPlayer::audioOutput
- If \a output is \nullptr, sets the output to the system default output
- device.
+ This property holds the target audio output.
+ Accepts one AudioOutput elements.
- Listen for the audioOutputChanged() signal to be notified if the output is
- successfully changed.
+ \sa QMediaPlayer::setAudioOutput()
+*/
+
+
+/*!
+ \property QMediaPlayer::audioOutput
+ \brief The audio output device used by the media player.
+
+ The current audio output to be used when playing back media. Setting
+ a new audio output will replace the currently used output.
+
+ Setting this property to \c nullptr will disable any audio output.
*/
void QMediaPlayer::setAudioOutput(QAudioOutput *output)
{
Q_D(QMediaPlayer);
- if (d->audioOutput == output)
+ auto oldOutput = d->audioOutput;
+ if (oldOutput == output)
return;
d->audioOutput = output;
- d->control->setAudioOutput(output ? output->handle() : nullptr);
+ if (d->control)
+ d->control->setAudioOutput(nullptr);
+ if (oldOutput)
+ oldOutput->setDisconnectFunction({});
+ if (output) {
+ output->setDisconnectFunction([this](){ setAudioOutput(nullptr); });
+ if (d->control)
+ d->control->setAudioOutput(output->handle());
+ }
emit audioOutputChanged();
}
@@ -531,6 +687,21 @@ QAudioOutput *QMediaPlayer::audioOutput() const
}
/*!
+ \qmlproperty list<mediaMetaData> QtMultimedia::MediaPlayer::audioTracks
+
+ This property holds a list of metadata.
+ Each index refers to an audio track.
+
+ The metadata holds properties describing the individual tracks. For
+ audio tracks the \l{QMediaMetaData}{Language} is usually the most
+ important property.
+
+ \sa mediaMetaData
+*/
+
+/*!
+ \property QMediaPlayer::audioTracks
+
Lists the set of available audio tracks inside the media.
The QMediaMetaData returned describes the properties of individual
@@ -545,6 +716,19 @@ QList<QMediaMetaData> QMediaPlayer::audioTracks() const
}
/*!
+ \qmlproperty list<mediaMetaData> QtMultimedia::MediaPlayer::videoTracks
+
+ This property holds a list of metadata.
+ Each index refers to a video track.
+
+ The metadata holds properties describing the individual tracks.
+
+ \sa mediaMetaData
+*/
+
+/*!
+ \property QMediaPlayer::videoTracks
+
Lists the set of available video tracks inside the media.
The QMediaMetaData returned describes the properties of individual
@@ -557,6 +741,21 @@ QList<QMediaMetaData> QMediaPlayer::videoTracks() const
}
/*!
+ \qmlproperty list<mediaMetaData> QtMultimedia::MediaPlayer::subtitleTracks
+
+ This property holds a list of metadata.
+ Each index refers to a subtitle track.
+
+ The metadata holds properties describing the individual tracks. For
+ subtitle tracks the \l{QMediaMetaData}{Language} is usually the most
+ important property.
+
+ \sa mediaMetaData
+*/
+
+/*!
+ \property QMediaPlayer::subtitleTracks
+
Lists the set of available subtitle tracks inside the media.
The QMediaMetaData returned describes the properties of individual
@@ -569,45 +768,76 @@ QList<QMediaMetaData> QMediaPlayer::subtitleTracks() const
}
/*!
- Returns the currently active audio track.
+ \qmlproperty int QtMultimedia::MediaPlayer::activeAudioTrack
+
+ This property holds the track number of the currently active audio track.
+ Set to \c{-1} to disable audio track.
+
+ The default property value is \c{0}: the first audio track.
+*/
+
+/*!
+ \property QMediaPlayer::activeAudioTrack
+ \brief Returns the currently active audio track.
+
+ By default, the first available audio track will be chosen.
+
+ Set \a index to \c -1 to disable all audio tracks.
*/
int QMediaPlayer::activeAudioTrack() const
{
Q_D(const QMediaPlayer);
- if (d->control)
- return d->control->activeTrack(QPlatformMediaPlayer::AudioStream);
- return 0;
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::AudioStream) : 0;
}
/*!
- Returns the currently active video track.
+ \since 6.2
+ \qmlproperty int QtMultimedia::MediaPlayer::activeVideoTrack
+
+ This property holds the track number of the currently active video audio track.
+ Set to \c{-1} to disable video track.
+
+ The default property value is \c{0}: the first video track.
+*/
+
+/*!
+ \property QMediaPlayer::activeVideoTrack
+ \brief Returns the currently active video track.
+
+ By default, the first available audio track will be chosen.
+
+ Set \a index to \c -1 to disable all video tracks.
*/
int QMediaPlayer::activeVideoTrack() const
{
Q_D(const QMediaPlayer);
- if (d->control)
- return d->control->activeTrack(QPlatformMediaPlayer::VideoStream);
- return -1;
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::VideoStream) : -1;
}
/*!
- Returns the currently active subtitle track.
+ \since 6.2
+ \qmlproperty int QtMultimedia::MediaPlayer::activeSubtitleTrack
+
+ This property holds the track number of the currently active subtitle track.
+ Set to \c{-1} to disable subtitle track.
+
+ The default property value is \c{-1}: no subtitles active.
*/
-int QMediaPlayer::activeSubtitleTrack() const
-{
- Q_D(const QMediaPlayer);
- if (d->control)
- return d->control->activeTrack(QPlatformMediaPlayer::SubtitleStream);
- return -1;
-}
/*!
- Sets the currently active audio track to one at the given \a index.
+ \property QMediaPlayer::activeSubtitleTrack
+ \brief Returns the currently active subtitle track.
- By default, the first available audio track will be chosen.
+ Set \a index to \c -1 to disable subtitles.
- Set \a index to \c -1 to disable all audio tracks.
+ Subtitles are disabled by default.
*/
+int QMediaPlayer::activeSubtitleTrack() const
+{
+ Q_D(const QMediaPlayer);
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::SubtitleStream) : -1;
+}
+
void QMediaPlayer::setActiveAudioTrack(int index)
{
Q_D(QMediaPlayer);
@@ -619,11 +849,6 @@ void QMediaPlayer::setActiveAudioTrack(int index)
d->control->setActiveTrack(QPlatformMediaPlayer::AudioStream, index);
}
-/*!
- Sets the currently active video track to one at the given \a index.
-
- By default, the first available video track will be chosen.
-*/
void QMediaPlayer::setActiveVideoTrack(int index)
{
Q_D(QMediaPlayer);
@@ -635,13 +860,6 @@ void QMediaPlayer::setActiveVideoTrack(int index)
d->control->setActiveTrack(QPlatformMediaPlayer::VideoStream, index);
}
-/*!
- Sets the currently active subtitle track to one at the given \a index.
-
- Set \a index to \c -1 to disable subtitles.
-
- Subtitles are disabled by default.
-*/
void QMediaPlayer::setActiveSubtitleTrack(int index)
{
Q_D(QMediaPlayer);
@@ -653,46 +871,60 @@ void QMediaPlayer::setActiveSubtitleTrack(int index)
d->control->setActiveTrack(QPlatformMediaPlayer::SubtitleStream, index);
}
+/*!
+ \qmlproperty VideoOutput QtMultimedia::MediaPlayer::videoOutput
+
+ This property holds the target video output.
+ Accepts one VideoOutput elements.
+
+ \sa QMediaPlayer::setVideoOutput()
+*/
+
+/*!
+ \property QMediaPlayer::videoOutput
+ \brief The video output to be used by the media player.
+
+ A media player can only have one video output attached, so
+ setting this property will replace the previously connected
+ video output.
+
+ Setting this property to \c nullptr will disable video output.
+*/
QObject *QMediaPlayer::videoOutput() const
{
Q_D(const QMediaPlayer);
return d->videoOutput;
}
-/*!
- Attach a video \a output to the media player.
-
- If the media player has already video output attached,
- it will be replaced with a new one.
-*/
void QMediaPlayer::setVideoOutput(QObject *output)
{
Q_D(QMediaPlayer);
- if (!d->control)
- return;
if (d->videoOutput == output)
return;
- QVideoSink *sink = qobject_cast<QVideoSink *>(output);
+ auto *sink = qobject_cast<QVideoSink *>(output);
if (!sink && output) {
auto *mo = output->metaObject();
- if (output)
- mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
+ mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
}
d->videoOutput = output;
d->setVideoSink(sink);
}
+/*!
+ Sets \a sink to be the QVideoSink instance to
+ retrieve video data.
+*/
void QMediaPlayer::setVideoSink(QVideoSink *sink)
{
Q_D(QMediaPlayer);
- if (!d->control)
- return;
-
d->videoOutput = nullptr;
d->setVideoSink(sink);
}
+/*!
+ Returns the QVideoSink instance.
+*/
QVideoSink *QMediaPlayer::videoSink() const
{
Q_D(const QMediaPlayer);
@@ -723,17 +955,26 @@ void QMediaPlayer::setVideoOutput(const QList<QVideoSink *> &sinks)
bool QMediaPlayer::isAvailable() const
{
Q_D(const QMediaPlayer);
+ return bool(d->control);
+}
- if (!d->control)
- return false;
+/*!
+ \qmlproperty mediaMetaData QtMultimedia::MediaPlayer::metaData
- return true;
-}
+ Returns meta data for the current media used by the media player.
+
+ Meta data can contain information such as the title of the video or its creation date.
+
+ \note The Windows implementation provides metadata only for media located on the local file
+ system.
+*/
/*!
+ \property QMediaPlayer::metaData
+
Returns meta data for the current media used by the media player.
- Meta data can contain information such as the title of the video or it's creation date.
+ Meta data can contain information such as the title of the video or its creation date.
\note The Windows implementation provides metadata only for media located on the local file
system.
@@ -741,7 +982,7 @@ bool QMediaPlayer::isAvailable() const
QMediaMetaData QMediaPlayer::metaData() const
{
Q_D(const QMediaPlayer);
- return d->control->metaData();
+ return d->control ? d->control->metaData() : QMediaMetaData{};
}
// Enums
@@ -752,12 +993,41 @@ QMediaMetaData QMediaPlayer::metaData() const
\value StoppedState The media player is not playing content, playback will begin from the start
of the current track.
- \value PlayingState The media player is currently playing content.
+ \value PlayingState The media player is currently playing content. This indicates the same as the \l playing property.
\value PausedState The media player has paused playback, playback of the current track will
resume from the position the player was paused at.
*/
/*!
+ \qmlproperty enumeration QtMultimedia::MediaPlayer::playbackState
+
+ This property holds the state of media playback. It can be one of the following:
+
+ \table
+ \header \li Property value
+ \li Description
+ \row \li PlayingState
+ \li The media is currently playing. This indicates the same as the \l playing property.
+ \row \li PausedState
+ \li Playback of the media has been suspended.
+ \row \li StoppedState
+ \li Playback of the media is yet to begin.
+ \endtable
+*/
+
+/*!
+ \qmlsignal QtMultimedia::MediaPlayer::playbackStateChanged()
+
+ This signal is emitted when the \l playbackState property is altered.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::MediaPlayer::playingChanged()
+
+ This signal is emitted when the \l playing property changes.
+*/
+
+/*!
\enum QMediaPlayer::MediaStatus
Defines the status of a media player's current media.
@@ -777,6 +1047,54 @@ QMediaMetaData QMediaPlayer::metaData() const
*/
/*!
+ \qmlproperty enumeration QtMultimedia::MediaPlayer::mediaStatus
+
+ This property holds the status of media loading. It can be one of the following:
+
+ \table
+ \header
+ \li Property value
+ \li Description
+ \row \li NoMedia
+ \li No media has been set.
+ \row \li LoadingMedia
+ \li The media is currently being loaded.
+ \row \li LoadedMedia
+ \li The media has been loaded.
+ \row \li BufferingMedia
+ \li The media is buffering data.
+ \row \li StalledMedia
+ \li Playback has been interrupted while the media is buffering data.
+ \row \li BufferedMedia
+ \li The media has buffered data.
+ \row \li EndOfMedia
+ \li The media has played to the end.
+ \row \li InvalidMedia
+ \li The media cannot be played.
+ \endtable
+*/
+
+/*!
+ \qmlproperty enumeration QtMultimedia::MediaPlayer::error
+
+ This property holds the error state of the audio. It can be one of the following.
+
+ \table
+ \header \li Value \li Description
+ \row \li NoError
+ \li There is no current error.
+ \row \li ResourceError
+ \li The audio cannot be played due to a problem allocating resources.
+ \row \li FormatError
+ \li The audio format is not supported.
+ \row \li NetworkError
+ \li The audio cannot be played due to network issues.
+ \row \li AccessDeniedError
+ \li The audio cannot be played due to insufficient permissions.
+ \endtable
+*/
+
+/*!
\enum QMediaPlayer::Error
Defines a media player error condition.
@@ -789,7 +1107,15 @@ QMediaMetaData QMediaPlayer::metaData() const
\value AccessDeniedError There are not the appropriate permissions to play a media resource.
*/
-// Signals
+/*!
+ \qmlsignal QtMultimedia::MediaPlayer::errorOccurred(error, errorString)
+
+ This signal is emitted when an \a error has occurred. The \a errorString
+ parameter may contain more detailed information about the error.
+
+ \sa QMediaPlayer::Error
+*/
+
/*!
\fn QMediaPlayer::errorOccurred(QMediaPlayer::Error error, const QString &errorString)
@@ -861,6 +1187,15 @@ QMediaMetaData QMediaPlayer::metaData() const
*/
/*!
+ \qmlproperty int QtMultimedia::MediaPlayer::duration
+
+ This property holds the duration of the media in milliseconds.
+
+ If the media doesn't have a fixed duration (a live stream for example) this
+ will be set to \c{0}.
+*/
+
+/*!
\property QMediaPlayer::duration
\brief the duration of the current media.
@@ -871,18 +1206,47 @@ QMediaMetaData QMediaPlayer::metaData() const
*/
/*!
+ \qmlproperty int QtMultimedia::MediaPlayer::position
+
+ The value is the current playback position, expressed in milliseconds since
+ the beginning of the media. Periodically changes in the position will be
+ indicated with the positionChanged() signal.
+
+ If the \l seekable property is true, this property can be set to milliseconds.
+*/
+
+/*!
\property QMediaPlayer::position
\brief the playback position of the current media.
The value is the current playback position, expressed in milliseconds since
the beginning of the media. Periodically changes in the position will be
- indicated with the signal positionChanged().
+ indicated with the positionChanged() signal.
+
+ If the \l seekable property is true, this property can be set to milliseconds.
*/
/*!
+ \qmlproperty real QtMultimedia::MediaPlayer::bufferProgress
+
+ This property holds how much of the data buffer is currently filled,
+ from \c 0.0 (empty) to \c 1.0 (full).
+
+ Playback can start or resume only when the buffer is entirely filled.
+ When the buffer is filled, \c MediaPlayer.Buffered is true.
+ When buffer progress is between \c 0.0 and \c 1.0, \c MediaPlayer.Buffering
+ is set to \c{true}.
+
+ A value lower than \c 1.0 implies that the property \c MediaPlayer.StalledMedia
+ is \c{true}.
+
+ \sa mediaStatus
+ */
+
+/*!
\property QMediaPlayer::bufferProgress
\brief the percentage of the temporary buffer filled before playback begins or resumes, from
- \c 0 (empty) to \c 100 (full).
+ \c 0. (empty) to \c 1. (full).
When the player object is buffering; this property holds the percentage of
the temporary buffer that is filled. The buffer will need to reach 100%
@@ -894,43 +1258,57 @@ QMediaMetaData QMediaPlayer::metaData() const
*/
/*!
- \property QMediaPlayer::hasAudio
- \brief the audio availabilty status for the current media.
+ \qmlproperty bool QtMultimedia::MediaPlayer::seekable
- \note As the life time of QMediaPlayer can be longer than the playback of
- one QUrl, this property may change over time.
+ This property holds whether the \l position of the media can be changed.
*/
/*!
- \property QMediaPlayer::hasVideo
- \brief the video availability status for the current media.
+ \property QMediaPlayer::seekable
+ \brief the seek-able status of the current media
- If available, the QVideoWidget class can be used to view the video.
+ If seeking is supported this property will be true; false otherwise. The
+ status of this property may change across the life time of the QMediaPlayer
+ object, use the seekableChanged signal to monitor changes.
+*/
- \note As the life time of QMediaPlayer can be longer than the playback of
- one QUrl, this property may change over time.
+/*!
+ \qmlproperty bool QtMultimedia::MediaPlayer::playing
+ \since 6.5
- \sa QVideoWidget, QUrl
+ Indicates whether the media is currently playing.
+
+ \sa playbackState
*/
/*!
- \property QMediaPlayer::seekable
- \brief the seek-able status of the current media
+ \property QMediaPlayer::playing
+ \brief Whether the media is playing.
+ \since 6.5
- If seeking is supported this property will be true; false otherwise. The
- status of this property may change across the life time of the QMediaPlayer
- object, use the seekableChanged signal to monitor changes.
+ \sa playbackState, PlayingState
+*/
+
+/*!
+ \qmlproperty real QtMultimedia::MediaPlayer::playbackRate
+
+ This property holds the rate at which media is played at as a multiple of
+ the normal rate.
+
+ For more information, see \l{QMediaPlayer::playbackRate}.
+
+ Defaults to \c{1.0}.
*/
/*!
\property QMediaPlayer::playbackRate
\brief the playback rate of the current media.
- This value is a multiplier applied to the media's standard play rate. By
- default this value is 1.0, indicating that the media is playing at the
- standard pace. Values higher than 1.0 will increase the rate of play.
- Values less than zero can be set and indicate the media should rewind at the
- multiplier of the standard pace.
+ This value is a multiplier applied to the media's standard playback
+ rate. By default this value is 1.0, indicating that the media is
+ playing at the standard speed. Values higher than 1.0 will increase
+ the playback speed, while values between 0.0 and 1.0 results in
+ slower playback. Negative playback rates are not supported.
Not all playback services support change of the playback rate. It is
framework defined as to the status and quality of audio and video
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index 5796c89e6..015a30f05 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEDIAPLAYER_H
#define QMEDIAPLAYER_H
@@ -44,7 +8,7 @@
#include <QtCore/qurl.h>
#include <QtMultimedia/qtmultimediaglobal.h>
#include <QtMultimedia/qmediaenumdebug.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
QT_BEGIN_NAMESPACE
@@ -65,7 +29,9 @@ class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QObject
Q_PROPERTY(bool hasAudio READ hasAudio NOTIFY hasAudioChanged)
Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged)
Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged)
+ Q_PROPERTY(bool playing READ isPlaying NOTIFY playingChanged)
Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged)
+ Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged)
Q_PROPERTY(PlaybackState playbackState READ playbackState NOTIFY playbackStateChanged)
Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged)
Q_PROPERTY(QMediaMetaData metaData READ metaData NOTIFY metaDataChanged)
@@ -118,6 +84,13 @@ public:
};
Q_ENUM(Error)
+ enum Loops
+ {
+ Infinite = -1,
+ Once = 1
+ };
+ Q_ENUM(Loops)
+
explicit QMediaPlayer(QObject *parent = nullptr);
~QMediaPlayer();
@@ -138,9 +111,6 @@ public:
void setVideoOutput(QObject *);
QObject *videoOutput() const;
-#if 0
- void setVideoOutput(const QList<QVideoSink *> &sinks);
-#endif
void setVideoSink(QVideoSink *sink);
QVideoSink *videoSink() const;
@@ -163,6 +133,11 @@ public:
bool isSeekable() const;
qreal playbackRate() const;
+ bool isPlaying() const;
+
+ int loops() const;
+ void setLoops(int loops);
+
Error error() const;
QString errorString() const;
@@ -195,7 +170,9 @@ Q_SIGNALS:
void bufferProgressChanged(float progress);
void seekableChanged(bool seekable);
+ void playingChanged(bool playing);
void playbackRateChanged(qreal rate);
+ void loopsChanged();
void metaDataChanged();
void videoOutputChanged();
diff --git a/src/multimedia/playback/qmediaplayer_p.h b/src/multimedia/playback/qmediaplayer_p.h
index 5da23fa00..ece086d06 100644
--- a/src/multimedia/playback/qmediaplayer_p.h
+++ b/src/multimedia/playback/qmediaplayer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEDIAPLAYER_P_H
#define QMEDIAPLAYER_P_H
@@ -56,14 +20,17 @@
#include "qvideosink.h"
#include "qaudiooutput.h"
#include <private/qplatformmediaplayer_p.h>
+#include <private/qerrorinfo_p.h>
#include "private/qobject_p.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
-#include <QtCore/qscopedpointer.h>
#include <QtCore/qurl.h>
#include <QtCore/qfile.h>
#include <QtCore/qtimer.h>
+
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QPlatformMediaPlayer;
@@ -74,19 +41,18 @@ class QMediaPlayerPrivate : public QObjectPrivate
public:
QMediaPlayerPrivate() = default;
- QPlatformMediaPlayer* control = nullptr;
- QString errorString;
+ QPlatformMediaPlayer *control = nullptr;
- QAudioOutput *audioOutput = nullptr;
- QVideoSink *videoSink = nullptr;
+ QPointer<QAudioOutput> audioOutput;
+ QPointer<QVideoSink> videoSink;
QPointer<QObject> videoOutput;
QUrl qrcMedia;
- QScopedPointer<QFile> qrcFile;
+ std::unique_ptr<QFile> qrcFile;
QUrl source;
QIODevice *stream = nullptr;
QMediaPlayer::PlaybackState state = QMediaPlayer::StoppedState;
- QMediaPlayer::Error error = QMediaPlayer::NoError;
+ QErrorInfo<QMediaPlayer::Error> error;
void setMedia(const QUrl &media, QIODevice *stream = nullptr);
@@ -94,7 +60,7 @@ public:
void setState(QMediaPlayer::PlaybackState state);
void setStatus(QMediaPlayer::MediaStatus status);
- void setError(int error, const QString &errorString);
+ void setError(QMediaPlayer::Error error, const QString &errorString);
void setVideoSink(QVideoSink *sink)
{
@@ -106,7 +72,8 @@ public:
videoSink = sink;
if (sink)
sink->setSource(q);
- control->setVideoSink(sink);
+ if (control)
+ control->setVideoSink(sink);
emit q->videoOutputChanged();
}
};
diff --git a/src/multimedia/pulseaudio/pulseaudio.json b/src/multimedia/pulseaudio/pulseaudio.json
new file mode 100644
index 000000000..5e0336ee8
--- /dev/null
+++ b/src/multimedia/pulseaudio/pulseaudio.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "pulseaudio" ]
+}
diff --git a/src/multimedia/pulseaudio/qaudioengine_pulse.cpp b/src/multimedia/pulseaudio/qaudioengine_pulse.cpp
new file mode 100644
index 000000000..e54356404
--- /dev/null
+++ b/src/multimedia/pulseaudio/qaudioengine_pulse.cpp
@@ -0,0 +1,508 @@
+// 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/qdebug.h>
+
+#include <qaudiodevice.h>
+#include <QGuiApplication>
+#include <QIcon>
+#include <QTimer>
+#include "qaudioengine_pulse_p.h"
+#include "qpulseaudiodevice_p.h"
+#include "qpulsehelpers_p.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <mutex> // for lock_guard
+
+QT_BEGIN_NAMESPACE
+
+template<typename Info>
+static bool updateDevicesMap(QReadWriteLock &lock, QByteArray defaultDeviceId,
+ QMap<int, QAudioDevice> &devices, QAudioDevice::Mode mode,
+ const Info &info)
+{
+ QWriteLocker locker(&lock);
+
+ bool isDefault = defaultDeviceId == info.name;
+ auto newDeviceInfo = std::make_unique<QPulseAudioDeviceInfo>(info.name, info.description, isDefault, mode);
+ newDeviceInfo->channelConfiguration = QPulseAudioInternal::channelConfigFromMap(info.channel_map);
+ newDeviceInfo->preferredFormat = QPulseAudioInternal::sampleSpecToAudioFormat(info.sample_spec);
+ newDeviceInfo->preferredFormat.setChannelConfig(newDeviceInfo->channelConfiguration);
+
+ auto &device = devices[info.index];
+ if (device.handle() && *newDeviceInfo == *device.handle())
+ return false;
+
+ device = newDeviceInfo.release()->create();
+ return true;
+}
+
+static bool updateDevicesMap(QReadWriteLock &lock, QByteArray defaultDeviceId,
+ QMap<int, QAudioDevice> &devices)
+{
+ QWriteLocker locker(&lock);
+
+ bool result = false;
+
+ for (QAudioDevice &device : devices) {
+ auto deviceInfo = device.handle();
+ const auto isDefault = deviceInfo->id == defaultDeviceId;
+ if (deviceInfo->isDefault != isDefault) {
+ Q_ASSERT(dynamic_cast<const QPulseAudioDeviceInfo *>(deviceInfo));
+ auto newDeviceInfo = std::make_unique<QPulseAudioDeviceInfo>(
+ *static_cast<const QPulseAudioDeviceInfo *>(deviceInfo));
+ newDeviceInfo->isDefault = isDefault;
+ device = newDeviceInfo.release()->create();
+ result = true;
+ }
+ }
+
+ return result;
+};
+
+static void serverInfoCallback(pa_context *context, const pa_server_info *info, void *userdata)
+{
+ using namespace Qt::Literals;
+ using namespace QPulseAudioInternal;
+
+ if (!info) {
+ qWarning() << "Failed to get server information:" << currentError(context);
+ return;
+ }
+
+ if (Q_UNLIKELY(qLcPulseAudioEngine().isEnabled(QtDebugMsg))) {
+ char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+
+ pa_sample_spec_snprint(ss, sizeof(ss), &info->sample_spec);
+ pa_channel_map_snprint(cm, sizeof(cm), &info->channel_map);
+
+ qCDebug(qLcPulseAudioEngine)
+ << QStringLiteral("User name: %1\n"
+ "Host Name: %2\n"
+ "Server Name: %3\n"
+ "Server Version: %4\n"
+ "Default Sample Specification: %5\n"
+ "Default Channel Map: %6\n"
+ "Default Sink: %7\n"
+ "Default Source: %8\n")
+ .arg(QString::fromUtf8(info->user_name),
+ QString::fromUtf8(info->host_name),
+ QString::fromUtf8(info->server_name),
+ QLatin1StringView(info->server_version), QLatin1StringView(ss),
+ QLatin1StringView(cm), QString::fromUtf8(info->default_sink_name),
+ QString::fromUtf8(info->default_source_name));
+ }
+
+ QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
+
+ bool defaultSinkChanged = false;
+ bool defaultSourceChanged = false;
+
+ {
+ QWriteLocker locker(&pulseEngine->m_serverLock);
+
+ if (pulseEngine->m_defaultSink != info->default_sink_name) {
+ pulseEngine->m_defaultSink = info->default_sink_name;
+ defaultSinkChanged = true;
+ }
+
+ if (pulseEngine->m_defaultSource != info->default_source_name) {
+ pulseEngine->m_defaultSource = info->default_source_name;
+ defaultSourceChanged = true;
+ }
+ }
+
+ if (defaultSinkChanged
+ && updateDevicesMap(pulseEngine->m_sinkLock, pulseEngine->m_defaultSink,
+ pulseEngine->m_sinks))
+ emit pulseEngine->audioOutputsChanged();
+
+ if (defaultSourceChanged
+ && updateDevicesMap(pulseEngine->m_sourceLock, pulseEngine->m_defaultSource,
+ pulseEngine->m_sources))
+ emit pulseEngine->audioInputsChanged();
+
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+}
+
+static void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int isLast, void *userdata)
+{
+ using namespace Qt::Literals;
+ using namespace QPulseAudioInternal;
+
+ QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine *>(userdata);
+
+ if (isLast < 0) {
+ qWarning() << "Failed to get sink information:" << currentError(context);
+ return;
+ }
+
+ if (isLast) {
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+ return;
+ }
+
+ Q_ASSERT(info);
+
+ if (Q_UNLIKELY(qLcPulseAudioEngine().isEnabled(QtDebugMsg))) {
+ static const QMap<pa_sink_state, QString> stateMap{
+ { PA_SINK_INVALID_STATE, u"n/a"_s }, { PA_SINK_RUNNING, u"RUNNING"_s },
+ { PA_SINK_IDLE, u"IDLE"_s }, { PA_SINK_SUSPENDED, u"SUSPENDED"_s },
+ { PA_SINK_UNLINKED, u"UNLINKED"_s },
+ };
+
+ qCDebug(qLcPulseAudioEngine)
+ << QStringLiteral("Sink #%1\n"
+ "\tState: %2\n"
+ "\tName: %3\n"
+ "\tDescription: %4\n")
+ .arg(QString::number(info->index), stateMap.value(info->state),
+ QString::fromUtf8(info->name),
+ QString::fromUtf8(info->description));
+ }
+
+ if (updateDevicesMap(pulseEngine->m_sinkLock, pulseEngine->m_defaultSink, pulseEngine->m_sinks,
+ QAudioDevice::Output, *info))
+ emit pulseEngine->audioOutputsChanged();
+}
+
+static void sourceInfoCallback(pa_context *context, const pa_source_info *info, int isLast, void *userdata)
+{
+ using namespace Qt::Literals;
+
+ Q_UNUSED(context);
+ QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
+
+ if (isLast) {
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+ return;
+ }
+
+ Q_ASSERT(info);
+
+ if (Q_UNLIKELY(qLcPulseAudioEngine().isEnabled(QtDebugMsg))) {
+ static const QMap<pa_source_state, QString> stateMap{
+ { PA_SOURCE_INVALID_STATE, u"n/a"_s }, { PA_SOURCE_RUNNING, u"RUNNING"_s },
+ { PA_SOURCE_IDLE, u"IDLE"_s }, { PA_SOURCE_SUSPENDED, u"SUSPENDED"_s },
+ { PA_SOURCE_UNLINKED, u"UNLINKED"_s },
+ };
+
+ qCDebug(qLcPulseAudioEngine)
+ << QStringLiteral("Source #%1\n"
+ "\tState: %2\n"
+ "\tName: %3\n"
+ "\tDescription: %4\n")
+ .arg(QString::number(info->index), stateMap.value(info->state),
+ QString::fromUtf8(info->name),
+ QString::fromUtf8(info->description));
+ }
+
+ // skip monitor channels
+ if (info->monitor_of_sink != PA_INVALID_INDEX)
+ return;
+
+ if (updateDevicesMap(pulseEngine->m_sourceLock, pulseEngine->m_defaultSource,
+ pulseEngine->m_sources, QAudioDevice::Input, *info))
+ emit pulseEngine->audioInputsChanged();
+}
+
+static void event_cb(pa_context* context, pa_subscription_event_type_t t, uint32_t index, void* userdata)
+{
+ QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
+
+ int type = t & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
+ int facility = t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
+
+ switch (type) {
+ case PA_SUBSCRIPTION_EVENT_NEW:
+ case PA_SUBSCRIPTION_EVENT_CHANGE:
+ switch (facility) {
+ case PA_SUBSCRIPTION_EVENT_SERVER: {
+ PAOperationUPtr op(pa_context_get_server_info(context, serverInfoCallback, userdata));
+ if (!op)
+ qWarning() << "PulseAudioService: failed to get server info";
+ break;
+ }
+ case PA_SUBSCRIPTION_EVENT_SINK: {
+ PAOperationUPtr op(
+ pa_context_get_sink_info_by_index(context, index, sinkInfoCallback, userdata));
+ if (!op)
+ qWarning() << "PulseAudioService: failed to get sink info";
+ break;
+ }
+ case PA_SUBSCRIPTION_EVENT_SOURCE: {
+ PAOperationUPtr op(pa_context_get_source_info_by_index(context, index,
+ sourceInfoCallback, userdata));
+ if (!op)
+ qWarning() << "PulseAudioService: failed to get source info";
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ case PA_SUBSCRIPTION_EVENT_REMOVE:
+ switch (facility) {
+ case PA_SUBSCRIPTION_EVENT_SINK: {
+ QWriteLocker locker(&pulseEngine->m_sinkLock);
+ pulseEngine->m_sinks.remove(index);
+ break;
+ }
+ case PA_SUBSCRIPTION_EVENT_SOURCE: {
+ QWriteLocker locker(&pulseEngine->m_sourceLock);
+ pulseEngine->m_sources.remove(index);
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void contextStateCallbackInit(pa_context *context, void *userdata)
+{
+ Q_UNUSED(context);
+
+ if (Q_UNLIKELY(qLcPulseAudioEngine().isEnabled(QtDebugMsg)))
+ qCDebug(qLcPulseAudioEngine) << pa_context_get_state(context);
+
+ QPulseAudioEngine *pulseEngine = reinterpret_cast<QPulseAudioEngine*>(userdata);
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+}
+
+static void contextStateCallback(pa_context *c, void *userdata)
+{
+ QPulseAudioEngine *self = reinterpret_cast<QPulseAudioEngine*>(userdata);
+ pa_context_state_t state = pa_context_get_state(c);
+
+ if (Q_UNLIKELY(qLcPulseAudioEngine().isEnabled(QtDebugMsg)))
+ qCDebug(qLcPulseAudioEngine) << state;
+
+ if (state == PA_CONTEXT_FAILED)
+ QMetaObject::invokeMethod(self, "onContextFailed", Qt::QueuedConnection);
+}
+
+Q_GLOBAL_STATIC(QPulseAudioEngine, pulseEngine);
+
+QPulseAudioEngine::QPulseAudioEngine(QObject *parent)
+ : QObject(parent)
+ , m_mainLoopApi(nullptr)
+ , m_context(nullptr)
+ , m_prepared(false)
+{
+ prepare();
+}
+
+QPulseAudioEngine::~QPulseAudioEngine()
+{
+ if (m_prepared)
+ release();
+}
+
+void QPulseAudioEngine::prepare()
+{
+ using namespace QPulseAudioInternal;
+ bool keepGoing = true;
+ bool ok = true;
+
+ m_mainLoop = pa_threaded_mainloop_new();
+ if (m_mainLoop == nullptr) {
+ qWarning() << "PulseAudioService: unable to create pulseaudio mainloop";
+ return;
+ }
+
+ if (pa_threaded_mainloop_start(m_mainLoop) != 0) {
+ qWarning() << "PulseAudioService: unable to start pulseaudio mainloop";
+ pa_threaded_mainloop_free(m_mainLoop);
+ m_mainLoop = nullptr;
+ return;
+ }
+
+ m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop);
+
+ lock();
+
+ pa_proplist *proplist = pa_proplist_new();
+ if (!QGuiApplication::applicationDisplayName().isEmpty())
+ pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, qUtf8Printable(QGuiApplication::applicationDisplayName()));
+ if (!QGuiApplication::desktopFileName().isEmpty())
+ pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, qUtf8Printable(QGuiApplication::desktopFileName()));
+ if (const QString windowIconName = QGuiApplication::windowIcon().name(); !windowIconName.isEmpty())
+ pa_proplist_sets(proplist, PA_PROP_WINDOW_ICON_NAME, qUtf8Printable(windowIconName));
+
+ m_context = pa_context_new_with_proplist(m_mainLoopApi, nullptr, proplist);
+ pa_proplist_free(proplist);
+
+ if (m_context == nullptr) {
+ qWarning() << "PulseAudioService: Unable to create new pulseaudio context";
+ pa_threaded_mainloop_unlock(m_mainLoop);
+ pa_threaded_mainloop_free(m_mainLoop);
+ m_mainLoop = nullptr;
+ onContextFailed();
+ return;
+ }
+
+ pa_context_set_state_callback(m_context, contextStateCallbackInit, this);
+
+ if (pa_context_connect(m_context, nullptr, static_cast<pa_context_flags_t>(0), nullptr) < 0) {
+ qWarning() << "PulseAudioService: pa_context_connect() failed";
+ pa_context_unref(m_context);
+ pa_threaded_mainloop_unlock(m_mainLoop);
+ pa_threaded_mainloop_free(m_mainLoop);
+ m_mainLoop = nullptr;
+ m_context = nullptr;
+ return;
+ }
+
+ pa_threaded_mainloop_wait(m_mainLoop);
+
+ while (keepGoing) {
+ switch (pa_context_get_state(m_context)) {
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+
+ case PA_CONTEXT_READY:
+ qCDebug(qLcPulseAudioEngine) << "Connection established.";
+ keepGoing = false;
+ break;
+
+ case PA_CONTEXT_TERMINATED:
+ qCritical("PulseAudioService: Context terminated.");
+ keepGoing = false;
+ ok = false;
+ break;
+
+ case PA_CONTEXT_FAILED:
+ default:
+ qCritical() << "PulseAudioService: Connection failure:"
+ << currentError(m_context);
+ keepGoing = false;
+ ok = false;
+ }
+
+ if (keepGoing)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ }
+
+ if (ok) {
+ pa_context_set_state_callback(m_context, contextStateCallback, this);
+
+ pa_context_set_subscribe_callback(m_context, event_cb, this);
+ PAOperationUPtr op(pa_context_subscribe(
+ m_context,
+ pa_subscription_mask_t(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE
+ | PA_SUBSCRIPTION_MASK_SERVER),
+ nullptr, nullptr));
+ if (!op)
+ qWarning() << "PulseAudioService: failed to subscribe to context notifications";
+ } else {
+ pa_context_unref(m_context);
+ m_context = nullptr;
+ }
+
+ unlock();
+
+ if (ok) {
+ updateDevices();
+ m_prepared = true;
+ } else {
+ pa_threaded_mainloop_free(m_mainLoop);
+ m_mainLoop = nullptr;
+ onContextFailed();
+ }
+}
+
+void QPulseAudioEngine::release()
+{
+ if (!m_prepared)
+ return;
+
+ if (m_context) {
+ pa_context_disconnect(m_context);
+ pa_context_unref(m_context);
+ m_context = nullptr;
+ }
+
+ if (m_mainLoop) {
+ pa_threaded_mainloop_stop(m_mainLoop);
+ pa_threaded_mainloop_free(m_mainLoop);
+ m_mainLoop = nullptr;
+ }
+
+ m_prepared = false;
+}
+
+void QPulseAudioEngine::updateDevices()
+{
+ std::lock_guard lock(*this);
+
+ // Get default input and output devices
+ PAOperationUPtr operation(pa_context_get_server_info(m_context, serverInfoCallback, this));
+ if (operation) {
+ while (pa_operation_get_state(operation.get()) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ } else {
+ qWarning() << "PulseAudioService: failed to get server info";
+ }
+
+ // Get output devices
+ operation.reset(pa_context_get_sink_info_list(m_context, sinkInfoCallback, this));
+ if (operation) {
+ while (pa_operation_get_state(operation.get()) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ } else {
+ qWarning() << "PulseAudioService: failed to get sink info";
+ }
+
+ // Get input devices
+ operation.reset(pa_context_get_source_info_list(m_context, sourceInfoCallback, this));
+ if (operation) {
+ while (pa_operation_get_state(operation.get()) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ } else {
+ qWarning() << "PulseAudioService: failed to get source info";
+ }
+}
+
+void QPulseAudioEngine::onContextFailed()
+{
+ // Give a chance to the connected slots to still use the Pulse main loop before releasing it.
+ emit contextFailed();
+
+ release();
+
+ // Try to reconnect later
+ QTimer::singleShot(3000, this, SLOT(prepare()));
+}
+
+QPulseAudioEngine *QPulseAudioEngine::instance()
+{
+ return pulseEngine();
+}
+
+QList<QAudioDevice> QPulseAudioEngine::availableDevices(QAudioDevice::Mode mode) const
+{
+ if (mode == QAudioDevice::Output) {
+ QReadLocker locker(&m_sinkLock);
+ return m_sinks.values();
+ }
+
+ if (mode == QAudioDevice::Input) {
+ QReadLocker locker(&m_sourceLock);
+ return m_sources.values();
+ }
+
+ return {};
+}
+
+QByteArray QPulseAudioEngine::defaultDevice(QAudioDevice::Mode mode) const
+{
+ return (mode == QAudioDevice::Output) ? m_defaultSink : m_defaultSource;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/platform/pulseaudio/qaudioengine_pulse_p.h b/src/multimedia/pulseaudio/qaudioengine_pulse_p.h
index c384d274b..2ed1fa0b1 100644
--- a/src/multimedia/platform/pulseaudio/qaudioengine_pulse_p.h
+++ b/src/multimedia/pulseaudio/qaudioengine_pulse_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QPULSEAUDIOENGINE_H
#define QPULSEAUDIOENGINE_H
@@ -95,6 +59,8 @@ public:
Q_SIGNALS:
void contextFailed();
+ void audioInputsChanged();
+ void audioOutputsChanged();
private Q_SLOTS:
void prepare();
diff --git a/src/multimedia/pulseaudio/qpulseaudiodevice.cpp b/src/multimedia/pulseaudio/qpulseaudiodevice.cpp
new file mode 100644
index 000000000..487b88f6d
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiodevice.cpp
@@ -0,0 +1,46 @@
+// 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 "qpulseaudiodevice_p.h"
+#include "qaudioengine_pulse_p.h"
+#include "qpulsehelpers_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPulseAudioDeviceInfo::QPulseAudioDeviceInfo(const char *device, const char *desc, bool isDef, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(device, mode)
+{
+ description = QString::fromUtf8(desc);
+ isDefault = isDef;
+
+ minimumChannelCount = 1;
+ maximumChannelCount = PA_CHANNELS_MAX;
+ minimumSampleRate = 1;
+ maximumSampleRate = PA_RATE_MAX;
+
+ constexpr bool isBigEndian = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+
+ const struct {
+ pa_sample_format pa_fmt;
+ QAudioFormat::SampleFormat qt_fmt;
+ } formatMap[] = {
+ { PA_SAMPLE_U8, QAudioFormat::UInt8 },
+ { isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE, QAudioFormat::Int16 },
+ { isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE, QAudioFormat::Int32 },
+ { isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE, QAudioFormat::Float },
+ };
+
+ for (const auto &f : formatMap) {
+ if (pa_sample_format_valid(f.pa_fmt) != 0)
+ supportedSampleFormats.append(f.qt_fmt);
+ }
+
+ preferredFormat.setChannelCount(2);
+ preferredFormat.setSampleRate(48000);
+ QAudioFormat::SampleFormat f = QAudioFormat::Int16;
+ if (!supportedSampleFormats.contains(f))
+ f = supportedSampleFormats.value(0, QAudioFormat::Unknown);
+ preferredFormat.setSampleFormat(f);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/pulseaudio/qpulseaudiodevice_p.h b/src/multimedia/pulseaudio/qpulseaudiodevice_p.h
new file mode 100644
index 000000000..b44c71e0d
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiodevice_p.h
@@ -0,0 +1,41 @@
+// 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 QAUDIODEVICEINFOPULSE_H
+#define QAUDIODEVICEINFOPULSE_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/qbytearray.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+
+#include "qaudio.h"
+#include "qaudiodevice.h"
+#include <private/qaudiosystem_p.h>
+#include <private/qaudiodevice_p.h>
+
+#include <pulse/pulseaudio.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPulseAudioDeviceInfo : public QAudioDevicePrivate
+{
+public:
+ QPulseAudioDeviceInfo(const char *device, const char *description, bool isDefault, QAudioDevice::Mode mode);
+ ~QPulseAudioDeviceInfo() {}
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/multimedia/pulseaudio/qpulseaudiomediadevices.cpp b/src/multimedia/pulseaudio/qpulseaudiomediadevices.cpp
new file mode 100644
index 000000000..4deee6033
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiomediadevices.cpp
@@ -0,0 +1,55 @@
+// 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 "qpulseaudiomediadevices_p.h"
+#include "qmediadevices.h"
+#include "private/qcameradevice_p.h"
+
+#include "qpulseaudiosource_p.h"
+#include "qpulseaudiosink_p.h"
+#include "qpulseaudiodevice_p.h"
+#include "qaudioengine_pulse_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPulseAudioMediaDevices::QPulseAudioMediaDevices()
+ : QPlatformMediaDevices()
+{
+ pulseEngine = new QPulseAudioEngine();
+
+ // TODO: it might make sense to connect device changing signals
+ // to each added QMediaDevices
+ QObject::connect(pulseEngine, &QPulseAudioEngine::audioInputsChanged,
+ this, &QPulseAudioMediaDevices::audioInputsChanged, Qt::DirectConnection);
+ QObject::connect(pulseEngine, &QPulseAudioEngine::audioOutputsChanged,
+ this, &QPulseAudioMediaDevices::audioOutputsChanged, Qt::DirectConnection);
+}
+
+QPulseAudioMediaDevices::~QPulseAudioMediaDevices()
+{
+ delete pulseEngine;
+}
+
+QList<QAudioDevice> QPulseAudioMediaDevices::audioInputs() const
+{
+ return pulseEngine->availableDevices(QAudioDevice::Input);
+}
+
+QList<QAudioDevice> QPulseAudioMediaDevices::audioOutputs() const
+{
+ return pulseEngine->availableDevices(QAudioDevice::Output);
+}
+
+QPlatformAudioSource *QPulseAudioMediaDevices::createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QPulseAudioSource(deviceInfo.id(), parent);
+}
+
+QPlatformAudioSink *QPulseAudioMediaDevices::createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QPulseAudioSink(deviceInfo.id(), parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/pulseaudio/qpulseaudiomediadevices_p.h b/src/multimedia/pulseaudio/qpulseaudiomediadevices_p.h
new file mode 100644
index 000000000..094dc3907
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiomediadevices_p.h
@@ -0,0 +1,45 @@
+// 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
+
+#ifndef QPULSEAUDIOMEDIADEVICES_H
+#define QPULSEAUDIOMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+#include <qset.h>
+#include <qaudio.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPulseAudioEngine;
+
+class QPulseAudioMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QPulseAudioMediaDevices();
+ ~QPulseAudioMediaDevices();
+
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+
+private:
+ QPulseAudioEngine *pulseEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/pulseaudio/qpulseaudiosink.cpp b/src/multimedia/pulseaudio/qpulseaudiosink.cpp
new file mode 100644
index 000000000..610677eeb
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiosink.cpp
@@ -0,0 +1,749 @@
+// 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 <private/qaudiohelpers_p.h>
+
+#include "qpulseaudiosink_p.h"
+#include "qaudioengine_pulse_p.h"
+#include "qpulsehelpers_p.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <mutex> // for std::lock_guard
+
+QT_BEGIN_NAMESPACE
+
+static constexpr uint SinkPeriodTimeMs = 20;
+static constexpr uint DefaultBufferLengthMs = 100;
+
+#define LOW_LATENCY_CATEGORY_NAME "game"
+
+static void outputStreamWriteCallback(pa_stream *stream, size_t length, void *userdata)
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(userdata);
+ qCDebug(qLcPulseAudioOut) << "Write callback:" << length;
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+}
+
+static void outputStreamStateCallback(pa_stream *stream, void *userdata)
+{
+ Q_UNUSED(userdata);
+ pa_stream_state_t state = pa_stream_get_state(stream);
+ qCDebug(qLcPulseAudioOut) << "Stream state callback:" << state;
+ switch (state) {
+ case PA_STREAM_CREATING:
+ case PA_STREAM_READY:
+ case PA_STREAM_TERMINATED:
+ break;
+
+ case PA_STREAM_FAILED:
+ default:
+ qWarning() << QStringLiteral("Stream error: %1")
+ .arg(QString::fromUtf8(pa_strerror(
+ pa_context_errno(pa_stream_get_context(stream)))));
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+ break;
+ }
+}
+
+static void outputStreamUnderflowCallback(pa_stream *stream, void *userdata)
+{
+ Q_UNUSED(stream);
+ qCDebug(qLcPulseAudioOut) << "Buffer underflow";
+ if (userdata)
+ static_cast<QPulseAudioSink *>(userdata)->streamUnderflowCallback();
+}
+
+static void outputStreamOverflowCallback(pa_stream *stream, void *userdata)
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(userdata);
+ qCDebug(qLcPulseAudioOut) << "Buffer overflow";
+}
+
+static void outputStreamLatencyCallback(pa_stream *stream, void *userdata)
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(userdata);
+
+ if (Q_UNLIKELY(qLcPulseAudioOut().isEnabled(QtDebugMsg))) {
+ const pa_timing_info *info = pa_stream_get_timing_info(stream);
+
+ qCDebug(qLcPulseAudioOut) << "Latency callback:";
+ qCDebug(qLcPulseAudioOut) << "\tWrite index corrupt: " << info->write_index_corrupt;
+ qCDebug(qLcPulseAudioOut) << "\tWrite index: " << info->write_index;
+ qCDebug(qLcPulseAudioOut) << "\tRead index corrupt: " << info->read_index_corrupt;
+ qCDebug(qLcPulseAudioOut) << "\tRead index: " << info->read_index;
+ qCDebug(qLcPulseAudioOut) << "\tSink usec: " << info->sink_usec;
+ qCDebug(qLcPulseAudioOut) << "\tConfigured sink usec: " << info->configured_sink_usec;
+ }
+}
+
+static void outputStreamSuccessCallback(pa_stream *stream, int success, void *userdata)
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(userdata);
+
+ qCDebug(qLcPulseAudioOut) << "Stream successful:" << success;
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+}
+
+static void outputStreamDrainComplete(pa_stream *stream, int success, void *userdata)
+{
+ Q_UNUSED(stream);
+
+ qCDebug(qLcPulseAudioOut) << "Stream drained:" << static_cast<bool>(success) << userdata;
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+
+ if (userdata && success)
+ static_cast<QPulseAudioSink *>(userdata)->streamDrainedCallback();
+}
+
+static void outputStreamFlushComplete(pa_stream *stream, int success, void *userdata)
+{
+ Q_UNUSED(stream);
+
+ qCDebug(qLcPulseAudioOut) << "Stream flushed:" << static_cast<bool>(success) << userdata;
+}
+
+static void streamAdjustPrebufferCallback(pa_stream *stream, int success, void *userdata)
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(success);
+ Q_UNUSED(userdata);
+
+ qCDebug(qLcPulseAudioOut) << "Prebuffer adjusted:" << static_cast<bool>(success);
+}
+
+QPulseAudioSink::QPulseAudioSink(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSink(parent), m_device(device), m_stateMachine(*this)
+{
+}
+
+QPulseAudioSink::~QPulseAudioSink()
+{
+ if (auto notifier = m_stateMachine.stop())
+ close();
+}
+
+QAudio::Error QPulseAudioSink::error() const
+{
+ return m_stateMachine.error();
+}
+
+QAudio::State QPulseAudioSink::state() const
+{
+ return m_stateMachine.state();
+}
+
+void QPulseAudioSink::streamUnderflowCallback()
+{
+ bool atEnd = m_audioSource && m_audioSource->atEnd();
+ if (atEnd && m_stateMachine.state() != QAudio::StoppedState) {
+ qCDebug(qLcPulseAudioOut) << "Draining stream at end of buffer";
+ exchangeDrainOperation(pa_stream_drain(m_stream, outputStreamDrainComplete, this));
+ }
+
+ m_stateMachine.updateActiveOrIdle(
+ false, (m_pullMode && atEnd) ? QAudio::NoError : QAudio::UnderrunError);
+}
+
+void QPulseAudioSink::streamDrainedCallback()
+{
+ if (!exchangeDrainOperation(nullptr))
+ return;
+}
+
+void QPulseAudioSink::start(QIODevice *device)
+{
+ reset();
+
+ m_pullMode = true;
+ m_audioSource = device;
+
+ if (!open()) {
+ m_audioSource = nullptr;
+ return;
+ }
+
+ // ensure we only process timing infos that are up to date
+ gettimeofday(&lastTimingInfo, nullptr);
+ lastProcessedUSecs = 0;
+
+ connect(m_audioSource, &QIODevice::readyRead, this, &QPulseAudioSink::startPulling);
+
+ m_stateMachine.start();
+}
+
+void QPulseAudioSink::startPulling()
+{
+ Q_ASSERT(m_pullMode);
+ if (m_tickTimer.isActive())
+ return;
+
+ m_tickTimer.start(m_pullingPeriodTime, this);
+}
+
+void QPulseAudioSink::stopTimer()
+{
+ if (m_tickTimer.isActive())
+ m_tickTimer.stop();
+}
+
+QIODevice *QPulseAudioSink::start()
+{
+ reset();
+
+ m_pullMode = false;
+
+ if (!open())
+ return nullptr;
+
+ m_audioSource = new PulseOutputPrivate(this);
+ m_audioSource->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
+
+ // ensure we only process timing infos that are up to date
+ gettimeofday(&lastTimingInfo, nullptr);
+ lastProcessedUSecs = 0;
+
+ m_stateMachine.start(false);
+
+ return m_audioSource;
+}
+
+bool QPulseAudioSink::open()
+{
+ if (m_opened)
+ return true;
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ if (!pulseEngine->context()
+ || pa_context_get_state(pulseEngine->context()) != PA_CONTEXT_READY) {
+ m_stateMachine.stopOrUpdateError(QAudio::FatalError);
+ return false;
+ }
+
+ pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format);
+ pa_channel_map channel_map = QPulseAudioInternal::channelMapForAudioFormat(m_format);
+ Q_ASSERT(spec.channels == channel_map.channels);
+
+ if (!pa_sample_spec_valid(&spec)) {
+ m_stateMachine.stopOrUpdateError(QAudio::OpenError);
+ return false;
+ }
+
+ m_spec = spec;
+ m_totalTimeValue = 0;
+
+ if (m_streamName.isNull())
+ m_streamName =
+ QStringLiteral("QtmPulseStream-%1-%2").arg(::getpid()).arg(quintptr(this)).toUtf8();
+
+ if (Q_UNLIKELY(qLcPulseAudioOut().isEnabled(QtDebugMsg))) {
+ qCDebug(qLcPulseAudioOut) << "Opening stream with.";
+ qCDebug(qLcPulseAudioOut) << "\tFormat: " << spec.format;
+ qCDebug(qLcPulseAudioOut) << "\tRate: " << spec.rate;
+ qCDebug(qLcPulseAudioOut) << "\tChannels: " << spec.channels;
+ qCDebug(qLcPulseAudioOut) << "\tFrame size: " << pa_frame_size(&spec);
+ }
+
+ pulseEngine->lock();
+
+ pa_proplist *propList = pa_proplist_new();
+#if 0
+ qint64 bytesPerSecond = m_format.sampleRate() * m_format.bytesPerFrame();
+ static const char *mediaRoleFromAudioRole[] = {
+ nullptr, // UnknownRole
+ "music", // MusicRole
+ "video", // VideoRole
+ "phone", // VoiceCommunicationRole
+ "event", // AlarmRole
+ "event", // NotificationRole
+ "phone", // RingtoneRole
+ "a11y", // AccessibilityRole
+ nullptr, // SonificationRole
+ "game" // GameRole
+ };
+
+ const char *r = mediaRoleFromAudioRole[m_role];
+ if (r)
+ pa_proplist_sets(propList, PA_PROP_MEDIA_ROLE, r);
+#endif
+
+ m_stream = pa_stream_new_with_proplist(pulseEngine->context(), m_streamName.constData(),
+ &m_spec, &channel_map, propList);
+ pa_proplist_free(propList);
+
+ if (!m_stream) {
+ qCWarning(qLcPulseAudioOut) << "QAudioSink: pa_stream_new_with_proplist() failed!";
+ pulseEngine->unlock();
+
+ m_stateMachine.stopOrUpdateError(QAudio::OpenError);
+ return false;
+ }
+
+ pa_stream_set_state_callback(m_stream, outputStreamStateCallback, this);
+ pa_stream_set_write_callback(m_stream, outputStreamWriteCallback, this);
+
+ pa_stream_set_underflow_callback(m_stream, outputStreamUnderflowCallback, this);
+ pa_stream_set_overflow_callback(m_stream, outputStreamOverflowCallback, this);
+ pa_stream_set_latency_update_callback(m_stream, outputStreamLatencyCallback, this);
+
+ pa_buffer_attr requestedBuffer;
+ // Request a target buffer size
+ auto targetBufferSize = m_userBufferSize ? *m_userBufferSize : defaultBufferSize();
+ requestedBuffer.tlength =
+ targetBufferSize ? static_cast<uint32_t>(targetBufferSize) : static_cast<uint32_t>(-1);
+ // Rest should be determined by PulseAudio
+ requestedBuffer.fragsize = static_cast<uint32_t>(-1);
+ requestedBuffer.maxlength = static_cast<uint32_t>(-1);
+ requestedBuffer.minreq = static_cast<uint32_t>(-1);
+ requestedBuffer.prebuf = static_cast<uint32_t>(-1);
+
+ pa_stream_flags flags =
+ pa_stream_flags(PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_ADJUST_LATENCY);
+ if (pa_stream_connect_playback(m_stream, m_device.data(), &requestedBuffer, flags, nullptr,
+ nullptr)
+ < 0) {
+ qCWarning(qLcPulseAudioOut) << "pa_stream_connect_playback() failed!";
+ pa_stream_unref(m_stream);
+ m_stream = nullptr;
+ pulseEngine->unlock();
+ m_stateMachine.stopOrUpdateError(QAudio::OpenError);
+ return false;
+ }
+
+ while (pa_stream_get_state(m_stream) != PA_STREAM_READY)
+ pa_threaded_mainloop_wait(pulseEngine->mainloop());
+
+ const pa_buffer_attr *buffer = pa_stream_get_buffer_attr(m_stream);
+ m_bufferSize = buffer->tlength;
+
+ if (m_pullMode) {
+ // Adjust period time to reduce chance of it being higher than amount of bytes requested by
+ // PulseAudio server
+ m_pullingPeriodTime =
+ qMin(SinkPeriodTimeMs, pa_bytes_to_usec(m_bufferSize, &m_spec) / 1000 / 2);
+ m_pullingPeriodSize = pa_usec_to_bytes(m_pullingPeriodTime * 1000, &m_spec);
+ }
+
+ m_audioBuffer.resize(buffer->maxlength);
+
+ const qint64 streamSize = m_audioSource ? m_audioSource->size() : 0;
+ if (m_pullMode && streamSize > 0 && static_cast<qint64>(buffer->prebuf) > streamSize) {
+ pa_buffer_attr newBufferAttr;
+ newBufferAttr = *buffer;
+ newBufferAttr.prebuf = streamSize;
+ PAOperationUPtr(pa_stream_set_buffer_attr(m_stream, &newBufferAttr,
+ streamAdjustPrebufferCallback, nullptr));
+ }
+
+ if (Q_UNLIKELY(qLcPulseAudioOut().isEnabled(QtDebugMsg))) {
+ qCDebug(qLcPulseAudioOut) << "Buffering info:";
+ qCDebug(qLcPulseAudioOut) << "\tMax length: " << buffer->maxlength;
+ qCDebug(qLcPulseAudioOut) << "\tTarget length: " << buffer->tlength;
+ qCDebug(qLcPulseAudioOut) << "\tPre-buffering: " << buffer->prebuf;
+ qCDebug(qLcPulseAudioOut) << "\tMinimum request: " << buffer->minreq;
+ qCDebug(qLcPulseAudioOut) << "\tFragment size: " << buffer->fragsize;
+ }
+
+ pulseEngine->unlock();
+
+ connect(pulseEngine, &QPulseAudioEngine::contextFailed, this,
+ &QPulseAudioSink::onPulseContextFailed);
+
+ m_opened = true;
+
+ if (m_pullMode)
+ startPulling();
+
+ m_elapsedTimeOffset = 0;
+
+ return true;
+}
+
+void QPulseAudioSink::close()
+{
+ if (!m_opened)
+ return;
+
+ stopTimer();
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ if (m_stream) {
+ std::lock_guard lock(*pulseEngine);
+
+ pa_stream_set_state_callback(m_stream, nullptr, nullptr);
+ pa_stream_set_write_callback(m_stream, nullptr, nullptr);
+ pa_stream_set_underflow_callback(m_stream, nullptr, nullptr);
+ pa_stream_set_overflow_callback(m_stream, nullptr, nullptr);
+ pa_stream_set_latency_update_callback(m_stream, nullptr, nullptr);
+
+ if (auto prevOp = exchangeDrainOperation(nullptr))
+ // cancel draining operation to prevent calling draining callback after closing.
+ pa_operation_cancel(prevOp.get());
+
+ PAOperationUPtr operation(pa_stream_flush(m_stream, outputStreamFlushComplete, nullptr));
+
+ pa_stream_disconnect(m_stream);
+ pa_stream_unref(m_stream);
+ m_stream = nullptr;
+ }
+
+ disconnect(pulseEngine, &QPulseAudioEngine::contextFailed, this,
+ &QPulseAudioSink::onPulseContextFailed);
+
+ if (m_audioSource) {
+ if (m_pullMode) {
+ disconnect(m_audioSource, &QIODevice::readyRead, this, nullptr);
+ m_audioSource->reset();
+ } else {
+ delete m_audioSource;
+ m_audioSource = nullptr;
+ }
+ }
+
+ m_opened = false;
+ m_audioBuffer.clear();
+}
+
+void QPulseAudioSink::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_tickTimer.timerId() && m_pullMode)
+ userFeed();
+
+ QPlatformAudioSink::timerEvent(event);
+}
+
+void QPulseAudioSink::userFeed()
+{
+ int writableSize = bytesFree();
+
+ if (writableSize == 0) {
+ // PulseAudio server doesn't want any more data
+ m_stateMachine.activateFromIdle();
+ return;
+ }
+
+ // Write up to writableSize
+ const int inputSize =
+ std::min({ m_pullingPeriodSize, static_cast<int>(m_audioBuffer.size()), writableSize });
+
+ Q_ASSERT(!m_audioBuffer.empty());
+ int audioBytesPulled = m_audioSource->read(m_audioBuffer.data(), inputSize);
+ Q_ASSERT(audioBytesPulled <= inputSize);
+
+ if (audioBytesPulled > 0) {
+ if (audioBytesPulled > inputSize) {
+ qCWarning(qLcPulseAudioOut)
+ << "Invalid audio data size provided by pull source:" << audioBytesPulled
+ << "should be less than" << inputSize;
+ audioBytesPulled = inputSize;
+ }
+ auto bytesWritten = write(m_audioBuffer.data(), audioBytesPulled);
+ if (bytesWritten != audioBytesPulled)
+ qWarning() << "Unfinished write:" << bytesWritten << "vs" << audioBytesPulled;
+
+ m_stateMachine.activateFromIdle();
+
+ if (inputSize < writableSize) // PulseAudio needs more data.
+ QMetaObject::invokeMethod(this, &QPulseAudioSink::userFeed, Qt::QueuedConnection);
+ } else if (audioBytesPulled == 0) {
+ stopTimer();
+ const auto atEnd = m_audioSource->atEnd();
+ qCDebug(qLcPulseAudioOut) << "No more data available, source is done:" << atEnd;
+ }
+}
+
+qint64 QPulseAudioSink::write(const char *data, qint64 len)
+{
+ using namespace QPulseAudioInternal;
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ pulseEngine->lock();
+
+ size_t nbytes = len;
+ void *dest = nullptr;
+
+ if (pa_stream_begin_write(m_stream, &dest, &nbytes) < 0) {
+ pulseEngine->unlock();
+ qCWarning(qLcPulseAudioOut)
+ << "pa_stream_begin_write error:" << currentError(pulseEngine->context());
+ m_stateMachine.updateActiveOrIdle(false, QAudio::IOError);
+ return 0;
+ }
+
+ len = qMin(len, qint64(nbytes));
+
+ if (m_volume < 1.0f) {
+ // Don't use PulseAudio volume, as it might affect all other streams of the same category
+ // or even affect the system volume if flat volumes are enabled
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, dest, len);
+ } else {
+ memcpy(dest, data, len);
+ }
+
+ data = reinterpret_cast<char *>(dest);
+
+ if ((pa_stream_write(m_stream, data, len, nullptr, 0, PA_SEEK_RELATIVE)) < 0) {
+ pulseEngine->unlock();
+ qCWarning(qLcPulseAudioOut)
+ << "pa_stream_write error:" << currentError(pulseEngine->context());
+ m_stateMachine.updateActiveOrIdle(false, QAudio::IOError);
+ return 0;
+ }
+
+ pulseEngine->unlock();
+ m_totalTimeValue += len;
+
+ m_stateMachine.updateActiveOrIdle(true);
+ return len;
+}
+
+void QPulseAudioSink::stop()
+{
+ if (auto notifier = m_stateMachine.stop()) {
+ {
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ std::lock_guard lock(*pulseEngine);
+
+ if (auto prevOp = exchangeDrainOperation(nullptr))
+ // cancel the draining callback that is not relevant already
+ pa_operation_cancel(prevOp.get());
+
+ PAOperationUPtr drainOp(pa_stream_drain(m_stream, outputStreamDrainComplete, nullptr));
+ pulseEngine->wait(drainOp.get());
+ }
+
+ close();
+ }
+}
+
+qsizetype QPulseAudioSink::bytesFree() const
+{
+ if (!m_stateMachine.isActiveOrIdle())
+ return 0;
+
+ std::lock_guard lock(*QPulseAudioEngine::instance());
+ return pa_stream_writable_size(m_stream);
+}
+
+void QPulseAudioSink::setBufferSize(qsizetype value)
+{
+ m_userBufferSize = value;
+}
+
+qsizetype QPulseAudioSink::bufferSize() const
+{
+ if (m_bufferSize)
+ return m_bufferSize;
+
+ if (m_userBufferSize)
+ return *m_userBufferSize;
+
+ return defaultBufferSize();
+}
+
+static qint64 operator-(timeval t1, timeval t2)
+{
+ constexpr qint64 secsToUSecs = 1000000;
+ return (t1.tv_sec - t2.tv_sec) * secsToUSecs + (t1.tv_usec - t2.tv_usec);
+}
+
+qint64 QPulseAudioSink::processedUSecs() const
+{
+ const auto state = this->state();
+ if (!m_stream || state == QAudio::StoppedState)
+ return 0;
+ if (state == QAudio::SuspendedState)
+ return lastProcessedUSecs;
+
+ auto info = pa_stream_get_timing_info(m_stream);
+ if (!info)
+ return lastProcessedUSecs;
+
+ // if the info changed, update our cached data, and recalculate the average latency
+ if (info->timestamp - lastTimingInfo > 0) {
+ lastTimingInfo.tv_sec = info->timestamp.tv_sec;
+ lastTimingInfo.tv_usec = info->timestamp.tv_usec;
+ averageLatency =
+ 0; // also use that as long as we don't have valid data from the timing info
+
+ // Only use timing values when playing, otherwise the latency numbers can be way off
+ if (info->since_underrun >= 0
+ && pa_bytes_to_usec(info->since_underrun, &m_spec) > info->sink_usec) {
+ latencyList.append(info->sink_usec);
+ // Average over the last X timing infos to keep numbers more stable.
+ // 10 seems to be a decent number that keeps values relatively stable but doesn't make
+ // the list too big
+ const int latencyListMaxSize = 10;
+ if (latencyList.size() > latencyListMaxSize)
+ latencyList.pop_front();
+ for (const auto l : latencyList)
+ averageLatency += l;
+ averageLatency /= latencyList.size();
+ if (averageLatency < 0)
+ averageLatency = 0;
+ }
+ }
+
+ const qint64 usecsRead = info->read_index < 0 ? 0 : pa_bytes_to_usec(info->read_index, &m_spec);
+ const qint64 usecsWritten =
+ info->write_index < 0 ? 0 : pa_bytes_to_usec(info->write_index, &m_spec);
+
+ // processed data is the amount read by the server minus its latency
+ qint64 usecs = usecsRead - averageLatency;
+
+ timeval tv;
+ gettimeofday(&tv, nullptr);
+
+ // and now adjust for the time since the last update
+ qint64 timeSinceUpdate = tv - info->timestamp;
+ if (timeSinceUpdate > 0)
+ usecs += timeSinceUpdate;
+
+ // We can never have processed more than we've written to the sink
+ if (usecs > usecsWritten)
+ usecs = usecsWritten;
+
+ // make sure timing is monotonic
+ if (usecs < lastProcessedUSecs)
+ usecs = lastProcessedUSecs;
+ else
+ lastProcessedUSecs = usecs;
+
+ return usecs;
+}
+
+void QPulseAudioSink::resume()
+{
+ if (auto notifier = m_stateMachine.resume()) {
+ {
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ std::lock_guard lock(*pulseEngine);
+
+ PAOperationUPtr operation(
+ pa_stream_cork(m_stream, 0, outputStreamSuccessCallback, nullptr));
+ pulseEngine->wait(operation.get());
+
+ operation.reset(pa_stream_trigger(m_stream, outputStreamSuccessCallback, nullptr));
+ pulseEngine->wait(operation.get());
+ }
+
+ if (m_pullMode)
+ startPulling();
+ }
+}
+
+void QPulseAudioSink::setFormat(const QAudioFormat &format)
+{
+ m_format = format;
+}
+
+QAudioFormat QPulseAudioSink::format() const
+{
+ return m_format;
+}
+
+void QPulseAudioSink::suspend()
+{
+ if (auto notifier = m_stateMachine.suspend()) {
+ stopTimer();
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ std::lock_guard lock(*pulseEngine);
+
+ PAOperationUPtr operation(
+ pa_stream_cork(m_stream, 1, outputStreamSuccessCallback, nullptr));
+ pulseEngine->wait(operation.get());
+ }
+}
+
+void QPulseAudioSink::reset()
+{
+ if (auto notifier = m_stateMachine.stopOrUpdateError())
+ close();
+}
+
+PulseOutputPrivate::PulseOutputPrivate(QPulseAudioSink *audio)
+{
+ m_audioDevice = qobject_cast<QPulseAudioSink *>(audio);
+}
+
+qint64 PulseOutputPrivate::readData(char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+}
+
+qint64 PulseOutputPrivate::writeData(const char *data, qint64 len)
+{
+ qint64 written = 0;
+
+ const auto state = m_audioDevice->state();
+ if (state == QAudio::ActiveState || state == QAudio::IdleState) {
+ while (written < len) {
+ int chunk = m_audioDevice->write(data + written, (len - written));
+ if (chunk <= 0)
+ return written;
+ written += chunk;
+ }
+ }
+
+ return written;
+}
+
+void QPulseAudioSink::setVolume(qreal vol)
+{
+ if (qFuzzyCompare(m_volume, vol))
+ return;
+
+ m_volume = qBound(qreal(0), vol, qreal(1));
+}
+
+qreal QPulseAudioSink::volume() const
+{
+ return m_volume;
+}
+
+void QPulseAudioSink::onPulseContextFailed()
+{
+ if (auto notifier = m_stateMachine.stop(QAudio::FatalError))
+ close();
+}
+
+PAOperationUPtr QPulseAudioSink::exchangeDrainOperation(pa_operation *newOperation)
+{
+ return PAOperationUPtr(m_drainOperation.exchange(newOperation));
+}
+
+qsizetype QPulseAudioSink::defaultBufferSize() const
+{
+ if (m_spec.rate > 0)
+ return pa_usec_to_bytes(DefaultBufferLengthMs * 1000, &m_spec);
+
+ auto spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format);
+ if (pa_sample_spec_valid(&spec))
+ return pa_usec_to_bytes(DefaultBufferLengthMs * 1000, &spec);
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpulseaudiosink_p.cpp"
diff --git a/src/multimedia/pulseaudio/qpulseaudiosink_p.h b/src/multimedia/pulseaudio/qpulseaudiosink_p.h
new file mode 100644
index 000000000..cf0b181ec
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiosink_p.h
@@ -0,0 +1,136 @@
+// 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 QAUDIOOUTPUTPULSE_H
+#define QAUDIOOUTPUTPULSE_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 "qaudio.h"
+#include "qaudiodevice.h"
+#include "pulseaudio/qpulsehelpers_p.h"
+
+#include <private/qaudiosystem_p.h>
+#include <private/qaudiostatemachine_p.h>
+#include <pulse/pulseaudio.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPulseAudioSink : public QPlatformAudioSink
+{
+ friend class PulseOutputPrivate;
+ Q_OBJECT
+
+public:
+ QPulseAudioSink(const QByteArray &device, QObject *parent);
+ ~QPulseAudioSink();
+
+ 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;
+
+ void streamUnderflowCallback();
+ void streamDrainedCallback();
+
+protected:
+ void timerEvent(QTimerEvent *event) override;
+
+private:
+ void startPulling();
+ void stopTimer();
+
+ bool open();
+ void close();
+ qint64 write(const char *data, qint64 len);
+
+private Q_SLOTS:
+ void userFeed();
+ void onPulseContextFailed();
+
+ PAOperationUPtr exchangeDrainOperation(pa_operation *newOperation);
+
+private:
+ qsizetype defaultBufferSize() const;
+
+ pa_sample_spec m_spec = {};
+ // calculate timing manually, as pulseaudio doesn't give us good enough data
+ mutable timeval lastTimingInfo = {};
+
+ mutable QList<qint64> latencyList; // last latency values
+
+ QByteArray m_device;
+ QByteArray m_streamName;
+ QAudioFormat m_format;
+ QBasicTimer m_tickTimer;
+
+ QIODevice *m_audioSource = nullptr;
+ pa_stream *m_stream = nullptr;
+ std::vector<char> m_audioBuffer;
+
+ qint64 m_totalTimeValue = 0;
+ qint64 m_elapsedTimeOffset = 0;
+ mutable qint64 averageLatency = 0; // average latency
+ mutable qint64 lastProcessedUSecs = 0;
+ qreal m_volume = 1.0;
+
+ std::atomic<pa_operation *> m_drainOperation = nullptr;
+ qsizetype m_bufferSize = 0;
+ std::optional<qsizetype> m_userBufferSize = std::nullopt;
+ int m_pullingPeriodSize = 0;
+ int m_pullingPeriodTime = 0;
+ bool m_pullMode = true;
+ bool m_opened = false;
+
+ QAudioStateMachine m_stateMachine;
+};
+
+class PulseOutputPrivate : public QIODevice
+{
+ friend class QPulseAudioSink;
+ Q_OBJECT
+
+public:
+ PulseOutputPrivate(QPulseAudioSink *audio);
+ virtual ~PulseOutputPrivate() {}
+
+protected:
+ qint64 readData(char *data, qint64 len) override;
+ qint64 writeData(const char *data, qint64 len) override;
+
+private:
+ QPulseAudioSink *m_audioDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/pulseaudio/qpulseaudiosource.cpp b/src/multimedia/pulseaudio/qpulseaudiosource.cpp
new file mode 100644
index 000000000..488daa48b
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiosource.cpp
@@ -0,0 +1,566 @@
+// 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 <private/qaudiohelpers_p.h>
+
+#include "qpulseaudiosource_p.h"
+#include "qaudioengine_pulse_p.h"
+#include "qpulseaudiodevice_p.h"
+#include "qpulsehelpers_p.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <mutex> // for lock_guard
+
+QT_BEGIN_NAMESPACE
+
+const int SourcePeriodTimeMs = 50;
+
+static void inputStreamReadCallback(pa_stream *stream, size_t length, void *userdata)
+{
+ Q_UNUSED(userdata);
+ Q_UNUSED(length);
+ Q_UNUSED(stream);
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+}
+
+static void inputStreamStateCallback(pa_stream *stream, void *userdata)
+{
+ using namespace QPulseAudioInternal;
+
+ Q_UNUSED(userdata);
+ pa_stream_state_t state = pa_stream_get_state(stream);
+ qCDebug(qLcPulseAudioIn) << "Stream state: " << state;
+ switch (state) {
+ case PA_STREAM_CREATING:
+ break;
+ case PA_STREAM_READY:
+ if (Q_UNLIKELY(qLcPulseAudioIn().isEnabled(QtDebugMsg))) {
+ QPulseAudioSource *audioInput = static_cast<QPulseAudioSource *>(userdata);
+ const pa_buffer_attr *buffer_attr = pa_stream_get_buffer_attr(stream);
+ qCDebug(qLcPulseAudioIn) << "*** maxlength: " << buffer_attr->maxlength;
+ qCDebug(qLcPulseAudioIn) << "*** prebuf: " << buffer_attr->prebuf;
+ qCDebug(qLcPulseAudioIn) << "*** fragsize: " << buffer_attr->fragsize;
+ qCDebug(qLcPulseAudioIn) << "*** minreq: " << buffer_attr->minreq;
+ qCDebug(qLcPulseAudioIn) << "*** tlength: " << buffer_attr->tlength;
+
+ pa_sample_spec spec =
+ QPulseAudioInternal::audioFormatToSampleSpec(audioInput->format());
+ qCDebug(qLcPulseAudioIn)
+ << "*** bytes_to_usec: " << pa_bytes_to_usec(buffer_attr->fragsize, &spec);
+ }
+ break;
+ case PA_STREAM_TERMINATED:
+ break;
+ case PA_STREAM_FAILED:
+ default:
+ qWarning() << "Stream error: " << currentError(stream);
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+ break;
+ }
+}
+
+static void inputStreamUnderflowCallback(pa_stream *stream, void *userdata)
+{
+ Q_UNUSED(userdata);
+ Q_UNUSED(stream);
+ qWarning() << "Got a buffer underflow!";
+}
+
+static void inputStreamOverflowCallback(pa_stream *stream, void *userdata)
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(userdata);
+ qWarning() << "Got a buffer overflow!";
+}
+
+static void inputStreamSuccessCallback(pa_stream *stream, int success, void *userdata)
+{
+ Q_UNUSED(stream);
+ Q_UNUSED(userdata);
+ Q_UNUSED(success);
+
+ // if (!success)
+ // TODO: Is cork success? i->operation_success = success;
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+}
+
+QPulseAudioSource::QPulseAudioSource(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSource(parent),
+ m_totalTimeValue(0),
+ m_audioSource(nullptr),
+ m_volume(qreal(1.0f)),
+ m_pullMode(true),
+ m_opened(false),
+ m_bufferSize(0),
+ m_periodSize(0),
+ m_periodTime(SourcePeriodTimeMs),
+ m_stream(nullptr),
+ m_device(device),
+ m_stateMachine(*this)
+{
+}
+
+QPulseAudioSource::~QPulseAudioSource()
+{
+ // TODO: Investigate draining the stream
+ if (auto notifier = m_stateMachine.stop())
+ close();
+}
+
+QAudio::Error QPulseAudioSource::error() const
+{
+ return m_stateMachine.error();
+}
+
+QAudio::State QPulseAudioSource::state() const
+{
+ return m_stateMachine.state();
+}
+
+void QPulseAudioSource::setFormat(const QAudioFormat &format)
+{
+ if (!m_stateMachine.isActiveOrIdle())
+ m_format = format;
+}
+
+QAudioFormat QPulseAudioSource::format() const
+{
+ return m_format;
+}
+
+void QPulseAudioSource::start(QIODevice *device)
+{
+ reset();
+
+ if (!open())
+ return;
+
+ m_pullMode = true;
+ m_audioSource = device;
+
+ m_stateMachine.start();
+}
+
+QIODevice *QPulseAudioSource::start()
+{
+ reset();
+
+ if (!open())
+ return nullptr;
+
+ m_pullMode = false;
+ m_audioSource = new PulseInputPrivate(this);
+ m_audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+
+ m_stateMachine.start(false);
+
+ return m_audioSource;
+}
+
+void QPulseAudioSource::stop()
+{
+ if (auto notifier = m_stateMachine.stop())
+ close();
+}
+
+bool QPulseAudioSource::open()
+{
+ if (m_opened)
+ return true;
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ if (!pulseEngine->context()
+ || pa_context_get_state(pulseEngine->context()) != PA_CONTEXT_READY) {
+ m_stateMachine.stopOrUpdateError(QAudio::FatalError);
+ return false;
+ }
+
+ pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format);
+ pa_channel_map channel_map = QPulseAudioInternal::channelMapForAudioFormat(m_format);
+ Q_ASSERT(spec.channels == channel_map.channels);
+
+ if (!pa_sample_spec_valid(&spec)) {
+ m_stateMachine.stopOrUpdateError(QAudio::OpenError);
+ return false;
+ }
+
+ m_spec = spec;
+
+ //if (Q_UNLIKELY(qLcPulseAudioIn().isEnabled(QtDebugMsg)) {
+ // QTime now(QTime::currentTime());
+ // qCDebug(qLcPulseAudioIn) << now.second() << "s " << now.msec() << "ms :open()";
+ //}
+
+ if (m_streamName.isNull())
+ m_streamName =
+ QStringLiteral("QtmPulseStream-%1-%2").arg(::getpid()).arg(quintptr(this)).toUtf8();
+
+ if (Q_UNLIKELY(qLcPulseAudioIn().isEnabled(QtDebugMsg))) {
+ qCDebug(qLcPulseAudioIn) << "Format: " << spec.format;
+ qCDebug(qLcPulseAudioIn) << "Rate: " << spec.rate;
+ qCDebug(qLcPulseAudioIn) << "Channels: " << spec.channels;
+ qCDebug(qLcPulseAudioIn) << "Frame size: " << pa_frame_size(&spec);
+ }
+
+ pulseEngine->lock();
+
+ m_stream = pa_stream_new(pulseEngine->context(), m_streamName.constData(), &spec, &channel_map);
+
+ pa_stream_set_state_callback(m_stream, inputStreamStateCallback, this);
+ pa_stream_set_read_callback(m_stream, inputStreamReadCallback, this);
+
+ pa_stream_set_underflow_callback(m_stream, inputStreamUnderflowCallback, this);
+ pa_stream_set_overflow_callback(m_stream, inputStreamOverflowCallback, this);
+
+ m_periodSize = pa_usec_to_bytes(SourcePeriodTimeMs * 1000, &spec);
+
+ int flags = 0;
+ pa_buffer_attr buffer_attr;
+ buffer_attr.maxlength = static_cast<uint32_t>(-1);
+ buffer_attr.prebuf = static_cast<uint32_t>(-1);
+ buffer_attr.tlength = static_cast<uint32_t>(-1);
+ buffer_attr.minreq = static_cast<uint32_t>(-1);
+ flags |= PA_STREAM_ADJUST_LATENCY;
+
+ if (m_bufferSize > 0)
+ buffer_attr.fragsize = static_cast<uint32_t>(m_bufferSize);
+ else
+ buffer_attr.fragsize = static_cast<uint32_t>(m_periodSize);
+
+ flags |= PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING;
+
+ int connectionResult = pa_stream_connect_record(m_stream, m_device.data(), &buffer_attr,
+ static_cast<pa_stream_flags_t>(flags));
+ if (connectionResult < 0) {
+ qWarning() << "pa_stream_connect_record() failed!";
+ pa_stream_unref(m_stream);
+ m_stream = nullptr;
+ pulseEngine->unlock();
+ m_stateMachine.stopOrUpdateError(QAudio::OpenError);
+ return false;
+ }
+
+ //if (Q_UNLIKELY(qLcPulseAudioIn().isEnabled(QtDebugMsg))) {
+ // auto *ss = pa_stream_get_sample_spec(m_stream);
+ // qCDebug(qLcPulseAudioIn) << "connected stream:";
+ // qCDebug(qLcPulseAudioIn) << " channels" << ss->channels << spec.channels;
+ // qCDebug(qLcPulseAudioIn) << " format" << ss->format << spec.format;
+ // qCDebug(qLcPulseAudioIn) << " rate" << ss->rate << spec.rate;
+ //}
+
+ while (pa_stream_get_state(m_stream) != PA_STREAM_READY)
+ pa_threaded_mainloop_wait(pulseEngine->mainloop());
+
+ const pa_buffer_attr *actualBufferAttr = pa_stream_get_buffer_attr(m_stream);
+ m_periodSize = actualBufferAttr->fragsize;
+ m_periodTime = pa_bytes_to_usec(m_periodSize, &spec) / 1000;
+ if (actualBufferAttr->tlength != static_cast<uint32_t>(-1))
+ m_bufferSize = actualBufferAttr->tlength;
+
+ pulseEngine->unlock();
+
+ connect(pulseEngine, &QPulseAudioEngine::contextFailed, this,
+ &QPulseAudioSource::onPulseContextFailed);
+
+ m_opened = true;
+ m_timer.start(m_periodTime, this);
+
+ m_elapsedTimeOffset = 0;
+ m_totalTimeValue = 0;
+
+ return true;
+}
+
+void QPulseAudioSource::close()
+{
+ if (!m_opened)
+ return;
+
+ m_timer.stop();
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ if (m_stream) {
+ std::lock_guard lock(*pulseEngine);
+
+ pa_stream_set_state_callback(m_stream, nullptr, nullptr);
+ pa_stream_set_read_callback(m_stream, nullptr, nullptr);
+ pa_stream_set_underflow_callback(m_stream, nullptr, nullptr);
+ pa_stream_set_overflow_callback(m_stream, nullptr, nullptr);
+
+ pa_stream_disconnect(m_stream);
+ pa_stream_unref(m_stream);
+ m_stream = nullptr;
+ }
+
+ disconnect(pulseEngine, &QPulseAudioEngine::contextFailed, this,
+ &QPulseAudioSource::onPulseContextFailed);
+
+ if (!m_pullMode && m_audioSource) {
+ delete m_audioSource;
+ m_audioSource = nullptr;
+ }
+ m_opened = false;
+}
+
+qsizetype QPulseAudioSource::bytesReady() const
+{
+ using namespace QPulseAudioInternal;
+
+ if (!m_stateMachine.isActiveOrIdle())
+ return 0;
+
+ std::lock_guard lock(*QPulseAudioEngine::instance());
+
+ int bytes = pa_stream_readable_size(m_stream);
+ if (bytes < 0) {
+ qWarning() << "pa_stream_readable_size() failed:" << currentError(m_stream);
+ return 0;
+ }
+
+ return static_cast<qsizetype>(bytes);
+}
+
+qint64 QPulseAudioSource::read(char *data, qint64 len)
+{
+ using namespace QPulseAudioInternal;
+
+ Q_ASSERT(data != nullptr || len == 0);
+
+ m_stateMachine.updateActiveOrIdle(true, QAudio::NoError);
+ int readBytes = 0;
+
+ if (!m_pullMode && !m_tempBuffer.isEmpty()) {
+ readBytes = qMin(static_cast<int>(len), m_tempBuffer.size());
+ if (readBytes)
+ memcpy(data, m_tempBuffer.constData(), readBytes);
+ m_totalTimeValue += readBytes;
+
+ if (readBytes < m_tempBuffer.size()) {
+ m_tempBuffer.remove(0, readBytes);
+ return readBytes;
+ }
+
+ m_tempBuffer.clear();
+ }
+
+ while (pa_stream_readable_size(m_stream) > 0) {
+ size_t readLength = 0;
+
+ if (Q_UNLIKELY(qLcPulseAudioIn().isEnabled(QtDebugMsg))) {
+ auto readableSize = pa_stream_readable_size(m_stream);
+ qCDebug(qLcPulseAudioIn) << "QPulseAudioSource::read -- " << readableSize
+ << " bytes available from pulse audio";
+ }
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pulseEngine->lock();
+
+ const void *audioBuffer;
+
+ // Second and third parameters (audioBuffer and length) to pa_stream_peek are output
+ // parameters, the audioBuffer pointer is set to point to the actual pulse audio data, and
+ // the length is set to the length of this data.
+ if (pa_stream_peek(m_stream, &audioBuffer, &readLength) < 0) {
+ qWarning() << "pa_stream_peek() failed:" << currentError(m_stream);
+ pulseEngine->unlock();
+ return 0;
+ }
+
+ qint64 actualLength = 0;
+ if (m_pullMode) {
+ QByteArray adjusted(readLength, Qt::Uninitialized);
+ applyVolume(audioBuffer, adjusted.data(), readLength);
+ actualLength = m_audioSource->write(adjusted);
+
+ if (actualLength < qint64(readLength)) {
+ pulseEngine->unlock();
+ m_stateMachine.updateActiveOrIdle(false, QAudio::UnderrunError);
+ return actualLength;
+ }
+ } else {
+ actualLength = qMin(static_cast<int>(len - readBytes), static_cast<int>(readLength));
+ applyVolume(audioBuffer, data + readBytes, actualLength);
+ }
+
+ qCDebug(qLcPulseAudioIn) << "QPulseAudioSource::read -- wrote " << actualLength
+ << " to client";
+
+ if (actualLength < qint64(readLength)) {
+ int diff = readLength - actualLength;
+ int oldSize = m_tempBuffer.size();
+
+ qCDebug(qLcPulseAudioIn) << "QPulseAudioSource::read -- appending " << diff
+ << " bytes of data to temp buffer";
+
+ m_tempBuffer.resize(m_tempBuffer.size() + diff);
+ applyVolume(static_cast<const char *>(audioBuffer) + actualLength,
+ m_tempBuffer.data() + oldSize, diff);
+ QMetaObject::invokeMethod(this, "userFeed", Qt::QueuedConnection);
+ }
+
+ m_totalTimeValue += actualLength;
+ readBytes += actualLength;
+
+ pa_stream_drop(m_stream);
+ pulseEngine->unlock();
+
+ if (!m_pullMode && readBytes >= len)
+ break;
+ }
+
+ qCDebug(qLcPulseAudioIn) << "QPulseAudioSource::read -- returning after reading " << readBytes
+ << " bytes";
+
+ return readBytes;
+}
+
+void QPulseAudioSource::applyVolume(const void *src, void *dest, int len)
+{
+ Q_ASSERT((src && dest) || len == 0);
+ if (m_volume < 1.f)
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_format, src, dest, len);
+ else if (len)
+ memcpy(dest, src, len);
+}
+
+void QPulseAudioSource::resume()
+{
+ if (auto notifier = m_stateMachine.resume()) {
+ {
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ std::lock_guard lock(*pulseEngine);
+
+ PAOperationUPtr operation(
+ pa_stream_cork(m_stream, 0, inputStreamSuccessCallback, nullptr));
+ pulseEngine->wait(operation.get());
+ }
+
+ m_timer.start(m_periodTime, this);
+ }
+}
+
+void QPulseAudioSource::setVolume(qreal vol)
+{
+ if (qFuzzyCompare(m_volume, vol))
+ return;
+
+ m_volume = qBound(qreal(0), vol, qreal(1));
+}
+
+qreal QPulseAudioSource::volume() const
+{
+ return m_volume;
+}
+
+void QPulseAudioSource::setBufferSize(qsizetype value)
+{
+ m_bufferSize = value;
+}
+
+qsizetype QPulseAudioSource::bufferSize() const
+{
+ return m_bufferSize;
+}
+
+qint64 QPulseAudioSource::processedUSecs() const
+{
+ if (!m_stream)
+ return 0;
+ pa_usec_t usecs = 0;
+ int result = pa_stream_get_time(m_stream, &usecs);
+ Q_UNUSED(result);
+ //if (result != 0)
+ // qWarning() << "no timing info from pulse";
+
+ return usecs;
+}
+
+void QPulseAudioSource::suspend()
+{
+ if (auto notifier = m_stateMachine.suspend()) {
+ m_timer.stop();
+
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+
+ std::lock_guard lock(*pulseEngine);
+
+ PAOperationUPtr operation(pa_stream_cork(m_stream, 1, inputStreamSuccessCallback, nullptr));
+ pulseEngine->wait(operation.get());
+ }
+}
+
+void QPulseAudioSource::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_timer.timerId())
+ userFeed();
+
+ QPlatformAudioSource::timerEvent(event);
+}
+
+void QPulseAudioSource::userFeed()
+{
+ if (!m_stateMachine.isActiveOrIdle())
+ return;
+
+ //if (Q_UNLIKELY(qLcPulseAudioIn().isEnabled(QtDebugMsg)) {
+ // QTime now(QTime::currentTime());
+ // qCDebug(qLcPulseAudioIn) << now.second() << "s " << now.msec() << "ms :userFeed() IN";
+ //}
+
+ if (m_pullMode) {
+ // reads some audio data and writes it to QIODevice
+ read(nullptr,0);
+ } else if (m_audioSource != nullptr) {
+ // emits readyRead() so user will call read() on QIODevice to get some audio data
+ PulseInputPrivate *a = qobject_cast<PulseInputPrivate*>(m_audioSource);
+ a->trigger();
+ }
+}
+
+void QPulseAudioSource::reset()
+{
+ if (auto notifier = m_stateMachine.stopOrUpdateError())
+ close();
+}
+
+void QPulseAudioSource::onPulseContextFailed()
+{
+ if (auto notifier = m_stateMachine.stopOrUpdateError(QAudio::FatalError))
+ close();
+}
+
+PulseInputPrivate::PulseInputPrivate(QPulseAudioSource *audio)
+{
+ m_audioDevice = qobject_cast<QPulseAudioSource *>(audio);
+}
+
+qint64 PulseInputPrivate::readData(char *data, qint64 len)
+{
+ return m_audioDevice->read(data, len);
+}
+
+qint64 PulseInputPrivate::writeData(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+ return 0;
+}
+
+void PulseInputPrivate::trigger()
+{
+ emit readyRead();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpulseaudiosource_p.cpp"
diff --git a/src/multimedia/platform/pulseaudio/qpulseaudiosource_p.h b/src/multimedia/pulseaudio/qpulseaudiosource_p.h
index 7a9f047dd..d652f81a0 100644
--- a/src/multimedia/platform/pulseaudio/qpulseaudiosource_p.h
+++ b/src/multimedia/pulseaudio/qpulseaudiosource_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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
@@ -61,6 +25,7 @@
#include "qaudio.h"
#include "qaudiodevice.h"
#include <private/qaudiosystem_p.h>
+#include <private/qaudiostatemachine_p.h>
#include <pulse/pulseaudio.h>
@@ -73,7 +38,7 @@ class QPulseAudioSource : public QPlatformAudioSource
Q_OBJECT
public:
- QPulseAudioSource(const QByteArray &device);
+ QPulseAudioSource(const QByteArray &device, QObject *parent);
~QPulseAudioSource();
qint64 read(char *data, qint64 len);
@@ -99,38 +64,35 @@ public:
qint64 m_totalTimeValue;
QIODevice *m_audioSource;
QAudioFormat m_format;
- QAudio::Error m_errorState;
- QAudio::State m_deviceState;
qreal m_volume;
+protected:
+ void timerEvent(QTimerEvent *event) override;
+
private slots:
void userFeed();
- bool deviceReady();
void onPulseContextFailed();
private:
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
void applyVolume(const void *src, void *dest, int len);
- int checkBytesReady();
bool open();
void close();
bool m_pullMode;
bool m_opened;
- int m_bytesAvailable;
int m_bufferSize;
int m_periodSize;
unsigned int m_periodTime;
- QTimer *m_timer;
+ QBasicTimer m_timer;
qint64 m_elapsedTimeOffset;
pa_stream *m_stream;
QByteArray m_streamName;
QByteArray m_device;
QByteArray m_tempBuffer;
pa_sample_spec m_spec;
+
+ QAudioStateMachine m_stateMachine;
};
class PulseInputPrivate : public QIODevice
@@ -138,7 +100,7 @@ class PulseInputPrivate : public QIODevice
Q_OBJECT
public:
PulseInputPrivate(QPulseAudioSource *audio);
- ~PulseInputPrivate() {};
+ ~PulseInputPrivate() override = default;
qint64 readData(char *data, qint64 len) override;
qint64 writeData(const char *data, qint64 len) override;
diff --git a/src/multimedia/pulseaudio/qpulsehelpers.cpp b/src/multimedia/pulseaudio/qpulsehelpers.cpp
new file mode 100644
index 000000000..bc03e133f
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulsehelpers.cpp
@@ -0,0 +1,284 @@
+// 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 "qpulsehelpers_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcPulseAudioOut, "qt.multimedia.pulseaudio.output")
+Q_LOGGING_CATEGORY(qLcPulseAudioIn, "qt.multimedia.pulseaudio.input")
+Q_LOGGING_CATEGORY(qLcPulseAudioEngine, "qt.multimedia.pulseaudio.engine")
+
+namespace QPulseAudioInternal
+{
+pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
+{
+ pa_sample_spec spec;
+
+ spec.rate = format.sampleRate();
+ spec.channels = format.channelCount();
+ spec.format = PA_SAMPLE_INVALID;
+ const bool isBigEndian = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+
+ if (format.sampleFormat() == QAudioFormat::UInt8) {
+ spec.format = PA_SAMPLE_U8;
+ } else if (format.sampleFormat() == QAudioFormat::Int16) {
+ spec.format = isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
+ } else if (format.sampleFormat() == QAudioFormat::Int32) {
+ spec.format = isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
+ } else if (format.sampleFormat() == QAudioFormat::Float) {
+ spec.format = isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
+ }
+
+ return spec;
+}
+
+pa_channel_map channelMapForAudioFormat(const QAudioFormat &format)
+{
+ pa_channel_map map;
+ map.channels = 0;
+
+ auto config = format.channelConfig();
+ if (config == QAudioFormat::ChannelConfigUnknown)
+ config = QAudioFormat::defaultChannelConfigForChannelCount(format.channelCount());
+
+ if (config == QAudioFormat::ChannelConfigMono) {
+ map.channels = 1;
+ map.map[0] = PA_CHANNEL_POSITION_MONO;
+ } else {
+ if (config & QAudioFormat::channelConfig(QAudioFormat::FrontLeft))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::FrontRight))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::FrontCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::LFE))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::BackLeft))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::BackRight))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::FrontLeftOfCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::FrontRightOfCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::BackCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::LFE2))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::SideLeft))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::SideRight))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopFrontLeft))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopFrontRight))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopFrontCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_CENTER;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopBackLeft))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopBackRight))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopSideLeft))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopSideRight))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_AUX1;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::TopBackCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_AUX2;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_AUX3;
+ if (config & QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight))
+ map.map[map.channels++] = PA_CHANNEL_POSITION_AUX4;
+ }
+
+ Q_ASSERT(qPopulationCount(config) == map.channels);
+ return map;
+}
+
+QAudioFormat::ChannelConfig channelConfigFromMap(const pa_channel_map &map)
+{
+ quint32 config = 0;
+ for (int i = 0; i < map.channels; ++i) {
+ switch (map.map[i]) {
+ case PA_CHANNEL_POSITION_MONO:
+ case PA_CHANNEL_POSITION_FRONT_CENTER:
+ config |= QAudioFormat::channelConfig(QAudioFormat::FrontCenter);
+ break;
+ case PA_CHANNEL_POSITION_FRONT_LEFT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::FrontLeft);
+ break;
+ case PA_CHANNEL_POSITION_FRONT_RIGHT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::FrontRight);
+ break;
+ case PA_CHANNEL_POSITION_REAR_CENTER:
+ config |= QAudioFormat::channelConfig(QAudioFormat::BackCenter);
+ break;
+ case PA_CHANNEL_POSITION_REAR_LEFT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::BackLeft);
+ break;
+ case PA_CHANNEL_POSITION_REAR_RIGHT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::BackRight);
+ break;
+ case PA_CHANNEL_POSITION_LFE:
+ config |= QAudioFormat::channelConfig(QAudioFormat::LFE);
+ break;
+ case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
+ config |= QAudioFormat::channelConfig(QAudioFormat::FrontLeftOfCenter);
+ break;
+ case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
+ config |= QAudioFormat::channelConfig(QAudioFormat::FrontRightOfCenter);
+ break;
+ case PA_CHANNEL_POSITION_SIDE_LEFT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::SideLeft);
+ break;
+ case PA_CHANNEL_POSITION_SIDE_RIGHT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::SideRight);
+ break;
+
+ case PA_CHANNEL_POSITION_TOP_CENTER:
+ config |= QAudioFormat::channelConfig(QAudioFormat::TopCenter);
+ break;
+ case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::TopFrontLeft);
+ break;
+ case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::TopFrontRight);
+ break;
+ case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
+ config |= QAudioFormat::channelConfig(QAudioFormat::TopFrontCenter);
+ break;
+ case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::TopBackLeft);
+ break;
+ case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
+ config |= QAudioFormat::channelConfig(QAudioFormat::TopBackRight);
+ break;
+ case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
+ config |= QAudioFormat::channelConfig(QAudioFormat::TopBackCenter);
+ break;
+ default:
+ break;
+ }
+ }
+ return QAudioFormat::ChannelConfig(config);
+}
+
+QAudioFormat sampleSpecToAudioFormat(const pa_sample_spec &spec)
+{
+ QAudioFormat format;
+
+ format.setSampleRate(spec.rate);
+ format.setChannelCount(spec.channels);
+ QAudioFormat::SampleFormat sampleFormat;
+ switch (spec.format) {
+ case PA_SAMPLE_U8:
+ sampleFormat = QAudioFormat::UInt8;
+ break;
+ case PA_SAMPLE_S16LE:
+ case PA_SAMPLE_S16BE:
+ sampleFormat = QAudioFormat::Int16;
+ break;
+ case PA_SAMPLE_FLOAT32LE:
+ case PA_SAMPLE_FLOAT32BE:
+ sampleFormat = QAudioFormat::Float;
+ break;
+ case PA_SAMPLE_S32LE:
+ case PA_SAMPLE_S32BE:
+ sampleFormat = QAudioFormat::Int32;
+ break;
+ default:
+ return {};
+ }
+
+ format.setSampleFormat(sampleFormat);
+ return format;
+}
+
+QUtf8StringView currentError(const pa_context *context)
+{
+ return pa_strerror(pa_context_errno(context));
+}
+
+QUtf8StringView currentError(const pa_stream *stream)
+{
+ return currentError(pa_stream_get_context(stream));
+}
+
+} // namespace QPulseAudioInternal
+
+static QLatin1StringView stateToQStringView(pa_stream_state_t state)
+{
+ using namespace Qt::StringLiterals;
+ switch (state)
+ {
+ case PA_STREAM_UNCONNECTED: return "Unconnected"_L1;
+ case PA_STREAM_CREATING: return "Creating"_L1;
+ case PA_STREAM_READY: return "Ready"_L1;
+ case PA_STREAM_FAILED: return "Failed"_L1;
+ case PA_STREAM_TERMINATED: return "Terminated"_L1;
+ default: Q_UNREACHABLE_RETURN("Unknown stream state"_L1);
+ }
+}
+
+static QLatin1StringView sampleFormatToQStringView(pa_sample_format format)
+{
+ using namespace Qt::StringLiterals;
+ switch (format)
+ {
+ case PA_SAMPLE_U8: return "Unsigned 8 Bit PCM."_L1;
+ case PA_SAMPLE_ALAW: return "8 Bit a-Law "_L1;
+ case PA_SAMPLE_ULAW: return "8 Bit mu-Law"_L1;
+ case PA_SAMPLE_S16LE: return "Signed 16 Bit PCM, little endian (PC)."_L1;
+ case PA_SAMPLE_S16BE: return "Signed 16 Bit PCM, big endian."_L1;
+ case PA_SAMPLE_FLOAT32LE: return "32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0"_L1;
+ case PA_SAMPLE_FLOAT32BE: return "32 Bit IEEE floating point, big endian, range -1.0 to 1.0"_L1;
+ case PA_SAMPLE_S32LE: return "Signed 32 Bit PCM, little endian (PC)."_L1;
+ case PA_SAMPLE_S32BE: return "Signed 32 Bit PCM, big endian."_L1;
+ case PA_SAMPLE_S24LE: return "Signed 24 Bit PCM packed, little endian (PC)."_L1;
+ case PA_SAMPLE_S24BE: return "Signed 24 Bit PCM packed, big endian."_L1;
+ case PA_SAMPLE_S24_32LE: return "Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC)."_L1;
+ case PA_SAMPLE_S24_32BE: return "Signed 24 Bit PCM in LSB of 32 Bit words, big endian."_L1;
+ case PA_SAMPLE_MAX: return "Upper limit of valid sample types."_L1;
+ case PA_SAMPLE_INVALID: return "Invalid sample format"_L1;
+ default: Q_UNREACHABLE_RETURN("Unknown sample format"_L1);
+ }
+}
+
+static QLatin1StringView stateToQStringView(pa_context_state_t state)
+{
+ using namespace Qt::StringLiterals;
+ switch (state)
+ {
+ case PA_CONTEXT_UNCONNECTED: return "Unconnected"_L1;
+ case PA_CONTEXT_CONNECTING: return "Connecting"_L1;
+ case PA_CONTEXT_AUTHORIZING: return "Authorizing"_L1;
+ case PA_CONTEXT_SETTING_NAME: return "Setting Name"_L1;
+ case PA_CONTEXT_READY: return "Ready"_L1;
+ case PA_CONTEXT_FAILED: return "Failed"_L1;
+ case PA_CONTEXT_TERMINATED: return "Terminated"_L1;
+ default: Q_UNREACHABLE_RETURN("Unknown context state"_L1);
+ }
+}
+
+
+QDebug operator<<(QDebug dbg, pa_stream_state_t state)
+{
+ return dbg << stateToQStringView(state);
+}
+
+QDebug operator<<(QDebug dbg, pa_sample_format format)
+{
+ return dbg << sampleFormatToQStringView(format);
+}
+
+QDebug operator<<(QDebug dbg, pa_context_state_t state)
+{
+ return dbg << stateToQStringView(state);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/pulseaudio/qpulsehelpers_p.h b/src/multimedia/pulseaudio/qpulsehelpers_p.h
new file mode 100644
index 000000000..d271fde48
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulsehelpers_p.h
@@ -0,0 +1,55 @@
+// 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 QPULSEHELPER_H
+#define QPULSEHELPER_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 "qaudiodevice.h"
+#include <qaudioformat.h>
+#include <pulse/pulseaudio.h>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(qLcPulseAudioOut)
+Q_DECLARE_LOGGING_CATEGORY(qLcPulseAudioIn)
+Q_DECLARE_LOGGING_CATEGORY(qLcPulseAudioEngine)
+
+struct PAOperationDeleter
+{
+ void operator()(pa_operation *op) const { pa_operation_unref(op); }
+};
+
+using PAOperationUPtr = std::unique_ptr<pa_operation, PAOperationDeleter>;
+
+namespace QPulseAudioInternal
+{
+pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format);
+QAudioFormat sampleSpecToAudioFormat(const pa_sample_spec &spec);
+pa_channel_map channelMapForAudioFormat(const QAudioFormat &format);
+QAudioFormat::ChannelConfig channelConfigFromMap(const pa_channel_map &map);
+
+QUtf8StringView currentError(const pa_context *);
+QUtf8StringView currentError(const pa_stream *);
+
+} // namespace QPulseAudioInternal
+
+QDebug operator<<(QDebug, pa_stream_state_t);
+QDebug operator<<(QDebug, pa_sample_format);
+QDebug operator<<(QDebug, pa_context_state_t);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/qerrorinfo_p.h b/src/multimedia/qerrorinfo_p.h
new file mode 100644
index 000000000..6428cb00f
--- /dev/null
+++ b/src/multimedia/qerrorinfo_p.h
@@ -0,0 +1,57 @@
+// 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 QERRORINFO_P_H
+#define QERRORINFO_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>
+#include <QString>
+
+QT_BEGIN_NAMESPACE
+
+template <typename ErrorCode, ErrorCode NoError = ErrorCode::NoError>
+class QErrorInfo
+{
+public:
+ QErrorInfo(ErrorCode error = NoError, QString description = {})
+ : m_code(error), m_description(std::move(description))
+ {
+ }
+
+ template <typename Notifier>
+ void setAndNotify(ErrorCode code, QString description, Notifier &notifier)
+ {
+ const bool changed = code != m_code || description != m_description;
+
+ m_code = code;
+ m_description = std::move(description);
+
+ if (code != NoError)
+ emit notifier.errorOccurred(m_code, m_description);
+
+ if (changed)
+ emit notifier.errorChanged();
+ }
+
+ ErrorCode code() const { return m_code; }
+ QString description() const { return m_description; };
+
+private:
+ ErrorCode m_code;
+ QString m_description;
+};
+
+QT_END_NAMESPACE
+
+#endif // QERRORINFO_P_H
diff --git a/src/multimedia/qmaybe_p.h b/src/multimedia/qmaybe_p.h
new file mode 100644
index 000000000..5fe2d4d6c
--- /dev/null
+++ b/src/multimedia/qmaybe_p.h
@@ -0,0 +1,96 @@
+// 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 QMAYBE_P_H
+#define QMAYBE_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/private/qglobal_p.h>
+#include <qstring.h>
+#include <optional>
+#include <utility>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+struct QUnexpect
+{
+};
+
+static constexpr QUnexpect unexpect{};
+
+template <typename Value, typename Error = QString>
+class QMaybe
+{
+public:
+ QMaybe(const Value &v)
+ {
+ if constexpr (std::is_pointer_v<Value>) {
+ if (!v)
+ return; // nullptr is treated as nullopt (for raw pointer types only)
+ }
+ m_value = v;
+ }
+
+ QMaybe(Value &&v)
+ {
+ if constexpr (std::is_pointer_v<Value>) {
+ if (!v)
+ return; // nullptr is treated as nullopt (for raw pointer types only)
+ }
+ m_value = std::move(v);
+ }
+
+ QMaybe(const QMaybe &other) = default;
+
+ QMaybe &operator=(const QMaybe &other) = default;
+
+ QMaybe(const Error &error) : m_error(error) { }
+
+ template <class... Args>
+ QMaybe(QUnexpect, Args &&...args) : m_error{ std::forward<Args>(args)... }
+ {
+ static_assert(std::is_constructible_v<Error, Args &&...>,
+ "Invalid arguments for creating an error type");
+ }
+
+ constexpr explicit operator bool() const noexcept { return m_value.has_value(); }
+
+ constexpr Value &value()
+ {
+ Q_ASSERT(m_value.has_value());
+ return *m_value;
+ }
+
+ constexpr const Value &value() const
+ {
+ Q_ASSERT(m_value.has_value());
+ return *m_value;
+ }
+
+ constexpr Value *operator->() noexcept { return std::addressof(value()); }
+ constexpr const Value *operator->() const noexcept { return std::addressof(value()); }
+
+ constexpr Value &operator*() &noexcept { return value(); }
+ constexpr const Value &operator*() const &noexcept { return value(); }
+
+ constexpr const Error &error() const { return m_error; }
+
+private:
+ std::optional<Value> m_value;
+ Error m_error;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMAYBE_P_H
diff --git a/src/multimedia/qmediadevices.cpp b/src/multimedia/qmediadevices.cpp
index 81536b276..1d77f4de8 100644
--- a/src/multimedia/qmediadevices.cpp
+++ b/src/multimedia/qmediadevices.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qmediadevices.h"
#include "private/qplatformmediaintegration_p.h"
@@ -53,16 +17,38 @@ QT_BEGIN_NAMESPACE
\ingroup multimedia
\inmodule QtMultimedia
- The QMediaDevices class helps in managing the available multimedia
- input and output devices. It manages three types of devices:
+ The QMediaDevices class provides information about the available multimedia
+ devices and the system defaults. It monitors the following three groups:
\list
\li Audio input devices (Microphones)
\li Audio output devices (Speakers, Headsets)
\li Video input devices (Cameras)
\endlist
- QMediaDevices allows listing all available devices and will emit
- signals when the list of available devices has changed.
+ QMediaDevices provides a separate list for each device group. If it detects that a
+ new device has been connected to the system or an attached device has been disconnected
+ from the system, it will update the corresponding device list and emit a signal
+ notifying about the change.
+
+ The QMediaDevices::audioInputs and QMediaDevices::audioOutputs functions can be used
+ to enumerate all microphones and speakers/headsets on the system. This example first
+ gets a list of all connected microphones, and then prints their identifier, description,
+ and if it is the default device or not.
+
+ \snippet multimedia-snippets/devices.cpp Media Audio Input Device Enumeration
+
+ Similarly, the QMediaDevices::videoInputs will return a list of all connected cameras.
+ In this example we list all connected cameras and their identifier, description, and
+ if it is the default camera or not.
+
+ \snippet multimedia-snippets/devices.cpp Media Video Input Device Enumeration
+
+ QMediaDevices monitors the system defaults for each device group. It will notify about
+ any changes done through the system settings. For example, if the user selects a new
+ default audio output in the system settings, QMediaDevices will update the default audio
+ output accordingly and emit a signal. If the system does not provide a default for a
+ camera or an audio input, QMediaDevices will select the first device from the list as
+ the default device.
While using the default input and output devices is often sufficient for
playing back or recording multimedia, there is often a need to explicitly
@@ -72,36 +58,125 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \qmltype MediaDevices
+ \since 6.2
+ \instantiates QMediaDevices
+ \brief MediaDevices provides information about available
+ multimedia input and output devices.
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+
+ The MediaDevices type provides information about the available multimedia
+ devices and the system defaults. It monitors the following three groups:
+ \list
+ \li Audio input devices (Microphones)
+ \li Audio output devices (Speakers, Headsets)
+ \li Video input devices (Cameras)
+ \endlist
+
+ MediaDevices provides a separate list for each device group. If it detects that a
+ new device has been connected to the system or an attached device has been disconnected
+ from the system, it will update the corresponding device list and emit a signal
+ notifying about the change.
+
+ MediaDevices monitors the system defaults for each device group. It will notify about
+ any changes done through the system settings. For example, if the user selects a new
+ default audio output in the system settings, MediaDevices will update the default audio
+ output accordingly and emit a signal. If the system does not provide a default for a
+ camera or an audio input, MediaDevices will select the first device from the list as
+ the default device.
+
+ While using the default input and output devices is often sufficient for
+ playing back or recording multimedia, there is often a need to explicitly
+ select the device to be used.
+
+ For example, the snippet below will ensure that the media player always uses
+ the systems default audio output device for playback:
+
+ \qml
+ MediaDevices {
+ id: devices
+ }
+ MediaPlayer {
+ ...
+ audioOutput: AudioOutput {
+ device: devices.defaultAudioOutput
+ }
+ }
+ \endqml
+
+ \sa Camera, AudioInput, VideoOutput
+*/
+
+/*!
+ \qmlproperty list<audioDevice> QtMultimedia::MediaDevices::audioInputs
+ Contains a list of available audio input devices on the system.
+
+ Those devices are usually microphones. Devices can be either built-in, or
+ connected through for example USB or Bluetooth.
+*/
+
+/*!
+ \property QMediaDevices::audioInputs
+
Returns a list of available audio input devices on the system.
- Those devices are usually microphones. Devices are either built-in, or
- connected to the device through USB or Bluetooth.
+ Those devices are usually microphones. Devices can be either built-in, or
+ connected through for example USB or Bluetooth.
*/
QList<QAudioDevice> QMediaDevices::audioInputs()
{
- return QPlatformMediaIntegration::instance()->devices()->audioInputs();
+ return QPlatformMediaIntegration::instance()->mediaDevices()->audioInputs();
}
/*!
+ \qmlproperty list<audioDevice> QtMultimedia::MediaDevices::audioOutputs
+ Contains a list of available audio output devices on the system.
+
+ Those devices are usually loudspeakers or head sets. Devices can be either
+ built-in, or connected through for example USB or Bluetooth.
+*/
+
+/*!
+ \property QMediaDevices::audioOutputs
+
Returns a list of available audio output devices on the system.
- Those devices are usually loudspeakers or head sets. Devices are either
- built-in, or connected to the device through USB or Bluetooth.
+ Those devices are usually loudspeakers or head sets. Devices can be either
+ built-in, or connected through for example USB or Bluetooth.
*/
QList<QAudioDevice> QMediaDevices::audioOutputs()
{
- return QPlatformMediaIntegration::instance()->devices()->audioOutputs();
+ return QPlatformMediaIntegration::instance()->mediaDevices()->audioOutputs();
}
/*!
+ \qmlproperty list<cameraDevice> QtMultimedia::MediaDevices::videoInputs
+ Contains a list of cameras on the system.
+*/
+
+/*!
+ \property QMediaDevices::videoInputs
+
Returns a list of available cameras on the system.
*/
QList<QCameraDevice> QMediaDevices::videoInputs()
{
- return QPlatformMediaIntegration::instance()->devices()->videoInputs();
+ QPlatformMediaIntegration::instance()->mediaDevices()->initVideoDevicesConnection();
+ return QPlatformMediaIntegration::instance()->videoInputs();
}
/*!
+ \qmlproperty audioDevice QtMultimedia::MediaDevices::defaultAudioInput
+ Returns the default audio input device.
+
+ The default device can change during the runtime of the application. The value
+ of this property will automatically adjust itself to such changes.
+*/
+
+/*!
+ \property QMediaDevices::defaultAudioInput
+
Returns the default audio input device.
The default device can change during the runtime of the application.
@@ -110,6 +185,8 @@ QList<QCameraDevice> QMediaDevices::videoInputs()
QAudioDevice QMediaDevices::defaultAudioInput()
{
const auto inputs = audioInputs();
+ if (inputs.isEmpty())
+ return {};
for (const auto &info : inputs)
if (info.isDefault())
return info;
@@ -117,6 +194,16 @@ QAudioDevice QMediaDevices::defaultAudioInput()
}
/*!
+ \qmlproperty audioDevice QtMultimedia::MediaDevices::defaultAudioOutput
+ Returns the default audio output device.
+
+ The default device can change during the runtime of the application. The value
+ of this property will automatically adjust itself to such changes.
+*/
+
+/*!
+ \property QMediaDevices::defaultAudioOutput
+
Returns the default audio output device.
The default device can change during the runtime of the application. The
@@ -125,6 +212,8 @@ QAudioDevice QMediaDevices::defaultAudioInput()
QAudioDevice QMediaDevices::defaultAudioOutput()
{
const auto outputs = audioOutputs();
+ if (outputs.isEmpty())
+ return {};
for (const auto &info : outputs)
if (info.isDefault())
return info;
@@ -132,9 +221,22 @@ QAudioDevice QMediaDevices::defaultAudioOutput()
}
/*!
+ \qmlproperty cameraDevice QtMultimedia::MediaDevices::defaultVideoInput
Returns the default camera on the system.
- /note The returned object should be checked using isNull() before being used,
+ \note The returned object should be checked using isNull() before being used,
+ in case there is no camera available.
+
+ The default device can change during the runtime of the application. The value
+ of this property will automatically adjust itself to such changes.
+*/
+
+/*!
+ \property QMediaDevices::defaultVideoInput
+
+ Returns the default camera on the system.
+
+ \note The returned object should be checked using isNull() before being used,
in case there is no default camera or no cameras at all.
The default device can change during the runtime of the application. The
@@ -145,6 +247,8 @@ QAudioDevice QMediaDevices::defaultAudioOutput()
QCameraDevice QMediaDevices::defaultVideoInput()
{
const auto inputs = videoInputs();
+ if (inputs.isEmpty())
+ return {};
for (const auto &info : inputs)
if (info.isDefault())
return info;
@@ -157,17 +261,27 @@ QCameraDevice QMediaDevices::defaultVideoInput()
QMediaDevices::QMediaDevices(QObject *parent)
: QObject(parent)
{
- QPlatformMediaIntegration::instance()->devices()->addDevices(this);
+ auto platformDevices = QPlatformMediaIntegration::instance()->mediaDevices();
+ connect(platformDevices, &QPlatformMediaDevices::videoInputsChanged, this,
+ &QMediaDevices::videoInputsChanged);
+ connect(platformDevices, &QPlatformMediaDevices::audioInputsChanged, this,
+ &QMediaDevices::audioInputsChanged);
+ connect(platformDevices, &QPlatformMediaDevices::audioOutputsChanged, this,
+ &QMediaDevices::audioOutputsChanged);
}
/*!
\internal
*/
-QMediaDevices::~QMediaDevices()
+QMediaDevices::~QMediaDevices() = default;
+
+void QMediaDevices::connectNotify(const QMetaMethod &signal)
{
- QPlatformMediaIntegration::instance()->devices()->removeDevices(this);
-}
+ if (signal == QMetaMethod::fromSignal(&QMediaDevices::videoInputsChanged))
+ QPlatformMediaIntegration::instance()->mediaDevices()->initVideoDevicesConnection();
+ QObject::connectNotify(signal);
+}
QT_END_NAMESPACE
diff --git a/src/multimedia/qmediadevices.h b/src/multimedia/qmediadevices.h
index ee69a3da8..832799095 100644
--- a/src/multimedia/qmediadevices.h
+++ b/src/multimedia/qmediadevices.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEDIADEVICES_H
#define QMEDIADEVICES_H
@@ -78,6 +42,9 @@ Q_SIGNALS:
void audioOutputsChanged();
void videoInputsChanged();
+protected:
+ void connectNotify(const QMetaMethod &signal) override;
+
private:
friend class QMediaDevicesPrivate;
};
diff --git a/src/multimedia/qmediaenumdebug.h b/src/multimedia/qmediaenumdebug.h
index 6fc151bbf..e9efb0983 100644
--- a/src/multimedia/qmediaenumdebug.h
+++ b/src/multimedia/qmediaenumdebug.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEDIAENUMDEBUG_H
#define QMEDIAENUMDEBUG_H
diff --git a/src/multimedia/qmediaformat.cpp b/src/multimedia/qmediaformat.cpp
index e464195bb..a05648636 100644
--- a/src/multimedia/qmediaformat.cpp
+++ b/src/multimedia/qmediaformat.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmediaformat.h"
#include "private/qplatformmediaintegration_p.h"
@@ -43,6 +7,7 @@
#include <QtCore/qmimedatabase.h>
QT_BEGIN_NAMESPACE
+
/*!
\class QMediaFormat
\ingroup multimedia
@@ -55,6 +20,43 @@ QT_BEGIN_NAMESPACE
You can check whether a certain media format can be used for encoding
or decoding using QMediaFormat.
*/
+
+/*!
+ \qmlvaluetype mediaFormat
+ \ingroup qmlvaluetypes
+ \since 6.2
+ //! \instantiates QMediaFormat
+ \brief MediaFormat describes the format of a media file.
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+
+ The MediaFormat type describes the format of a media file. It contains
+ three properties that describe the file type and the audio and video codecs
+ that are being used.
+
+ MediaFormat can be used to specify the type of file that should be created
+ by a MediaRecorder. The snippet below shows an example that sets up the
+ recorder to create an mpeg4 video with AAC encoded audio and H265 video:
+
+ \qml
+ CaptureSession {
+ ... // setup inputs
+ MediaRecorder {
+ mediaFormat {
+ fileFormat: MediaFormat.MPEG4
+ audioCodec: MediaFormat.AudioCodec.AAC
+ videoCodec: MediaFormat.VideoCodec.H265
+ }
+ }
+ }
+ \endqml
+
+ If the specified mediaFormat is not supported, the MediaRecorder will automatically try
+ to find the best possible replacement format and use that instead.
+
+ \sa MediaRecorder, CaptureSession
+*/
+
namespace {
const char *mimeTypeForFormat[QMediaFormat::LastFileFormat + 2] =
@@ -71,9 +73,9 @@ const char *mimeTypeForFormat[QMediaFormat::LastFileFormat + 2] =
"audio/mp4",
"audio/aac",
"audio/x-ms-wma",
- "audio/flac",
"audio/mpeg",
- "audio/wav",
+ "audio/flac",
+ "audio/wav"
};
constexpr QMediaFormat::FileFormat videoFormatPriorityList[] =
@@ -141,8 +143,6 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QMediaFormatPrivate);
\value WMA
\l {Windows Media Audio}
- \value UnspecifiedFormat
- The format is unspecified.
\value AAC
\l{Advanced Audio Coding}
\value Matroska
@@ -167,10 +167,51 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QMediaFormatPrivate);
\l{MPEG-4 Part 3 or MPEG-4 Audio (formally ISO/IEC 14496-3)}
\value FLAC
\l{Free Lossless Audio Codec}
+ \value UnspecifiedFormat
+ The format is unspecified.
\omitvalue LastFileFormat
*/
+/*! \qmlproperty enumeration QtMultimedia::mediaFormat::fileFormat
+
+ Describes the container format used in a multimedia file or stream.
+ It can take one of the following values:
+
+ \table
+ \header \li Property value
+ \li Description
+ \row \li MediaFormat.WMA
+ \li \l{Windows Media Audio}
+ \row \li MediaFormat.AAC
+ \li \l{Advanced Audio Coding}
+ \row \li MediaFormat.Matroska
+ \li \l{Matroska (MKV)}
+ \row \li MediaFormat.WMV
+ \li \l{Windows Media Video}
+ \row \li MediaFormat.MP3
+ \li \l{MPEG-1 Audio Layer III or MPEG-2 Audio Layer III}
+ \row \li MediaFormat.Wave
+ \li \l{Waveform Audio File Format}
+ \row \li MediaFormat.Ogg
+ \li \l{Ogg}
+ \row \li MediaFormat.MPEG4
+ \li \l{MPEG-4}
+ \row \li MediaFormat.AVI
+ \li \l{Audio Video Interleave}
+ \row \li MediaFormat.QuickTime
+ \li \l{QuickTime}
+ \row \li MediaFormat.WebM
+ \li \l{WebM}
+ \row \li MediaFormat.Mpeg4Audio
+ \li \l{MPEG-4 Part 3 or MPEG-4 Audio (formally ISO/IEC 14496-3)}
+ \row \li MediaFormat.FLAC
+ \li \l{Free Lossless Audio Codec}
+ \row \li MediaFormat.UnspecifiedFormat
+ \li The format is unspecified.
+ \endtable
+*/
+
/*! \enum QMediaFormat::AudioCodec
Describes the audio codec used in multimedia file or stream.
@@ -203,6 +244,41 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QMediaFormatPrivate);
\omitvalue LastAudioCodec
*/
+/*! \qmlproperty enumeration QtMultimedia::mediaFormat::audioCodec
+
+ Describes the audio codec used in multimedia file or stream.
+ It can take one of the following values:
+
+ \table
+ \header \li Property value
+ \li Description
+ \row \li MediaFormat.WMA
+ \li \l {Windows Media Audio}
+ \row \li MediaFormat.AC3
+ \li \l {Dolby Digital}
+ \row \li MediaFormat.AAC
+ \li \l{Advanced Audio Coding}
+ \row \li MediaFormat.ALAC
+ \li \l{Apple Lossless Audio Codec}
+ \row \li MediaFormat.DolbyTrueHD
+ \li \l{Dolby TrueHD}
+ \row \li MediaFormat.EAC3
+ \li \l {Dolby Digital Plus (EAC3)}
+ \row \li MediaFormat.MP3
+ \li \l{MPEG-1 Audio Layer III or MPEG-2 Audio Layer III}
+ \row \li MediaFormat.Wave
+ \li \l{Waveform Audio File Format}
+ \row \li MediaFormat.Vorbis
+ \li \l{Ogg Vorbis}
+ \row \li MediaFormat.FLAC
+ \li \l{Free Lossless Audio Codec}
+ \row \li MediaFormat.Opus
+ \li \l{Opus Audio Format}
+ \row \li MediaFormat.Unspecified
+ \li Unspecified codec
+ \endtable
+*/
+
/*! \enum QMediaFormat::VideoCodec
Describes the video coded used in multimedia file or stream.
@@ -227,14 +303,49 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QMediaFormatPrivate);
\l{MotionJPEG}
\value VP9
\l{VP9}
- \value Unspecified
- Video codec not specified
\value Theora
\l{Theora}
+ \value Unspecified
+ Video codec not specified
\omitvalue LastVideoCodec
*/
+/*! \qmlproperty enumeration QtMultimedia::mediaFormat::videoCodec
+
+ Describes the video codec used in multimedia file or stream.
+ It can take one of the following values:
+
+ \table
+ \header \li Property value
+ \li Description
+ \row \li MediaFormat.VP8
+ \li \l{VP8}
+ \row \li MediaFormat.MPEG2
+ \li \l{MPEG-2}
+ \row \li MediaFormat.MPEG1
+ \li \l{MPEG-1}
+ \row \li MediaFormat.WMV
+ \li \l{Windows Media Video}
+ \row \li MediaFormat.H265
+ \li \l{High Efficiency Video Coding (HEVC)}
+ \row \li MediaFormat.H264
+ \li \l{Advanced Video Coding}
+ \row \li MediaFormat.MPEG4
+ \li \l{MPEG-4}
+ \row \li MediaFormat.AV1
+ \li \l{AOMedia Video 1}
+ \row \li MediaFormat.MotionJPEG
+ \li \l{MotionJPEG}
+ \row \li MediaFormat.VP9
+ \li \l{VP9}
+ \row \li MediaFormat.Theora
+ \li \l{Theora}
+ \row \li MediaFormat.Unspecified
+ \li Video codec not specified
+ \endtable
+*/
+
// these are non inline to make a possible future addition of a d pointer binary compatible
/*!
@@ -256,6 +367,11 @@ QMediaFormat::~QMediaFormat() = default;
QMediaFormat::QMediaFormat(const QMediaFormat &other) noexcept = default;
/*!
+ \fn void QMediaFormat::swap(QMediaFormat &other) noexcept
+
+ Swaps the media format with \a other.
+*/
+/*!
Copies \a other into this QMediaFormat object.
*/
QMediaFormat &QMediaFormat::operator=(const QMediaFormat &other) noexcept = default;
@@ -339,13 +455,32 @@ QMimeType QMediaFormat::mimeType() const
return QMimeDatabase().mimeTypeForName(QString::fromLatin1(mimeTypeForFormat[fmt + 1]));
}
-static QPlatformMediaFormatInfo *formatInfo()
-{
- QPlatformMediaFormatInfo *result = nullptr;
- if (auto *pi = QPlatformMediaIntegration::instance())
- result = pi->formatInfo();
- return result;
-}
+/*!
+ \enum QMediaFormat::ConversionMode
+
+ In many cases, systems have asymmetric capabilities and can often decode more formats
+ or codecs than can be encoded. This enum describes the requested conversion mode to
+ be used when checking whether a certain file format or codec is supported.
+
+ \value Encode
+ Used to check whether a certain file format or codec can be encoded.
+ \value Decode
+ Used to check whether a certain file format or codec can be decoded.
+
+ \sa supportedFileFormats, supportedAudioCodecs, supportedVideoCodecs
+*/
+
+/*!
+ \qmlmethod list<FileFormat> QtMultimedia::mediaFormat::supportedFileFormats(conversionMode)
+ Returns a list of file formats for the audio and video
+ codec indicated by \a{conversionMode}.
+
+ To get all supported file formats, run this query on a default constructed MediaFormat. To
+ get a list of file formats supporting a specific combination of an audio and video codec,
+ you can set the audioCodec and videoCodec properties before running this query.
+
+ \sa QMediaFormat::ConversionMode
+*/
/*!
Returns a list of file formats for the audio and video
@@ -353,41 +488,75 @@ static QPlatformMediaFormatInfo *formatInfo()
To get all supported file formats, run this query on a default constructed
QMediaFormat.
+
+ \sa QMediaFormat::ConversionMode
*/
QList<QMediaFormat::FileFormat> QMediaFormat::supportedFileFormats(QMediaFormat::ConversionMode m)
{
- auto *fi = formatInfo();
- return fi != nullptr ? fi->supportedFileFormats(*this, m) : QList<QMediaFormat::FileFormat>{};
+ return QPlatformMediaIntegration::instance()->formatInfo()->supportedFileFormats(*this, m);
}
/*!
+ \qmlmethod list<VideoCodec> QtMultimedia::mediaFormat::supportedVideoCodecs(conversionMode)
+ Returns a list of video codecs for the chosen file format and
+ audio codec (\a conversionMode).
+
+ To get all supported video codecs, run this query on a default constructed MediaFormat. To
+ get a list of supported video codecs for a specific combination of a file format and an audio
+ codec, you can set the fileFormat and audioCodec properties before running this query.
+
+ \sa QMediaFormat::ConversionMode
+*/
+
+/*!
Returns a list of video codecs for the chosen file format and
audio codec (\a m).
To get all supported video codecs, run this query on a default constructed
- QMediaFormat.
+ MediaFormat.
+
+ \sa QMediaFormat::ConversionMode
*/
QList<QMediaFormat::VideoCodec> QMediaFormat::supportedVideoCodecs(QMediaFormat::ConversionMode m)
{
- auto *fi = formatInfo();
- return fi != nullptr ? fi->supportedVideoCodecs(*this, m) : QList<QMediaFormat::VideoCodec>{};
+ return QPlatformMediaIntegration::instance()->formatInfo()->supportedVideoCodecs(*this, m);
}
/*!
+ \qmlmethod list<AudioCodec> QtMultimedia::mediaFormat::supportedAudioFormats(conversionMode)
+ Returns a list of audio codecs for the chosen file format and
+ video codec (\a conversionMode).
+
+ To get all supported audio codecs, run this query on a default constructed MediaFormat. To get
+ a list of supported audio codecs for a specific combination of a file format and a video codec,
+ you can set the fileFormat and videoCodec properties before running this query.
+ \sa QMediaFormat::ConversionMode
+*/
+
+/*!
Returns a list of audio codecs for the chosen file format and
video codec (\a m).
To get all supported audio codecs, run this query on a default constructed
QMediaFormat.
+
+ \sa QMediaFormat::ConversionMode
*/
QList<QMediaFormat::AudioCodec> QMediaFormat::supportedAudioCodecs(QMediaFormat::ConversionMode m)
{
- auto *fi = formatInfo();
- return fi != nullptr ? fi->supportedAudioCodecs(*this, m) : QList<QMediaFormat::AudioCodec>{};
+ return QPlatformMediaIntegration::instance()->formatInfo()->supportedAudioCodecs(*this, m);
}
-QString QMediaFormat::fileFormatName(QMediaFormat::FileFormat c)
+/*!
+ \qmlmethod string QtMultimedia::mediaFormat::fileFormatName(fileFormat)
+ Returns a string based name for \a fileFormat.
+*/
+
+/*!
+ Returns a string based name for \a fileFormat.
+*/
+QString QMediaFormat::fileFormatName(QMediaFormat::FileFormat fileFormat)
{
constexpr const char *descriptions[QMediaFormat::LastFileFormat + 2] = {
"Unspecified",
@@ -406,10 +575,18 @@ QString QMediaFormat::fileFormatName(QMediaFormat::FileFormat c)
"FLAC",
"Wave"
};
- return QString::fromUtf8(descriptions[int(c) + 1]);
+ return QString::fromUtf8(descriptions[int(fileFormat) + 1]);
}
-QString QMediaFormat::audioCodecName(QMediaFormat::AudioCodec c)
+/*!
+ \qmlmethod string QtMultimedia::mediaFormat::audioCodecName(codec)
+ Returns a string based name for \a codec.
+*/
+
+/*!
+ Returns a string based name for \a codec.
+*/
+QString QMediaFormat::audioCodecName(QMediaFormat::AudioCodec codec)
{
constexpr const char *descriptions[] = {
"Invalid",
@@ -425,10 +602,18 @@ QString QMediaFormat::audioCodecName(QMediaFormat::AudioCodec c)
"WMA",
"ALAC",
};
- return QString::fromUtf8(descriptions[int(c) + 1]);
+ return QString::fromUtf8(descriptions[int(codec) + 1]);
}
-QString QMediaFormat::videoCodecName(QMediaFormat::VideoCodec c)
+/*!
+ \qmlmethod string QtMultimedia::mediaFormat::videoCodecName(codec)
+ Returns a string based name for \a codec.
+*/
+
+/*!
+ Returns a string based name for \a codec.
+*/
+QString QMediaFormat::videoCodecName(QMediaFormat::VideoCodec codec)
{
constexpr const char *descriptions[] = {
"Invalid",
@@ -444,10 +629,18 @@ QString QMediaFormat::videoCodecName(QMediaFormat::VideoCodec c)
"WMV",
"MotionJPEG"
};
- return QString::fromUtf8(descriptions[int(c) + 1]);
+ return QString::fromUtf8(descriptions[int(codec) + 1]);
}
-QString QMediaFormat::fileFormatDescription(QMediaFormat::FileFormat c)
+/*!
+ \qmlmethod string QtMultimedia::mediaFormat::fileFormatDescription(fileFormat)
+ Returns a description for \a fileFormat.
+*/
+
+/*!
+ Returns a description for \a fileFormat.
+*/
+QString QMediaFormat::fileFormatDescription(QMediaFormat::FileFormat fileFormat)
{
constexpr const char *descriptions[QMediaFormat::LastFileFormat + 2] = {
"Unspecified File Format",
@@ -466,10 +659,18 @@ QString QMediaFormat::fileFormatDescription(QMediaFormat::FileFormat c)
"Free Lossless Audio Codec (FLAC)",
"Wave File"
};
- return QString::fromUtf8(descriptions[int(c) + 1]);
+ return QString::fromUtf8(descriptions[int(fileFormat) + 1]);
}
-QString QMediaFormat::audioCodecDescription(QMediaFormat::AudioCodec c)
+/*!
+ \qmlmethod string QtMultimedia::mediaFormat::audioCodecDescription(codec)
+ Returns a description for \a codec.
+*/
+
+/*!
+ Returns a description for \a codec.
+*/
+QString QMediaFormat::audioCodecDescription(QMediaFormat::AudioCodec codec)
{
constexpr const char *descriptions[] = {
"Unspecified Audio Codec",
@@ -485,10 +686,18 @@ QString QMediaFormat::audioCodecDescription(QMediaFormat::AudioCodec c)
"Windows Media Audio",
"Apple Lossless Audio Codec (ALAC)",
};
- return QString::fromUtf8(descriptions[int(c) + 1]);
+ return QString::fromUtf8(descriptions[int(codec) + 1]);
}
-QString QMediaFormat::videoCodecDescription(QMediaFormat::VideoCodec c)
+/*!
+ \qmlmethod string QtMultimedia::mediaFormat::videoCodecDescription(codec)
+ Returns a description for \a codec.
+*/
+
+/*!
+ Returns a description for \a codec.
+*/
+QString QMediaFormat::videoCodecDescription(QMediaFormat::VideoCodec codec)
{
constexpr const char *descriptions[] = {
"Unspecified Video Codec",
@@ -504,9 +713,20 @@ QString QMediaFormat::videoCodecDescription(QMediaFormat::VideoCodec c)
"Windows Media Video",
"MotionJPEG"
};
- return QString::fromUtf8(descriptions[int(c) + 1]);
+ return QString::fromUtf8(descriptions[int(codec) + 1]);
}
+/*!
+ \fn bool QMediaFormat::operator!=(const QMediaFormat &other) const
+
+ Returns \c true if \a other is not equal to the current media format,
+ otherwise returns \c false.
+*/
+
+/*!
+ Returns \c true if \a other is equal to the current media format, otherwise
+ returns \c false.
+*/
bool QMediaFormat::operator==(const QMediaFormat &other) const
{
Q_ASSERT(!d);
@@ -642,4 +862,22 @@ void QMediaFormat::resolveForEncoding(ResolveFlags flags)
}
}
+/*!
+ \variable QMediaFormat::audio
+ \internal
+*/
+/*!
+ \variable QMediaFormat::d
+ \internal
+*/
+/*!
+ \variable QMediaFormat::video
+ \internal
+*/
+/*!
+ \variable QMediaFormat::fmt
+ \internal
+*/
QT_END_NAMESPACE
+
+#include "moc_qmediaformat.cpp"
diff --git a/src/multimedia/qmediaformat.h b/src/multimedia/qmediaformat.h
index d3631ea42..225d21896 100644
--- a/src/multimedia/qmediaformat.h
+++ b/src/multimedia/qmediaformat.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMEDIAFORMAT_H
#define QMEDIAFORMAT_H
@@ -135,10 +99,10 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QMediaFormat)
void swap(QMediaFormat &other) noexcept
{
- qSwap(fmt, other.fmt);
- qSwap(audio, other.audio);
- qSwap(video, other.video);
- qSwap(d, other.d);
+ std::swap(fmt, other.fmt);
+ std::swap(audio, other.audio);
+ std::swap(video, other.video);
+ d.swap(other.d);
}
FileFormat fileFormat() const { return fmt; }
@@ -158,13 +122,13 @@ public:
Q_INVOKABLE QList<VideoCodec> supportedVideoCodecs(ConversionMode m);
Q_INVOKABLE QList<AudioCodec> supportedAudioCodecs(ConversionMode m);
- Q_INVOKABLE static QString fileFormatName(FileFormat c);
- Q_INVOKABLE static QString audioCodecName(AudioCodec c);
- Q_INVOKABLE static QString videoCodecName(VideoCodec c);
+ Q_INVOKABLE static QString fileFormatName(FileFormat fileFormat);
+ Q_INVOKABLE static QString audioCodecName(AudioCodec codec);
+ Q_INVOKABLE static QString videoCodecName(VideoCodec codec);
- static QString fileFormatDescription(QMediaFormat::FileFormat c);
- static QString audioCodecDescription(QMediaFormat::AudioCodec c);
- static QString videoCodecDescription(QMediaFormat::VideoCodec c);
+ Q_INVOKABLE static QString fileFormatDescription(QMediaFormat::FileFormat fileFormat);
+ Q_INVOKABLE static QString audioCodecDescription(QMediaFormat::AudioCodec codec);
+ Q_INVOKABLE static QString videoCodecDescription(QMediaFormat::VideoCodec codec);
bool operator==(const QMediaFormat &other) const;
bool operator!=(const QMediaFormat &other) const
diff --git a/src/multimedia/qmediametadata.cpp b/src/multimedia/qmediametadata.cpp
index cc580b482..dc238721f 100644
--- a/src/multimedia/qmediametadata.cpp
+++ b/src/multimedia/qmediametadata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 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 "qmediametadata.h"
#include <QtCore/qcoreapplication.h>
@@ -44,6 +8,8 @@
#include <qdatetime.h>
#include <qmediaformat.h>
#include <qsize.h>
+#include <qurl.h>
+#include <qimage.h>
QT_BEGIN_NAMESPACE
@@ -64,7 +30,7 @@ QT_BEGIN_NAMESPACE
\row \li Comment \li A user comment about the media. \li QString
\row \li Description \li A description of the media. \li QString
\row \li Genre \li The genre of the media. \li QStringList
- \row \li Date \li The date of the media. \li QDate.
+ \row \li Date \li The date of the media. \li QDateTime.
\row \li Language \li The language of media. \li QLocale::Language
\row \li Publisher \li The publisher of the media. \li QString
@@ -80,7 +46,7 @@ QT_BEGIN_NAMESPACE
\header \li {3,1}
Audio attributes
\row \li AudioBitRate \li The bit rate of the media's audio stream in bits per second. \li int
- \row \li AudioCodec \li The codec of the media's audio stream. \li QMediaForma::AudioCodec
+ \row \li AudioCodec \li The codec of the media's audio stream. \li QMediaFormat::AudioCodec
\header \li {3,1}
Video attributes
@@ -97,21 +63,83 @@ QT_BEGIN_NAMESPACE
\row \li Composer \li The composer of the media. \li QStringList
\row \li LeadPerformer \li The lead performer in the media. \li QStringList
- \row \li ThumbnailImage \li An embedded thumbnail image. \li QImage
+ \row \li ThumbnailImage \li An embedded thumbnail image if present in metadata. \li QImage
\row \li CoverArtImage \li An embedded cover art image. \li QImage
\header \li {3,1}
Image and video attributes
+ \row \li Orientation \li The rotation angle of an image or video. \li int
\row \li Resolution \li The dimensions of an image or video. \li QSize
\endtable
*/
+
/*!
- \qmltype MetaData
+ Returns the meta type used to store data for Key \a key.
+*/
+QMetaType QMediaMetaData::keyType(Key key)
+{
+ switch (key) {
+ case Title:
+ case Comment:
+ case Description:
+ case Publisher:
+ case Copyright:
+ case MediaType:
+ case AlbumTitle:
+ case AlbumArtist:
+ return QMetaType::fromType<QString>();
+ case Genre:
+ case Author:
+ case ContributingArtist:
+ case Composer:
+ case LeadPerformer:
+ return QMetaType::fromType<QStringList>();
+
+ case Date:
+ return QMetaType::fromType<QDateTime>();
+
+ case Language:
+ return QMetaType::fromType<QLocale::Language>();
+ case Url:
+ return QMetaType::fromType<QUrl>();
+
+ case Duration:
+ return QMetaType::fromType<qint64>();
+ case FileFormat:
+ return QMetaType::fromType<QMediaFormat::FileFormat>();
+
+ case AudioBitRate:
+ case VideoBitRate:
+ case TrackNumber:
+ case Orientation:
+ return QMetaType::fromType<int>();
+ case AudioCodec:
+ return QMetaType::fromType<QMediaFormat::AudioCodec>();
+ case VideoCodec:
+ return QMetaType::fromType<QMediaFormat::VideoCodec>();
+ case VideoFrameRate:
+ return QMetaType::fromType<qreal>();
+
+
+ case ThumbnailImage:
+ case CoverArtImage:
+ return QMetaType::fromType<QImage>();
+
+ case Resolution:
+ return QMetaType::fromType<QSize>();
+ default:
+ return QMetaType::fromType<void>();
+ }
+}
+
+/*!
+ \qmlvaluetype mediaMetaData
+ \ingroup qmlvaluetypes
\inqmlmodule QtMultimedia
\since 6.2
- \instantiates QMediaMetaData
+ //! \instantiates QMediaMetaData
\brief Provides meta-data for media files.
\ingroup multimedia_qml
\ingroup multimedia_audio_qml
@@ -216,7 +244,47 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlmethod QVariant QtMultimedia::MetaData::value(QMediaMetaData::Key key)
+ \enum QMediaMetaData::Key
+
+ The following meta data keys can be used:
+
+ \value Title Media title
+ \value Author Media author
+ \value Comment Comment
+ \value Description Brief desripttion
+ \value Genre Genre the media belongs to
+ \value Date Creation date
+ \value Language Media language
+ \value Publisher Media publisher info.
+ \value Copyright Media copyright info.
+ \value Url Publisher's website URL
+ \value Duration Media playback duration
+ \value MediaType Type of the media
+ \value FileFormat File format
+ \value AudioBitRate
+ \value AudioCodec
+ \value VideoBitRate
+ \value VideoCodec
+ \value VideoFrameRate
+ \value AlbumTitle Album's title
+ \value AlbumArtist Artist's info.
+ \value ContributingArtist
+ \value TrackNumber
+ \value Composer Media composer's info.
+ \value LeadPerformer
+ \value ThumbnailImage Media thumbnail image (if embedded in metadata)
+ \value CoverArtImage Media cover art
+ \value Orientation
+ \value Resolution
+*/
+
+/*!
+ \variable QMediaMetaData::NumMetaData
+ \internal
+*/
+
+/*!
+ \qmlmethod variant QtMultimedia::mediaMetaData::value(Key key)
Returns the meta data value for Key \a key, or a null QVariant if no
meta-data for the key is available.
@@ -225,12 +293,12 @@ QT_BEGIN_NAMESPACE
/*!
\fn QVariant QMediaMetaData::value(QMediaMetaData::Key key) const
- Returns the meta data value for Key \a key, or a null QVariant is not
+ Returns the meta data value for Key \a key, or a null QVariant if no
meta data for the key is available.
*/
/*!
- \qmlmethod bool QtMultimedia::MetaData::isEmpty()
+ \qmlmethod bool QtMultimedia::mediaMetaData::isEmpty()
Returns \c true if the meta data contains no items: otherwise returns \c{false}.
*/
@@ -240,17 +308,17 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlmethod void QtMultimedia::MetaData::clear()
- Removes all data from the MetaData object.
+ \qmlmethod void QtMultimedia::mediaMetaData::clear()
+ Removes all data from the MediaMetaData object.
*/
/*!
\fn void QMediaMetaData::clear()
- Removes all data from the MetaData object.
+ Removes all data from the meta data object.
*/
/*!
- \qmlmethod void QtMultimedia::MetaData::insert(QMediaMetaData::Key k, const QVariant &value)
+ \qmlmethod void QtMultimedia::mediaMetaData::insert(Key k, variant value)
Inserts a \a value into a Key: \a{k}.
*/
@@ -259,7 +327,7 @@ QT_BEGIN_NAMESPACE
Inserts a \a value into a Key: \a{k}.
*/
/*!
- \qmlmethod void QtMultimedia::MetaData::remove(QMediaMetaData::Key k)
+ \qmlmethod void QtMultimedia::mediaMetaData::remove(Key k)
Removes meta data from a Key: \a{k}.
*/
@@ -269,8 +337,8 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlmethod QList QtMultimedia::MetaData::keys()
- Returns a QList of MetaData.Keys.
+ \qmlmethod list<Key> QtMultimedia::mediaMetaData::keys()
+ Returns a list of MediaMetaData.Keys.
*/
/*!
@@ -279,7 +347,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlmethod QString QtMultimedia::MetaData::stringValue(QMediaMetaData::Key key)
+ \qmlmethod string QtMultimedia::mediaMetaData::stringValue(Key key)
Returns the meta data for key \a key as a QString.
This is mainly meant to simplify presenting the meta data to a user.
@@ -334,7 +402,7 @@ QString QMediaMetaData::stringValue(QMediaMetaData::Key key) const
return QMediaFormat::videoCodecName(value.value<QMediaFormat::VideoCodec>());
case Resolution: {
QSize size = value.toSize();
- return QString::fromUtf8("%1 x %2").arg(size.width()).arg(size.height());
+ return QStringLiteral("%1 x %2").arg(size.width()).arg(size.height());
}
case ThumbnailImage:
case CoverArtImage:
@@ -343,7 +411,7 @@ QString QMediaMetaData::stringValue(QMediaMetaData::Key key) const
return QString();
}
/*!
- \qmlmethod QString QtMultimedia::MetaData::metaDataKeyToString(QMediaMetaData::Key key)
+ \qmlmethod string QtMultimedia::mediaMetaData::metaDataKeyToString(Key key)
returns a string representation of \a key that can be used when presenting
meta data to users.
*/
@@ -414,6 +482,7 @@ QString QMediaMetaData::metaDataKeyToString(QMediaMetaData::Key key)
}
return QString();
}
+
// operator documentation
/*!
\fn QVariant &QMediaMetaData ::operator[](QMediaMetaData::Key k)
@@ -443,3 +512,5 @@ QString QMediaMetaData::metaDataKeyToString(QMediaMetaData::Key key)
*/
QT_END_NAMESPACE
+
+#include "moc_qmediametadata.cpp"
diff --git a/src/multimedia/qmediametadata.h b/src/multimedia/qmediametadata.h
index f8fa23098..d6f4477d3 100644
--- a/src/multimedia/qmediametadata.h
+++ b/src/multimedia/qmediametadata.h
@@ -1,45 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEDIAMETADATA_H
#define QMEDIAMETADATA_H
+#if 0
+#pragma qt_class(QMediaMetaData)
+#endif
+
#include <QtCore/qpair.h>
#include <QtCore/qvariant.h>
#include <QtCore/qstring.h>
@@ -87,8 +55,8 @@ public:
ThumbnailImage,
CoverArtImage,
- Orientation,
+ Orientation,
Resolution
};
Q_ENUM(Key)
@@ -115,6 +83,8 @@ protected:
friend bool operator!=(const QMediaMetaData &a, const QMediaMetaData &b)
{ return a.data != b.data; }
+ static QMetaType keyType(Key key);
+
QHash<Key, QVariant> data;
};
diff --git a/src/multimedia/qmediastoragelocation.cpp b/src/multimedia/qmediastoragelocation.cpp
index 2c30562ee..61c4061f4 100644
--- a/src/multimedia/qmediastoragelocation.cpp
+++ b/src/multimedia/qmediastoragelocation.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmediastoragelocation_p.h"
#include <QStandardPaths>
+#include <QUrl>
QT_BEGIN_NAMESPACE
@@ -57,7 +22,7 @@ QDir QMediaStorageLocation::defaultDirectory(QStandardPaths::StandardLocation ty
dirCandidates << QDir::currentPath();
dirCandidates << QDir::tempPath();
- for (const QString &path : qAsConst(dirCandidates)) {
+ for (const QString &path : std::as_const(dirCandidates)) {
QDir dir(path);
if (dir.exists() && QFileInfo(path).isWritable())
return dir;
@@ -69,13 +34,13 @@ QDir QMediaStorageLocation::defaultDirectory(QStandardPaths::StandardLocation ty
static QString generateFileName(const QDir &dir, const QString &prefix, const QString &extension)
{
auto lastMediaIndex = 0;
- const auto list = dir.entryList({ QString::fromLatin1("%1*.%2").arg(prefix, extension) });
+ const auto list = dir.entryList({ QStringLiteral("%1*.%2").arg(prefix, extension) });
for (const QString &fileName : list) {
- auto mediaIndex = QStringView{fileName}.mid(prefix.length(), fileName.size() - prefix.length() - extension.length() - 1).toInt();
+ auto mediaIndex = QStringView{fileName}.mid(prefix.size(), fileName.size() - prefix.size() - extension.size() - 1).toInt();
lastMediaIndex = qMax(lastMediaIndex, mediaIndex);
}
- const QString name = QString::fromLatin1("%1%2.%3")
+ const QString name = QStringLiteral("%1%2.%3")
.arg(prefix)
.arg(lastMediaIndex + 1, 4, 10, QLatin1Char('0'))
.arg(extension);
@@ -88,11 +53,16 @@ QString QMediaStorageLocation::generateFileName(const QString &requestedName,
QStandardPaths::StandardLocation type,
const QString &extension)
{
- auto prefix = QLatin1String("clip_");
+ using namespace Qt::StringLiterals;
+
+ if (QUrl(requestedName).scheme() == "content"_L1)
+ return requestedName;
+
+ auto prefix = "clip_"_L1;
switch (type) {
- case QStandardPaths::PicturesLocation: prefix = QLatin1String("image_"); break;
- case QStandardPaths::MoviesLocation: prefix = QLatin1String("video_"); break;
- case QStandardPaths::MusicLocation: prefix = QLatin1String("record_"); break;
+ case QStandardPaths::PicturesLocation: prefix = "image_"_L1; break;
+ case QStandardPaths::MoviesLocation: prefix = "video_"_L1; break;
+ case QStandardPaths::MusicLocation: prefix = "record_"_L1; break;
default: break;
}
@@ -101,14 +71,14 @@ QString QMediaStorageLocation::generateFileName(const QString &requestedName,
QString path = requestedName;
- if (QFileInfo(path).isRelative())
+ if (QFileInfo(path).isRelative() && QUrl(path).isRelative())
path = defaultDirectory(type).absoluteFilePath(path);
if (QFileInfo(path).isDir())
return generateFileName(QDir(path), prefix, extension);
if (!path.endsWith(extension))
- path.append(QString(QLatin1String(".%1")).arg(extension));
+ path.append(QStringLiteral(".%1").arg(extension));
return path;
}
diff --git a/src/multimedia/qmediastoragelocation_p.h b/src/multimedia/qmediastoragelocation_p.h
index ec32cfdbe..39c4b7162 100644
--- a/src/multimedia/qmediastoragelocation_p.h
+++ b/src/multimedia/qmediastoragelocation_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 QMEDIASTORAGELOCATION_H
#define QMEDIASTORAGELOCATION_H
@@ -54,13 +18,14 @@
#include <qtmultimediaglobal.h>
#include <QStandardPaths>
#include <QDir>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
namespace QMediaStorageLocation
{
- QDir defaultDirectory(QStandardPaths::StandardLocation type);
- QString generateFileName(const QString &requestedName, QStandardPaths::StandardLocation type, const QString &extension);
+ Q_MULTIMEDIA_EXPORT QDir defaultDirectory(QStandardPaths::StandardLocation type);
+ Q_MULTIMEDIA_EXPORT QString generateFileName(const QString &requestedName, QStandardPaths::StandardLocation type, const QString &extension);
};
QT_END_NAMESPACE
diff --git a/src/multimedia/qmediatimerange.cpp b/src/multimedia/qmediatimerange.cpp
index 80ab5d928..2af9cefc6 100644
--- a/src/multimedia/qmediatimerange.cpp
+++ b/src/multimedia/qmediatimerange.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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/qdebug.h>
@@ -166,7 +130,7 @@ void QMediaTimeRangePrivate::addInterval(const QMediaTimeRange::Interval &interv
// Find a place to insert the interval
int i;
- for (i = 0; i < intervals.count(); i++) {
+ for (i = 0; i < intervals.size(); i++) {
// Insert before this element
if(interval.s < intervals[i].s) {
intervals.insert(i, interval);
@@ -175,7 +139,7 @@ void QMediaTimeRangePrivate::addInterval(const QMediaTimeRange::Interval &interv
}
// Interval needs to be added to the end of the list
- if (i == intervals.count())
+ if (i == intervals.size())
intervals.append(interval);
// Do we need to correct the element before us?
@@ -183,7 +147,7 @@ void QMediaTimeRangePrivate::addInterval(const QMediaTimeRange::Interval &interv
i--;
// Merge trailing ranges
- while (i < intervals.count() - 1
+ while (i < intervals.size() - 1
&& intervals[i].e >= intervals[i + 1].s - 1) {
intervals[i].e = qMax(intervals[i].e, intervals[i + 1].e);
intervals.removeAt(i + 1);
@@ -196,7 +160,7 @@ void QMediaTimeRangePrivate::removeInterval(const QMediaTimeRange::Interval &int
if (!interval.isNormal())
return;
- for (int i = 0; i < intervals.count(); i++) {
+ for (int i = 0; i < intervals.size(); i++) {
const QMediaTimeRange::Interval r = intervals.at(i);
if (r.e < interval.s) {
@@ -296,6 +260,12 @@ QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) noexcept = defaul
*/
/*!
+ \fn void QMediaTimeRange::swap(QMediaTimeRange &other) noexcept
+
+ Swaps the current instance with the \a other.
+*/
+
+/*!
\fn QMediaTimeRange::~QMediaTimeRange()
Destructor.
@@ -347,7 +317,7 @@ qint64 QMediaTimeRange::earliestTime() const
qint64 QMediaTimeRange::latestTime() const
{
if (!d->intervals.isEmpty())
- return d->intervals[d->intervals.count() - 1].end();
+ return d->intervals[d->intervals.size() - 1].end();
return 0;
}
@@ -536,7 +506,7 @@ bool QMediaTimeRange::isEmpty() const
*/
bool QMediaTimeRange::isContinuous() const
{
- return (d->intervals.count() <= 1);
+ return (d->intervals.size() <= 1);
}
/*!
@@ -546,7 +516,7 @@ bool QMediaTimeRange::isContinuous() const
*/
bool QMediaTimeRange::contains(qint64 time) const
{
- for (int i = 0; i < d->intervals.count(); i++) {
+ for (int i = 0; i < d->intervals.size(); i++) {
if (d->intervals[i].contains(time))
return true;
diff --git a/src/multimedia/qmediatimerange.h b/src/multimedia/qmediatimerange.h
index 2a8e948c3..7245a845a 100644
--- a/src/multimedia/qmediatimerange.h
+++ b/src/multimedia/qmediatimerange.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEDIATIMERANGE_H
#define QMEDIATIMERANGE_H
@@ -107,7 +71,7 @@ public:
QMediaTimeRange(QMediaTimeRange &&other) noexcept = default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QMediaTimeRange)
void swap(QMediaTimeRange &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
void detach();
QMediaTimeRange &operator=(const Interval&);
diff --git a/src/multimedia/qmultimediautils.cpp b/src/multimedia/qmultimediautils.cpp
index 54653751b..9740b6d60 100644
--- a/src/multimedia/qmultimediautils.cpp
+++ b/src/multimedia/qmultimediautils.cpp
@@ -1,50 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qmultimediautils_p.h"
+#include "qvideoframe.h"
+#include "qvideoframeformat.h"
+
+#include <QtCore/qdir.h>
QT_BEGIN_NAMESPACE
-void qt_real_to_fraction(qreal value, int *numerator, int *denominator)
+Fraction qRealToFraction(qreal value)
{
- if (!numerator || !denominator)
- return;
+ int integral = int(floor(value));
+ value -= qreal(integral);
+ if (value == 0.)
+ return {integral, 1};
const int dMax = 1000;
int n1 = 0, d1 = 1, n2 = 1, d2 = 1;
@@ -53,19 +23,7 @@ void qt_real_to_fraction(qreal value, int *numerator, int *denominator)
mid = qreal(n1 + n2) / (d1 + d2);
if (qAbs(value - mid) < 0.000001) {
- if (d1 + d2 <= dMax) {
- *numerator = n1 + n2;
- *denominator = d1 + d2;
- return;
- } else if (d2 > d1) {
- *numerator = n2;
- *denominator = d2;
- return;
- } else {
- *numerator = n1;
- *denominator = d1;
- return;
- }
+ break;
} else if (value > mid) {
n1 = n1 + n2;
d1 = d1 + d2;
@@ -75,13 +33,68 @@ void qt_real_to_fraction(qreal value, int *numerator, int *denominator)
}
}
- if (d1 > dMax) {
- *numerator = n2;
- *denominator = d2;
- } else {
- *numerator = n1;
- *denominator = d1;
- }
+ if (d1 + d2 <= dMax)
+ return {n1 + n2 + integral * (d1 + d2), d1 + d2};
+ else if (d2 < d1)
+ return { n2 + integral * d2, d2 };
+ else
+ return { n1 + integral * d1, d1 };
+}
+
+QSize qCalculateFrameSize(QSize resolution, Fraction par)
+{
+ if (par.numerator == par.denominator || par.numerator < 1 || par.denominator < 1)
+ return resolution;
+
+ if (par.numerator > par.denominator)
+ return { resolution.width() * par.numerator / par.denominator, resolution.height() };
+
+ return { resolution.width(), resolution.height() * par.denominator / par.numerator };
+}
+
+QSize qRotatedFrameSize(QSize size, int rotation)
+{
+ Q_ASSERT(rotation % 90 == 0);
+ return rotation % 180 ? size.transposed() : size;
+}
+
+QSize qRotatedFrameSize(const QVideoFrame &frame)
+{
+ return qRotatedFrameSize(frame.size(), frame.rotation());
+}
+
+QUrl qMediaFromUserInput(QUrl url)
+{
+ using namespace Qt::Literals;
+ if (url.scheme().isEmpty() || url.scheme() == "file"_L1)
+ url = QUrl::fromUserInput(url.toString(), QDir::currentPath(), QUrl::AssumeLocalFile);
+ return url;
+}
+
+bool qIsAutoHdrEnabled()
+{
+ static const bool autoHdrEnabled = qEnvironmentVariableIntValue("QT_MEDIA_AUTO_HDR");
+
+ return autoHdrEnabled;
+}
+
+QRhiSwapChain::Format qGetRequiredSwapChainFormat(const QVideoFrameFormat &format)
+{
+ constexpr auto sdrMaxLuminance = 100.0f;
+ const auto formatMaxLuminance = format.maxLuminance();
+
+ return formatMaxLuminance > sdrMaxLuminance ? QRhiSwapChain::HDRExtendedSrgbLinear
+ : QRhiSwapChain::SDR;
+}
+
+bool qShouldUpdateSwapChainFormat(QRhiSwapChain *swapChain,
+ QRhiSwapChain::Format requiredSwapChainFormat)
+{
+ if (!swapChain)
+ return false;
+
+ return qIsAutoHdrEnabled() && swapChain->format() != requiredSwapChainFormat
+ && swapChain->isFormatSupported(requiredSwapChainFormat);
}
QT_END_NAMESPACE
diff --git a/src/multimedia/qmultimediautils_p.h b/src/multimedia/qmultimediautils_p.h
index c5cdbe935..a5d60e066 100644
--- a/src/multimedia/qmultimediautils_p.h
+++ b/src/multimedia/qmultimediautils_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMULTIMEDIAUTILS_P_H
#define QMULTIMEDIAUTILS_P_H
@@ -52,10 +16,48 @@
//
#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtMultimedia/qtvideo.h>
+#include <QtMultimedia/private/qmaybe_p.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qurl.h>
+#include <QtGui/rhi/qrhi.h>
QT_BEGIN_NAMESPACE
-Q_MULTIMEDIA_EXPORT void qt_real_to_fraction(qreal value, int *numerator, int *denominator);
+class QRhiSwapChain;
+class QVideoFrame;
+class QVideoFrameFormat;
+
+struct Fraction {
+ int numerator;
+ int denominator;
+};
+
+Q_MULTIMEDIA_EXPORT Fraction qRealToFraction(qreal value);
+
+Q_MULTIMEDIA_EXPORT QSize qCalculateFrameSize(QSize resolution, Fraction pixelAspectRatio);
+
+// TODO: after adding pixel aspect ratio to QVideoFrameFormat, the function should
+// consider PAR as well as rotation
+Q_MULTIMEDIA_EXPORT QSize qRotatedFrameSize(QSize size, int rotation);
+
+inline QSize qRotatedFrameSize(QSize size, QtVideo::Rotation rotation)
+{
+ return qRotatedFrameSize(size, qToUnderlying(rotation));
+}
+
+Q_MULTIMEDIA_EXPORT QSize qRotatedFrameSize(const QVideoFrame &frame);
+
+Q_MULTIMEDIA_EXPORT QUrl qMediaFromUserInput(QUrl fileName);
+
+Q_MULTIMEDIA_EXPORT bool qIsAutoHdrEnabled();
+
+Q_MULTIMEDIA_EXPORT QRhiSwapChain::Format
+qGetRequiredSwapChainFormat(const QVideoFrameFormat &format);
+
+Q_MULTIMEDIA_EXPORT bool
+qShouldUpdateSwapChainFormat(QRhiSwapChain *swapChain,
+ QRhiSwapChain::Format requiredSwapChainFormat);
QT_END_NAMESPACE
diff --git a/src/multimedia/qnx/qqnxaudiodevice.cpp b/src/multimedia/qnx/qqnxaudiodevice.cpp
new file mode 100644
index 000000000..4e1390e8b
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudiodevice.cpp
@@ -0,0 +1,85 @@
+// Copyright (C) 2016 Research In Motion
+// Copyright (C) 2021 The Qt Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqnxaudiodevice_p.h"
+
+#include "qqnxaudioutils_p.h"
+
+#include <array>
+
+#include <sys/asoundlib.h>
+
+using namespace QnxAudioUtils;
+
+QT_BEGIN_NAMESPACE
+
+QnxAudioDeviceInfo::QnxAudioDeviceInfo(const QByteArray &deviceName, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(deviceName, mode)
+{
+ isDefault = id.contains("Preferred");
+
+ preferredFormat.setChannelCount(mode == QAudioDevice::Input ? 1 : 2);
+
+ description = QString::fromUtf8(id);
+
+ minimumChannelCount = 1;
+ maximumChannelCount = 2;
+
+ const std::optional<snd_pcm_channel_info_t> info = pcmChannelInfo(id, mode);
+
+ if (!info)
+ return;
+
+ minimumSampleRate = info->min_rate;
+ maximumSampleRate = info->max_rate;
+
+ constexpr std::array sampleRates { 48000, 44100, 22050, 16000, 11025, 8000 };
+
+ for (int rate : sampleRates) {
+ if (rate <= maximumSampleRate && rate >= minimumSampleRate) {
+ preferredFormat.setSampleRate(rate);
+ break;
+ }
+ }
+
+ if (info->formats & SND_PCM_FMT_U8) {
+ supportedSampleFormats << QAudioFormat::UInt8;
+ preferredFormat.setSampleFormat(QAudioFormat::UInt8);
+ }
+
+ if (info->formats & SND_PCM_FMT_S16) {
+ supportedSampleFormats << QAudioFormat::Int16;
+ preferredFormat.setSampleFormat(QAudioFormat::Int16);
+ }
+
+ if (info->formats & SND_PCM_FMT_S32)
+ supportedSampleFormats << QAudioFormat::Int32;
+
+ if (info->formats & SND_PCM_FMT_FLOAT)
+ supportedSampleFormats << QAudioFormat::Float;
+}
+
+QnxAudioDeviceInfo::~QnxAudioDeviceInfo()
+{
+}
+
+bool QnxAudioDeviceInfo::isFormatSupported(const QAudioFormat &format) const
+{
+ const HandleUniquePtr handle = openPcmDevice(id, mode);
+
+ if (!handle)
+ return false;
+
+ const std::optional<snd_pcm_channel_info_t> info = pcmChannelInfo(handle.get(), mode);
+
+ if (!info)
+ return false;
+
+ snd_pcm_channel_params_t params = formatToChannelParams(format, mode, info->max_fragment_size);
+ const int errorCode = snd_pcm_plugin_params(handle.get(), &params);
+
+ return errorCode == 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qnx/qqnxaudiodevice_p.h b/src/multimedia/qnx/qqnxaudiodevice_p.h
new file mode 100644
index 000000000..52c89c14f
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudiodevice_p.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2016 Research In Motion
+// Copyright (C) 2021 The Qt Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNXAUDIODEVICE_P_H
+#define QNXAUDIODEVICE_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 "private/qaudiosystem_p.h"
+#include <private/qaudiodevice_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QnxAudioDeviceInfo : public QAudioDevicePrivate
+{
+public:
+ QnxAudioDeviceInfo(const QByteArray &deviceName, QAudioDevice::Mode mode);
+ ~QnxAudioDeviceInfo();
+
+ bool isFormatSupported(const QAudioFormat &format) const;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/platform/qnx/audio/qqnxaudiosink.cpp b/src/multimedia/qnx/qqnxaudiosink.cpp
index d2c1f98c7..fa4b97ab6 100644
--- a/src/multimedia/platform/qnx/audio/qqnxaudiosink.cpp
+++ b/src/multimedia/qnx/qqnxaudiosink.cpp
@@ -1,68 +1,43 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxaudiosink_p.h"
-#include "qnxaudioutils_p.h"
-
#include <private/qaudiohelpers_p.h>
+#include <sys/asoundlib.h>
+#include <sys/asound_common.h>
+
+#include <algorithm>
+#include <limits>
#pragma GCC diagnostic ignored "-Wvla"
QT_BEGIN_NAMESPACE
-QQnxAudioSink::QQnxAudioSink()
- : m_source(0)
+QQnxAudioSink::QQnxAudioSink(const QAudioDevice &deviceInfo, QObject *parent)
+ : QPlatformAudioSink(parent)
+ , m_source(0)
, m_pushSource(false)
+ , m_timer(new QTimer(this))
, m_error(QAudio::NoError)
, m_state(QAudio::StoppedState)
+ , m_suspendedInState(QAudio::SuspendedState)
, m_volume(1.0)
, m_periodSize(0)
- , m_pcmHandle(0)
, m_bytesWritten(0)
-#if _NTO_VERSION >= 700
+ , m_requestedBufferSize(0)
+ , m_deviceInfo(deviceInfo)
, m_pcmNotifier(0)
-#endif
{
- m_timer.setSingleShot(false);
- m_timer.setInterval(20);
- connect(&m_timer, SIGNAL(timeout()), this, SLOT(pullData()));
+ m_timer->setSingleShot(false);
+ m_timer->setInterval(20);
+ connect(m_timer, &QTimer::timeout, this, &QQnxAudioSink::pullData);
+
+ const std::optional<snd_pcm_channel_info_t> info = QnxAudioUtils::pcmChannelInfo(
+ m_deviceInfo.id(), QAudioDevice::Output);
+
+ if (info)
+ m_requestedBufferSize = info->max_fragment_size;
}
QQnxAudioSink::~QQnxAudioSink()
@@ -75,16 +50,14 @@ void QQnxAudioSink::start(QIODevice *source)
if (m_state != QAudio::StoppedState)
stop();
- m_error = QAudio::NoError;
m_source = source;
m_pushSource = false;
if (open()) {
- setState(QAudio::ActiveState);
- m_timer.start();
+ changeState(QAudio::ActiveState, QAudio::NoError);
+ m_timer->start();
} else {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
+ changeState(QAudio::StoppedState, QAudio::OpenError);
}
}
@@ -93,16 +66,14 @@ QIODevice *QQnxAudioSink::start()
if (m_state != QAudio::StoppedState)
stop();
- m_error = QAudio::NoError;
m_source = new QnxPushIODevice(this);
m_source->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
m_pushSource = true;
- if (open())
- setState(QAudio::IdleState);
- else {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
+ if (open()) {
+ changeState(QAudio::IdleState, QAudio::NoError);
+ } else {
+ changeState(QAudio::StoppedState, QAudio::OpenError);
}
return m_source;
@@ -113,8 +84,8 @@ void QQnxAudioSink::stop()
if (m_state == QAudio::StoppedState)
return;
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
+ changeState(QAudio::StoppedState, QAudio::NoError);
+
close();
}
@@ -122,39 +93,54 @@ void QQnxAudioSink::reset()
{
if (m_pcmHandle)
#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
- snd_pcm_playback_drain(m_pcmHandle);
+ snd_pcm_playback_drain(m_pcmHandle.get());
#else
- snd_pcm_channel_drain(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
+ snd_pcm_channel_drain(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
#endif
stop();
}
void QQnxAudioSink::suspend()
{
- snd_pcm_playback_pause(m_pcmHandle);
+ if (!m_pcmHandle)
+ return;
+
+ snd_pcm_playback_pause(m_pcmHandle.get());
suspendInternal(QAudio::SuspendedState);
}
void QQnxAudioSink::resume()
{
- snd_pcm_playback_resume(m_pcmHandle);
+ if (!m_pcmHandle)
+ return;
+
+ snd_pcm_playback_resume(m_pcmHandle.get());
resumeInternal();
}
+void QQnxAudioSink::setBufferSize(qsizetype bufferSize)
+{
+ m_requestedBufferSize = std::clamp<qsizetype>(bufferSize, 0, std::numeric_limits<int>::max());
+}
+
+qsizetype QQnxAudioSink::bufferSize() const
+{
+ const std::optional<snd_pcm_channel_setup_t> setup = m_pcmHandle
+ ? QnxAudioUtils::pcmChannelSetup(m_pcmHandle.get(), QAudioDevice::Output)
+ : std::nullopt;
+
+ return setup ? setup->buf.block.frag_size : m_requestedBufferSize;
+}
+
qsizetype QQnxAudioSink::bytesFree() const
{
if (m_state != QAudio::ActiveState && m_state != QAudio::IdleState)
return 0;
- snd_pcm_channel_status_t status;
- memset(&status, 0, sizeof(status));
- status.channel = SND_PCM_CHANNEL_PLAYBACK;
- const int errorCode = snd_pcm_plugin_status(m_pcmHandle, &status);
+ const std::optional<snd_pcm_channel_status_t> status = QnxAudioUtils::pcmChannelStatus(
+ m_pcmHandle.get(), QAudioDevice::Output);
- if (errorCode)
- return 0;
- else
- return status.free;
+ return status ? status->free : 0;
}
qint64 QQnxAudioSink::processedUSecs() const
@@ -193,6 +179,20 @@ qreal QQnxAudioSink::volume() const
return m_volume;
}
+void QQnxAudioSink::updateState()
+{
+ const std::optional<snd_pcm_channel_status_t> status = QnxAudioUtils::pcmChannelStatus(
+ m_pcmHandle.get(), QAudioDevice::Output);
+
+ if (!status)
+ return;
+
+ if (state() == QAudio::ActiveState && status->underrun > 0)
+ changeState(QAudio::IdleState, QAudio::UnderrunError);
+ else if (state() == QAudio::IdleState && status->underrun == 0)
+ changeState(QAudio::ActiveState, QAudio::NoError);
+}
+
void QQnxAudioSink::pullData()
{
if (m_state == QAudio::StoppedState
@@ -200,11 +200,12 @@ void QQnxAudioSink::pullData()
return;
const int bytesAvailable = bytesFree();
- const int frames = m_format.framesForBytes(bytesAvailable);
- if (frames == 0 || bytesAvailable < periodSize())
+ // skip if we have less than 4ms of data
+ if (m_format.durationForBytes(bytesAvailable) < 4000)
return;
+ const int frames = m_format.framesForBytes(bytesAvailable);
// The buffer is placed on the stack so no more than 64K or 1 frame
// whichever is larger.
const int maxFrames = qMax(m_format.framesForBytes(64 * 1024), 1);
@@ -218,24 +219,21 @@ void QQnxAudioSink::pullData()
return;
if (bytesRead > 0) {
- // Got some data to output
- if (m_state != QAudio::ActiveState)
- return;
-
const qint64 bytesWritten = write(buffer, bytesRead);
- if (bytesWritten != bytesRead)
- m_source->seek(m_source->pos()-(bytesRead-bytesWritten));
+ if (bytesWritten <= 0) {
+ close();
+ changeState(QAudio::StoppedState, QAudio::FatalError);
+ } else if (bytesWritten != bytesRead) {
+ m_source->seek(m_source->pos()-(bytesRead-bytesWritten));
+ }
} else {
// We're done
- close();
- if (bytesRead != 0)
- setError(QAudio::IOError);
- setState(QAudio::StoppedState);
+ if (bytesRead == 0)
+ changeState(QAudio::IdleState, QAudio::NoError);
+ else
+ changeState(QAudio::IdleState, QAudio::IOError);
}
-
- if (m_state != QAudio::ActiveState)
- return;
}
bool QQnxAudioSink::open()
@@ -249,16 +247,15 @@ bool QQnxAudioSink::open()
return false;
}
- int errorCode = 0;
- int card = 0;
- int device = 0;
- if ((errorCode = snd_pcm_open_preferred(&m_pcmHandle, &card, &device, SND_PCM_OPEN_PLAYBACK)) < 0) {
- qWarning("QQnxAudioSink: open error, couldn't open card (0x%x)", -errorCode);
+ m_pcmHandle = QnxAudioUtils::openPcmDevice(m_deviceInfo.id(), QAudioDevice::Output);
+
+ if (!m_pcmHandle)
return false;
- }
- if ((errorCode = snd_pcm_nonblock_mode(m_pcmHandle, 0)) < 0) {
+ int errorCode = 0;
+
+ if ((errorCode = snd_pcm_nonblock_mode(m_pcmHandle.get(), 0)) < 0) {
qWarning("QQnxAudioSink: open error, couldn't set non block mode (0x%x)", -errorCode);
close();
return false;
@@ -267,42 +264,43 @@ bool QQnxAudioSink::open()
addPcmEventFilter();
// Necessary so that bytesFree() which uses the "free" member of the status struct works
- snd_pcm_plugin_set_disable(m_pcmHandle, PLUGIN_MMAP);
+ snd_pcm_plugin_set_disable(m_pcmHandle.get(), PLUGIN_MMAP);
+
+ const std::optional<snd_pcm_channel_info_t> info = QnxAudioUtils::pcmChannelInfo(
+ m_pcmHandle.get(), QAudioDevice::Output);
- snd_pcm_channel_info_t info;
- memset(&info, 0, sizeof(info));
- info.channel = SND_PCM_CHANNEL_PLAYBACK;
- if ((errorCode = snd_pcm_plugin_info(m_pcmHandle, &info)) < 0) {
- qWarning("QQnxAudioSink: open error, couldn't get channel info (0x%x)", -errorCode);
+ if (!info) {
close();
return false;
}
- snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format, QAudioDevice::Output, info.max_fragment_size);
- setTypeName(&params);
+ const int fragmentSize = std::clamp(m_requestedBufferSize,
+ info->min_fragment_size, info->max_fragment_size);
- if ((errorCode = snd_pcm_plugin_params(m_pcmHandle, &params)) < 0) {
+ snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format,
+ QAudioDevice::Output, fragmentSize);
+
+ if ((errorCode = snd_pcm_plugin_params(m_pcmHandle.get(), &params)) < 0) {
qWarning("QQnxAudioSink: open error, couldn't set channel params (0x%x)", -errorCode);
close();
return false;
}
- if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK)) < 0) {
+ if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK)) < 0) {
qWarning("QQnxAudioSink: open error, couldn't prepare channel (0x%x)", -errorCode);
close();
return false;
}
- snd_pcm_channel_setup_t setup;
- memset(&setup, 0, sizeof(setup));
- setup.channel = SND_PCM_CHANNEL_PLAYBACK;
- if ((errorCode = snd_pcm_plugin_setup(m_pcmHandle, &setup)) < 0) {
- qWarning("QQnxAudioSink: open error, couldn't get channel setup (0x%x)", -errorCode);
+ const std::optional<snd_pcm_channel_setup_t> setup = QnxAudioUtils::pcmChannelSetup(
+ m_pcmHandle.get(), QAudioDevice::Output);
+
+ if (!setup) {
close();
return false;
}
- m_periodSize = qMin(2048, setup.buf.block.frag_size);
+ m_periodSize = qMin(2048, setup->buf.block.frag_size);
m_bytesWritten = 0;
createPcmNotifiers();
@@ -312,18 +310,18 @@ bool QQnxAudioSink::open()
void QQnxAudioSink::close()
{
- m_timer.stop();
+ if (!m_pushSource)
+ m_timer->stop();
destroyPcmNotifiers();
if (m_pcmHandle) {
#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
- snd_pcm_plugin_flush(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
+ snd_pcm_plugin_flush(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
#else
- snd_pcm_plugin_drop(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
+ snd_pcm_plugin_drop(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
#endif
- snd_pcm_close(m_pcmHandle);
- m_pcmHandle = 0;
+ m_pcmHandle = nullptr;
}
if (m_pushSource) {
@@ -332,20 +330,57 @@ void QQnxAudioSink::close()
}
}
-void QQnxAudioSink::setError(QAudio::Error error)
+void QQnxAudioSink::changeState(QAudio::State state, QAudio::Error error)
{
+ if (m_state != state) {
+ m_state = state;
+ emit stateChanged(state);
+ }
+
if (m_error != error) {
m_error = error;
emit errorChanged(error);
}
}
-void QQnxAudioSink::setState(QAudio::State state)
+qint64 QQnxAudioSink::pushData(const char *data, qint64 len)
{
- if (m_state != state) {
- m_state = state;
- emit stateChanged(state);
+ const QAudio::State s = state();
+
+ if (s == QAudio::StoppedState || s == QAudio::SuspendedState)
+ return 0;
+
+ if (s == QAudio::IdleState)
+ changeState(QAudio::ActiveState, QAudio::NoError);
+
+ qint64 totalWritten = 0;
+
+ int retry = 0;
+
+ constexpr int maxRetries = 10;
+
+ while (totalWritten < len) {
+ const int bytesWritten = write(data + totalWritten, len - totalWritten);
+
+ if (bytesWritten <= 0) {
+ ++retry;
+
+ if (retry >= maxRetries) {
+ close();
+ changeState(QAudio::StoppedState, QAudio::FatalError);
+
+ return totalWritten;
+ } else {
+ continue;
+ }
+ }
+
+ retry = 0;
+
+ totalWritten += bytesWritten;
}
+
+ return totalWritten;
}
qint64 QQnxAudioSink::write(const char *data, qint64 len)
@@ -364,41 +399,34 @@ qint64 QQnxAudioSink::write(const char *data, qint64 len)
if (m_volume < 1.0f) {
char out[size];
QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, out, size);
- written = snd_pcm_plugin_write(m_pcmHandle, out, size);
+ written = snd_pcm_plugin_write(m_pcmHandle.get(), out, size);
} else {
- written = snd_pcm_plugin_write(m_pcmHandle, data, size);
+ written = snd_pcm_plugin_write(m_pcmHandle.get(), data, size);
}
if (written > 0) {
m_bytesWritten += written;
- setError(QAudio::NoError);
- setState(QAudio::ActiveState);
return written;
- } else {
- close();
- setError(QAudio::FatalError);
- setState(QAudio::StoppedState);
- return 0;
}
+
+ return 0;
}
void QQnxAudioSink::suspendInternal(QAudio::State suspendState)
{
- m_timer.stop();
- setState(suspendState);
+ if (!m_pushSource)
+ m_timer->stop();
+
+ m_suspendedInState = m_state;
+ changeState(suspendState, QAudio::NoError);
}
void QQnxAudioSink::resumeInternal()
{
- if (m_pushSource) {
- setState(QAudio::IdleState);
- } else {
- setState(QAudio::ActiveState);
- m_timer.start();
- }
-}
+ changeState(m_suspendedInState, QAudio::NoError);
-#if _NTO_VERSION >= 700
+ m_timer->start();
+}
QAudio::State suspendState(const snd_pcm_event_t &event)
{
@@ -414,15 +442,16 @@ void QQnxAudioSink::addPcmEventFilter()
memset(&filter, 0, sizeof(filter));
filter.enable = (1<<SND_PCM_EVENT_AUDIOMGMT_STATUS) |
(1<<SND_PCM_EVENT_AUDIOMGMT_MUTE) |
- (1<<SND_PCM_EVENT_OUTPUTCLASS);
- snd_pcm_set_filter(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &filter);
+ (1<<SND_PCM_EVENT_OUTPUTCLASS) |
+ (1<<SND_PCM_EVENT_UNDERRUN);
+ snd_pcm_set_filter(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK, &filter);
}
void QQnxAudioSink::createPcmNotifiers()
{
// QSocketNotifier::Read for poll based event dispatcher. Exception for
// select based event dispatcher.
- m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle,
+ m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle.get(),
SND_PCM_CHANNEL_PLAYBACK),
QSocketNotifier::Read, this);
connect(m_pcmNotifier, &QSocketNotifier::activated,
@@ -437,36 +466,13 @@ void QQnxAudioSink::destroyPcmNotifiers()
}
}
-void QQnxAudioSink::setTypeName(snd_pcm_channel_params_t *params)
-{
-#if 0
-// Use some mapping from QAudio::Role
- if (m_category.isEmpty())
- return;
-
- QByteArray latin1Category = m_category.toLatin1();
-
- if (QString::fromLatin1(latin1Category) != m_category) {
- qWarning("QQnxAudioSink: audio category name isn't a Latin1 string.");
- return;
- }
-
- if (latin1Category.size() >= static_cast<int>(sizeof(params->audio_type_name))) {
- qWarning("QQnxAudioSink: audio category name too long.");
- return;
- }
-
- strcpy(params->audio_type_name, latin1Category.constData());
-#endif
-}
-
void QQnxAudioSink::pcmNotifierActivated(int socket)
{
Q_UNUSED(socket);
snd_pcm_event_t pcm_event;
memset(&pcm_event, 0, sizeof(pcm_event));
- while (snd_pcm_channel_read_event(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &pcm_event) == 0) {
+ while (snd_pcm_channel_read_event(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK, &pcm_event) == 0) {
if (pcm_event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS) {
if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED)
suspendInternal(suspendState(pcm_event));
@@ -474,19 +480,12 @@ void QQnxAudioSink::pcmNotifierActivated(int socket)
resumeInternal();
else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_PAUSED)
suspendInternal(QAudio::SuspendedState);
+ } else if (pcm_event.type == SND_PCM_EVENT_UNDERRUN) {
+ updateState();
}
}
}
-#else
-
-void QQnxAudioSink::addPcmEventFilter() {}
-void QQnxAudioSink::createPcmNotifiers() {}
-void QQnxAudioSink::destroyPcmNotifiers() {}
-void QQnxAudioSink::setTypeName(snd_pcm_channel_params_t *) {}
-
-#endif
-
QnxPushIODevice::QnxPushIODevice(QQnxAudioSink *output)
: QIODevice(output),
m_output(output)
@@ -506,28 +505,12 @@ qint64 QnxPushIODevice::readData(char *data, qint64 len)
qint64 QnxPushIODevice::writeData(const char *data, qint64 len)
{
- int retry = 0;
- qint64 written = 0;
-
- if (m_output->state() == QAudio::ActiveState
- || m_output->state() == QAudio::IdleState) {
- while (written < len) {
- const int writeSize = m_output->write(data + written, len - written);
-
- if (writeSize <= 0) {
- retry++;
- if (retry > 10)
- return written;
- else
- continue;
- }
-
- retry = 0;
- written += writeSize;
- }
- }
+ return m_output->pushData(data, len);
+}
- return written;
+bool QnxPushIODevice::isSequential() const
+{
+ return true;
}
QT_END_NAMESPACE
diff --git a/src/multimedia/qnx/qqnxaudiosink_p.h b/src/multimedia/qnx/qqnxaudiosink_p.h
new file mode 100644
index 000000000..1275121b3
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudiosink_p.h
@@ -0,0 +1,119 @@
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNXAUDIOOUTPUT_H
+#define QNXAUDIOOUTPUT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qaudiosystem_p.h"
+
+#include "qqnxaudioutils_p.h"
+
+#include <QElapsedTimer>
+#include <QTimer>
+#include <QIODevice>
+#include <QSocketNotifier>
+
+#include <sys/asoundlib.h>
+#include <sys/neutrino.h>
+
+QT_BEGIN_NAMESPACE
+
+class QnxPushIODevice;
+
+class QQnxAudioSink : public QPlatformAudioSink
+{
+ Q_OBJECT
+
+public:
+ explicit QQnxAudioSink(const QAudioDevice &deviceInfo, QObject *parent);
+ ~QQnxAudioSink();
+
+ void start(QIODevice *source) override;
+ QIODevice *start() override;
+ void stop() override;
+ void reset() override;
+ void suspend() override;
+ void resume() override;
+ qsizetype bytesFree() const override;
+ void setBufferSize(qsizetype) 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;
+ qint64 pushData(const char *data, qint64 len);
+
+private slots:
+ void pullData();
+ void pcmNotifierActivated(int socket);
+
+private:
+ bool open();
+ void close();
+ void changeState(QAudio::State state, QAudio::Error error);
+
+ void addPcmEventFilter();
+ void createPcmNotifiers();
+ void destroyPcmNotifiers();
+
+ void suspendInternal(QAudio::State suspendState);
+ void resumeInternal();
+
+ void updateState();
+
+ qint64 write(const char *data, qint64 len);
+
+ QIODevice *m_source;
+ bool m_pushSource;
+ QTimer *m_timer;
+
+ QAudio::Error m_error;
+ QAudio::State m_state;
+ QAudio::State m_suspendedInState;
+ QAudioFormat m_format;
+ qreal m_volume;
+ int m_periodSize;
+
+ QnxAudioUtils::HandleUniquePtr m_pcmHandle;
+ qint64 m_bytesWritten;
+
+ int m_requestedBufferSize;
+
+ QAudioDevice m_deviceInfo;
+
+ QSocketNotifier *m_pcmNotifier;
+};
+
+class QnxPushIODevice : public QIODevice
+{
+ Q_OBJECT
+public:
+ explicit QnxPushIODevice(QQnxAudioSink *output);
+ ~QnxPushIODevice();
+
+ qint64 readData(char *data, qint64 len);
+ qint64 writeData(const char *data, qint64 len);
+
+ bool isSequential() const override;
+
+private:
+ QQnxAudioSink *m_output;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/platform/qnx/audio/qqnxaudiosource.cpp b/src/multimedia/qnx/qqnxaudiosource.cpp
index b90681a83..becbaa0c0 100644
--- a/src/multimedia/platform/qnx/audio/qqnxaudiosource.cpp
+++ b/src/multimedia/qnx/qqnxaudiosource.cpp
@@ -1,55 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxaudiosource_p.h"
-#include "qnxaudioutils_p.h"
-
#include <private/qaudiohelpers_p.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
-QQnxAudioSource::QQnxAudioSource()
- : m_audioSource(0)
- , m_pcmHandle(0)
+QQnxAudioSource::QQnxAudioSource(const QAudioDevice &deviceInfo, QObject *parent)
+ : QPlatformAudioSource(parent)
+ , m_audioSource(0)
, m_pcmNotifier(0)
, m_error(QAudio::NoError)
, m_state(QAudio::StoppedState)
@@ -60,6 +22,7 @@ QQnxAudioSource::QQnxAudioSource()
, m_bytesAvailable(0)
, m_bufferSize(0)
, m_periodSize(0)
+ , m_deviceInfo(deviceInfo)
, m_pullMode(true)
{
}
@@ -80,13 +43,10 @@ void QQnxAudioSource::start(QIODevice *device)
m_pullMode = true;
m_audioSource = device;
- if (open()) {
- setError(QAudio::NoError);
- setState(QAudio::ActiveState);
- } else {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- }
+ if (open())
+ changeState(QAudio::ActiveState, QAudio::NoError);
+ else
+ changeState(QAudio::StoppedState, QAudio::OpenError);
}
QIODevice *QQnxAudioSource::start()
@@ -102,14 +62,12 @@ QIODevice *QQnxAudioSource::start()
m_audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
if (open()) {
- setError(QAudio::NoError);
- setState(QAudio::IdleState);
+ changeState(QAudio::IdleState, QAudio::NoError);
} else {
delete m_audioSource;
m_audioSource = 0;
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
+ changeState(QAudio::StoppedState, QAudio::OpenError);
}
return m_audioSource;
@@ -120,8 +78,7 @@ void QQnxAudioSource::stop()
if (m_state == QAudio::StoppedState)
return;
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
+ changeState(QAudio::StoppedState, QAudio::NoError);
close();
}
@@ -133,26 +90,31 @@ void QQnxAudioSource::reset()
void QQnxAudioSource::suspend()
{
- snd_pcm_capture_pause(m_pcmHandle);
+ if (m_state == QAudio::StoppedState)
+ return;
+
+ snd_pcm_capture_pause(m_pcmHandle.get());
if (m_pcmNotifier)
m_pcmNotifier->setEnabled(false);
- setState(QAudio::SuspendedState);
+ changeState(QAudio::SuspendedState, QAudio::NoError);
}
void QQnxAudioSource::resume()
{
- snd_pcm_capture_resume(m_pcmHandle);
+ if (m_state == QAudio::StoppedState)
+ return;
+
+ snd_pcm_capture_resume(m_pcmHandle.get());
if (m_pcmNotifier)
m_pcmNotifier->setEnabled(true);
- if (m_pullMode) {
- setState(QAudio::ActiveState);
- } else {
- setState(QAudio::IdleState);
- }
+ if (m_pullMode)
+ changeState(QAudio::ActiveState, QAudio::NoError);
+ else
+ changeState(QAudio::IdleState, QAudio::NoError);
}
qsizetype QQnxAudioSource::bytesReady() const
@@ -246,83 +208,71 @@ bool QQnxAudioSource::open()
return false;
}
- int errorCode = 0;
+ m_pcmHandle = QnxAudioUtils::openPcmDevice(m_deviceInfo.id(), QAudioDevice::Input);
- int card = 0;
- int device = 0;
- if ((errorCode = snd_pcm_open_preferred(&m_pcmHandle, &card, &device, SND_PCM_OPEN_CAPTURE)) < 0) {
- qWarning("QQnxAudioSource: open error, couldn't open card (0x%x)", -errorCode);
+ if (!m_pcmHandle)
return false;
- }
+
+ int errorCode = 0;
// Necessary so that bytesFree() which uses the "free" member of the status struct works
- snd_pcm_plugin_set_disable(m_pcmHandle, PLUGIN_MMAP);
+ snd_pcm_plugin_set_disable(m_pcmHandle.get(), PLUGIN_MMAP);
- snd_pcm_channel_info_t info;
- memset(&info, 0, sizeof(info));
- info.channel = SND_PCM_CHANNEL_CAPTURE;
- if ((errorCode = snd_pcm_plugin_info(m_pcmHandle, &info)) < 0) {
- qWarning("QQnxAudioSource: open error, couldn't get channel info (0x%x)", -errorCode);
+ const std::optional<snd_pcm_channel_info_t> info = QnxAudioUtils::pcmChannelInfo(
+ m_pcmHandle.get(), QAudioDevice::Input);
+
+ if (!info) {
close();
return false;
}
- snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format, QAudioDevice::Input, info.max_fragment_size);
+ snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format,
+ QAudioDevice::Input, info->max_fragment_size);
- if ((errorCode = snd_pcm_plugin_params(m_pcmHandle, &params)) < 0) {
+ if ((errorCode = snd_pcm_plugin_params(m_pcmHandle.get(), &params)) < 0) {
qWarning("QQnxAudioSource: open error, couldn't set channel params (0x%x)", -errorCode);
close();
return false;
}
- if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE)) < 0) {
+ if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE)) < 0) {
qWarning("QQnxAudioSource: open error, couldn't prepare channel (0x%x)", -errorCode);
close();
return false;
}
- snd_pcm_channel_setup_t setup;
-
- memset(&setup, 0, sizeof(setup));
- setup.channel = SND_PCM_CHANNEL_CAPTURE;
- if ((errorCode = snd_pcm_plugin_setup(m_pcmHandle, &setup)) < 0) {
- qWarning("QQnxAudioSource: open error, couldn't get channel setup (0x%x)", -errorCode);
- close();
- return false;
- }
+ const std::optional<snd_pcm_channel_setup_t> setup = QnxAudioUtils::pcmChannelSetup(
+ m_pcmHandle.get(), QAudioDevice::Input);
- m_periodSize = qMin(2048, setup.buf.block.frag_size);
+ m_periodSize = qMin(2048, setup->buf.block.frag_size);
m_elapsedTimeOffset = 0;
m_totalTimeValue = 0;
m_bytesRead = 0;
- m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE),
+ m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE),
QSocketNotifier::Read, this);
- connect(m_pcmNotifier, SIGNAL(activated(QSocketDescriptor)), SLOT(userFeed()));
+ connect(m_pcmNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(userFeed()));
return true;
}
void QQnxAudioSource::close()
{
- if (m_pcmHandle)
+ if (m_pcmHandle) {
#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
- snd_pcm_plugin_flush(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE);
+ snd_pcm_plugin_flush(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE);
#else
- snd_pcm_plugin_drop(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE);
+ snd_pcm_plugin_drop(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE);
#endif
+ m_pcmHandle = nullptr;
+ }
if (m_pcmNotifier) {
delete m_pcmNotifier;
m_pcmNotifier = 0;
}
- if (m_pcmHandle) {
- snd_pcm_close(m_pcmHandle);
- m_pcmHandle = 0;
- }
-
if (!m_pullMode && m_audioSource) {
delete m_audioSource;
m_audioSource = 0;
@@ -331,35 +281,35 @@ void QQnxAudioSource::close()
qint64 QQnxAudioSource::read(char *data, qint64 len)
{
+ if (!m_pullMode && m_bytesAvailable == 0)
+ return 0;
+
int errorCode = 0;
QByteArray tempBuffer(m_periodSize, 0);
- const int actualRead = snd_pcm_plugin_read(m_pcmHandle, tempBuffer.data(), m_periodSize);
+ const int actualRead = snd_pcm_plugin_read(m_pcmHandle.get(), tempBuffer.data(), m_periodSize);
if (actualRead < 1) {
snd_pcm_channel_status_t status;
memset(&status, 0, sizeof(status));
status.channel = SND_PCM_CHANNEL_CAPTURE;
- if ((errorCode = snd_pcm_plugin_status(m_pcmHandle, &status)) < 0) {
+ if ((errorCode = snd_pcm_plugin_status(m_pcmHandle.get(), &status)) < 0) {
qWarning("QQnxAudioSource: read error, couldn't get plugin status (0x%x)", -errorCode);
close();
- setError(QAudio::FatalError);
- setState(QAudio::StoppedState);
+ changeState(QAudio::StoppedState, QAudio::FatalError);
return -1;
}
if (status.status == SND_PCM_STATUS_READY
|| status.status == SND_PCM_STATUS_OVERRUN) {
- if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE)) < 0) {
+ if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE)) < 0) {
qWarning("QQnxAudioSource: read error, couldn't prepare plugin (0x%x)", -errorCode);
close();
- setError(QAudio::FatalError);
- setState(QAudio::StoppedState);
+ changeState(QAudio::StoppedState, QAudio::FatalError);
return -1;
}
}
} else {
- setError(QAudio::NoError);
- setState(QAudio::ActiveState);
+ changeState(QAudio::ActiveState, QAudio::NoError);
}
if (m_volume < 1.0f)
@@ -378,22 +328,17 @@ qint64 QQnxAudioSource::read(char *data, qint64 len)
return actualRead;
}
-void QQnxAudioSource::setError(QAudio::Error error)
-{
- if (m_error == error)
- return;
-
- m_error = error;
- emit errorChanged(m_error);
-}
-
-void QQnxAudioSource::setState(QAudio::State state)
+void QQnxAudioSource::changeState(QAudio::State state, QAudio::Error error)
{
- if (m_state == state)
- return;
+ if (m_state != state) {
+ m_state = state;
+ emit stateChanged(state);
+ }
- m_state = state;
- emit stateChanged(m_state);
+ if (m_error != error) {
+ m_error = error;
+ emit errorChanged(error);
+ }
}
InputPrivate::InputPrivate(QQnxAudioSource *audio)
@@ -413,6 +358,16 @@ qint64 InputPrivate::writeData(const char *data, qint64 len)
return 0;
}
+qint64 InputPrivate::bytesAvailable() const
+{
+ return m_audioDevice->m_bytesAvailable + QIODevice::bytesAvailable();
+}
+
+bool InputPrivate::isSequential() const
+{
+ return true;
+}
+
void InputPrivate::trigger()
{
emit readyRead();
diff --git a/src/multimedia/qnx/qqnxaudiosource_p.h b/src/multimedia/qnx/qqnxaudiosource_p.h
new file mode 100644
index 000000000..6b9cf61ac
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudiosource_p.h
@@ -0,0 +1,113 @@
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNXAUDIOINPUT_H
+#define QNXAUDIOINPUT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qaudiosystem_p.h"
+
+#include "qqnxaudioutils_p.h"
+
+#include <QSocketNotifier>
+#include <QIODevice>
+#include <QElapsedTimer>
+#include <QTimer>
+
+#include <sys/asoundlib.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQnxAudioSource : public QPlatformAudioSource
+{
+ Q_OBJECT
+
+public:
+ explicit QQnxAudioSource(const QAudioDevice &deviceInfo, QObject *parent);
+ ~QQnxAudioSource();
+
+ void start(QIODevice*) override;
+ QIODevice* start() override;
+ void stop() override;
+ void reset() override;
+ void suspend() override;
+ void resume() override;
+ qsizetype bytesReady() const override;
+ void setBufferSize(qsizetype ) override;
+ qsizetype bufferSize() const override;
+ qint64 processedUSecs() const override;
+ QAudio::Error error() const override;
+ QAudio::State state() const override;
+ void setFormat(const QAudioFormat&) override;
+ QAudioFormat format() const override;
+ void setVolume(qreal) override;
+ qreal volume() const override;
+
+private slots:
+ void userFeed();
+ bool deviceReady();
+
+private:
+ friend class InputPrivate;
+
+ bool open();
+ void close();
+ qint64 read(char *data, qint64 len);
+ void changeState(QAudio::State state, QAudio::Error error);
+
+ QAudioFormat m_format;
+
+ QIODevice *m_audioSource;
+ QnxAudioUtils::HandleUniquePtr m_pcmHandle;
+ QSocketNotifier *m_pcmNotifier;
+
+ QAudio::Error m_error;
+ QAudio::State m_state;
+
+ qint64 m_bytesRead;
+ qint64 m_elapsedTimeOffset;
+ qint64 m_totalTimeValue;
+
+ qreal m_volume;
+
+ int m_bytesAvailable;
+ int m_bufferSize;
+ int m_periodSize;
+
+ QAudioDevice m_deviceInfo;
+
+ bool m_pullMode;
+};
+
+class InputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ InputPrivate(QQnxAudioSource *audio);
+
+ qint64 readData(char *data, qint64 len) override;
+ qint64 writeData(const char *data, qint64 len) override;
+
+ qint64 bytesAvailable() const override;
+
+ bool isSequential() const override;
+
+ void trigger();
+
+private:
+ QQnxAudioSource *m_audioDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/qnx/qqnxaudioutils.cpp b/src/multimedia/qnx/qqnxaudioutils.cpp
new file mode 100644
index 000000000..ddcb4f0de
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudioutils.cpp
@@ -0,0 +1,148 @@
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqnxaudioutils_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QnxAudioUtils
+{
+
+snd_pcm_channel_params_t formatToChannelParams(const QAudioFormat &format, QAudioDevice::Mode mode, int fragmentSize)
+{
+ snd_pcm_channel_params_t params;
+ memset(&params, 0, sizeof(params));
+ params.channel = (mode == QAudioDevice::Output) ? SND_PCM_CHANNEL_PLAYBACK : SND_PCM_CHANNEL_CAPTURE;
+ params.mode = SND_PCM_MODE_BLOCK;
+ params.start_mode = SND_PCM_START_DATA;
+ params.stop_mode = SND_PCM_STOP_ROLLOVER;
+ params.buf.block.frag_size = fragmentSize;
+ params.buf.block.frags_min = 1;
+ params.buf.block.frags_max = 1;
+ strcpy(params.sw_mixer_subchn_name, "QAudio Channel");
+
+ params.format.interleave = 1;
+ params.format.rate = format.sampleRate();
+ params.format.voices = format.channelCount();
+
+ switch (format.sampleFormat()) {
+ case QAudioFormat::UInt8:
+ params.format.format = SND_PCM_SFMT_U8;
+ break;
+ default:
+ // fall through
+ case QAudioFormat::Int16:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ params.format.format = SND_PCM_SFMT_S16_LE;
+#else
+ params.format.format = SND_PCM_SFMT_S16_BE;
+#endif
+ break;
+ case QAudioFormat::Int32:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ params.format.format = SND_PCM_SFMT_S32_LE;
+#else
+ params.format.format = SND_PCM_SFMT_S32_BE;
+#endif
+ break;
+ case QAudioFormat::Float:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ params.format.format = SND_PCM_SFMT_FLOAT_LE;
+#else
+ params.format.format = SND_PCM_SFMT_FLOAT_BE;
+#endif
+ break;
+ }
+
+ return params;
+}
+
+
+HandleUniquePtr openPcmDevice(const QByteArray &id, QAudioDevice::Mode mode)
+{
+ const int pcmMode = mode == QAudioDevice::Output
+ ? SND_PCM_OPEN_PLAYBACK
+ : SND_PCM_OPEN_CAPTURE;
+
+ snd_pcm_t *handle;
+
+ const int errorCode = snd_pcm_open_name(&handle, id.constData(), pcmMode);
+
+ if (errorCode != 0) {
+ qWarning("Unable to open PCM device %s (0x%x)", id.constData(), -errorCode);
+ return {};
+ }
+
+ return HandleUniquePtr { handle };
+}
+
+template <typename T, typename Func>
+std::optional<T> pcmChannelGetStruct(snd_pcm_t *handle, QAudioDevice::Mode mode, Func &&func)
+{
+ // initialize in-place to prevent an extra copy when returning
+ std::optional<T> t = { T{} };
+
+ t->channel = mode == QAudioDevice::Output
+ ? SND_PCM_CHANNEL_PLAYBACK
+ : SND_PCM_CHANNEL_CAPTURE;
+
+ const int errorCode = func(handle, &(*t));
+
+ if (errorCode != 0) {
+ qWarning("QAudioDevice: couldn't get channel info (0x%x)", -errorCode);
+ return {};
+ }
+
+ return t;
+}
+
+template <typename T, typename Func>
+std::optional<T> pcmChannelGetStruct(const QByteArray &device,
+ QAudioDevice::Mode mode, Func &&func)
+{
+ const HandleUniquePtr handle = openPcmDevice(device, mode);
+
+ if (!handle)
+ return {};
+
+ return pcmChannelGetStruct<T>(handle.get(), mode, std::forward<Func>(func));
+}
+
+
+std::optional<snd_pcm_channel_info_t> pcmChannelInfo(snd_pcm_t *handle, QAudioDevice::Mode mode)
+{
+ return pcmChannelGetStruct<snd_pcm_channel_info_t>(handle, mode, snd_pcm_plugin_info);
+}
+
+std::optional<snd_pcm_channel_info_t> pcmChannelInfo(const QByteArray &device,
+ QAudioDevice::Mode mode)
+{
+ return pcmChannelGetStruct<snd_pcm_channel_info_t>(device, mode, snd_pcm_plugin_info);
+}
+
+std::optional<snd_pcm_channel_setup_t> pcmChannelSetup(snd_pcm_t *handle, QAudioDevice::Mode mode)
+{
+ return pcmChannelGetStruct<snd_pcm_channel_setup_t>(handle, mode, snd_pcm_plugin_setup);
+}
+
+std::optional<snd_pcm_channel_setup_t> pcmChannelSetup(const QByteArray &device,
+ QAudioDevice::Mode mode)
+{
+ return pcmChannelGetStruct<snd_pcm_channel_setup_t>(device, mode, snd_pcm_plugin_setup);
+}
+
+std::optional<snd_pcm_channel_status_t> pcmChannelStatus(snd_pcm_t *handle, QAudioDevice::Mode mode)
+{
+ return pcmChannelGetStruct<snd_pcm_channel_status_t>(handle, mode, snd_pcm_plugin_status);
+}
+
+std::optional<snd_pcm_channel_status_t> pcmChannelStatus(const QByteArray &device,
+ QAudioDevice::Mode mode)
+{
+ return pcmChannelGetStruct<snd_pcm_channel_status_t>(device, mode, snd_pcm_plugin_status);
+}
+
+
+} // namespace QnxAudioUtils
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qnx/qqnxaudioutils_p.h b/src/multimedia/qnx/qqnxaudioutils_p.h
new file mode 100644
index 000000000..c0d2e5b1c
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudioutils_p.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNXAUDIOUTILS_H
+#define QNXAUDIOUTILS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qaudiosystem_p.h"
+
+#include <memory>
+#include <optional>
+
+#include <sys/asoundlib.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QnxAudioUtils
+{
+ snd_pcm_channel_params_t formatToChannelParams(const QAudioFormat &format, QAudioDevice::Mode mode, int fragmentSize);
+
+ struct HandleDeleter
+ {
+ void operator()(snd_pcm_t *h) { if (h) snd_pcm_close(h); }
+ };
+
+ using HandleUniquePtr = std::unique_ptr<snd_pcm_t, HandleDeleter>;
+ HandleUniquePtr openPcmDevice(const QByteArray &id, QAudioDevice::Mode mode);
+
+ std::optional<snd_pcm_channel_info_t> pcmChannelInfo(snd_pcm_t *handle, QAudioDevice::Mode mode);
+ std::optional<snd_pcm_channel_info_t> pcmChannelInfo(const QByteArray &device, QAudioDevice::Mode mode);
+
+ std::optional<snd_pcm_channel_setup_t> pcmChannelSetup(snd_pcm_t *handle, QAudioDevice::Mode mode);
+ std::optional<snd_pcm_channel_setup_t> pcmChannelSetup(const QByteArray &device, QAudioDevice::Mode mode);
+
+ std::optional<snd_pcm_channel_status_t> pcmChannelStatus(snd_pcm_t *handle, QAudioDevice::Mode mode);
+ std::optional<snd_pcm_channel_status_t> pcmChannelStatus(const QByteArray &device, QAudioDevice::Mode mode);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/qnx/qqnxmediadevices.cpp b/src/multimedia/qnx/qqnxmediadevices.cpp
new file mode 100644
index 000000000..d9e33fcdc
--- /dev/null
+++ b/src/multimedia/qnx/qqnxmediadevices.cpp
@@ -0,0 +1,70 @@
+// 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 "qqnxmediadevices_p.h"
+#include "qmediadevices.h"
+#include "private/qcameradevice_p.h"
+#include "qcameradevice.h"
+
+#include "qqnxaudiosource_p.h"
+#include "qqnxaudiosink_p.h"
+#include "qqnxaudiodevice_p.h"
+
+#include <qdir.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+static QList<QAudioDevice> enumeratePcmDevices(QAudioDevice::Mode mode)
+{
+ if (mode == QAudioDevice::Null)
+ return {};
+
+ QDir dir(QStringLiteral("/dev/snd"));
+
+ dir.setFilter(QDir::Files);
+ dir.setSorting(QDir::Name);
+
+ // QNX PCM devices names start with the pcm prefix and end either with the
+ // 'p' (playback) or 'c' (capture) suffix
+
+ const char modeSuffix = mode == QAudioDevice::Input ? 'c' : 'p';
+
+ QList<QAudioDevice> devices;
+
+ for (const QString &entry : dir.entryList()) {
+ if (entry.startsWith(QStringLiteral("pcm")) && entry.back() == modeSuffix)
+ devices << (new QnxAudioDeviceInfo(entry.toUtf8(), mode))->create();
+ }
+
+ return devices;
+}
+
+QQnxMediaDevices::QQnxMediaDevices()
+ : QPlatformMediaDevices()
+{
+}
+
+QList<QAudioDevice> QQnxMediaDevices::audioInputs() const
+{
+ return ::enumeratePcmDevices(QAudioDevice::Input);
+}
+
+QList<QAudioDevice> QQnxMediaDevices::audioOutputs() const
+{
+ return ::enumeratePcmDevices(QAudioDevice::Output);
+}
+
+QPlatformAudioSource *QQnxMediaDevices::createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QQnxAudioSource(deviceInfo, parent);
+}
+
+QPlatformAudioSink *QQnxMediaDevices::createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QQnxAudioSink(deviceInfo, parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qnx/qqnxmediadevices_p.h b/src/multimedia/qnx/qqnxmediadevices_p.h
new file mode 100644
index 000000000..b8ccf5807
--- /dev/null
+++ b/src/multimedia/qnx/qqnxmediadevices_p.h
@@ -0,0 +1,39 @@
+// 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
+
+#ifndef QQNXMEDIADEVICES_H
+#define QQNXMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+#include <qaudio.h>
+#include <qcameradevice.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQnxMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QQnxMediaDevices();
+
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/qt_cmdline.cmake b/src/multimedia/qt_cmdline.cmake
index 4c5710464..5aabbbcb7 100644
--- a/src/multimedia/qt_cmdline.cmake
+++ b/src/multimedia/qt_cmdline.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_commandline_option(alsa TYPE boolean)
qt_commandline_option(evr TYPE boolean)
qt_commandline_option(wmf TYPE boolean)
diff --git a/src/multimedia/qtmultimediaglobal.h b/src/multimedia/qtmultimediaglobal.h
index ae11ed271..6b6200add 100644
--- a/src/multimedia/qtmultimediaglobal.h
+++ b/src/multimedia/qtmultimediaglobal.h
@@ -1,59 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 QTMULTIMEDIAGLOBAL_H
#define QTMULTIMEDIAGLOBAL_H
#include <QtGui/qtguiglobal.h>
#include <QtMultimedia/qtmultimedia-config.h>
+#include <QtMultimedia/qtmultimediaexports.h>
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_STATIC
-# if defined(QT_BUILD_MULTIMEDIA_LIB)
-# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT
-# else
-# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT
-# endif
-#else
-# define Q_MULTIMEDIA_EXPORT
-#endif
-
-QT_END_NAMESPACE
-#endif // QTQMLGLOBAL_H
+#endif // QTMULTIMEDIAGLOBAL_H
diff --git a/src/multimedia/qtmultimediaglobal_p.h b/src/multimedia/qtmultimediaglobal_p.h
index 797142029..e8ff737a7 100644
--- a/src/multimedia/qtmultimediaglobal_p.h
+++ b/src/multimedia/qtmultimediaglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 QTMULTIMEDIAGLOBAL_P_H
#define QTMULTIMEDIAGLOBAL_P_H
diff --git a/src/multimedia/recording/qcapturablewindow.cpp b/src/multimedia/recording/qcapturablewindow.cpp
new file mode 100644
index 000000000..34b6a1f5d
--- /dev/null
+++ b/src/multimedia/recording/qcapturablewindow.cpp
@@ -0,0 +1,156 @@
+// 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 "qcapturablewindow.h"
+#include "qcapturablewindow_p.h"
+#include "qplatformmediaintegration_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QCapturableWindowPrivate)
+
+/*!
+ \class QCapturableWindow
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_video
+ \since 6.6
+
+ \brief Used for getting the basic information of a capturable window.
+
+ The class contains a set of window information, except the method
+ QCapturableWindow::isValid which pulls the current state
+ whenever it's called.
+
+ \sa QWindowCapture
+*/
+/*!
+ \qmlvaluetype CapturableWindow
+ \instantiates QCapturableWindow
+ \brief The CapturableWindow type is used getting basic
+ of a window that is available for capturing via WindowCapture.
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_video_qml
+ \since 6.6
+
+ The class contains a dump of window information, except the property
+ 'isValid' which pulls the actual window state every time.
+
+ \sa WindowCapture
+*/
+
+/*!
+ \fn QCapturableWindow::QCapturableWindow(QCapturableWindow &&other)
+
+ Constructs a QCapturableWindow by moving from \a other.
+*/
+
+/*!
+ \fn void QCapturableWindow::swap(QCapturableWindow &other) noexcept
+
+ Swaps the current window information with \a other.
+*/
+
+/*!
+ \fn QCapturableWindow &QCapturableWindow::operator=(QCapturableWindow &&other)
+
+ Moves \a other into this QCapturableWindow.
+*/
+
+/*!
+ Constructs a null capturable window information that doesn't refer to any window.
+*/
+QCapturableWindow::QCapturableWindow() = default;
+
+/*!
+ Destroys the window information.
+ */
+QCapturableWindow::~QCapturableWindow() = default;
+
+/*!
+ Construct a new window information using \a other QCapturableWindow.
+*/
+QCapturableWindow::QCapturableWindow(const QCapturableWindow &other) = default;
+
+/*!
+ Assigns the \a other window information to this QCapturableWindow.
+*/
+QCapturableWindow& QCapturableWindow::operator=(const QCapturableWindow &other) = default;
+
+/*!
+ \fn bool QCapturableWindow::operator==(const QCapturableWindow &lhs, const QCapturableWindow &rhs)
+
+ Returns \c true if window information \a lhs and \a rhs refer to the same window,
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QCapturableWindow::operator!=(const QCapturableWindow &lhs, const QCapturableWindow &rhs)
+
+ Returns \c true if window information \a lhs and \a rhs refer to different windows,
+ otherwise returns \c false.
+*/
+bool operator==(const QCapturableWindow &lhs, const QCapturableWindow &rhs) noexcept
+{
+ return lhs.d == rhs.d || (lhs.d && rhs.d && lhs.d->id == rhs.d->id);
+}
+
+/*!
+ \qmlproperty string QtMultimedia::CapturableWindow::isValid
+
+ This property identifies whether a window information is valid.
+
+ An invalid window information refers to non-existing window or doesn't refer to any one.
+*/
+
+/*!
+ Identifies whether a window information is valid.
+
+ An invalid window information refers to non-existing window or doesn't refer to any one.
+
+ Returns true if the window is valid, and false if it is not.
+*/
+bool QCapturableWindow::isValid() const
+{
+ return d && QPlatformMediaIntegration::instance()->isCapturableWindowValid(*d);
+}
+
+/*!
+ \qmlproperty string QtMultimedia::CapturableWindow::description
+
+ This property holds the description of the reffered window.
+*/
+
+/*!
+ Returns a description of the window. In most cases it represents the window title.
+*/
+QString QCapturableWindow::description() const
+{
+ if (!d)
+ return {};
+
+ if (d->description.isEmpty() && d->id)
+ return QLatin1String("Window 0x") + QString::number(d->id, 16);
+
+ return d->description;
+}
+
+QCapturableWindow::QCapturableWindow(QCapturableWindowPrivate *capturablePrivate)
+ : d(capturablePrivate)
+{
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QCapturableWindow &window)
+{
+ dbg << QStringLiteral("Capturable window '%1'").arg(window.description());
+ return dbg;
+}
+#endif
+
+
+QT_END_NAMESPACE
+
+#include "moc_qcapturablewindow.cpp"
diff --git a/src/multimedia/recording/qcapturablewindow.h b/src/multimedia/recording/qcapturablewindow.h
new file mode 100644
index 000000000..f18dbf72d
--- /dev/null
+++ b/src/multimedia/recording/qcapturablewindow.h
@@ -0,0 +1,66 @@
+// 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 QCAPTURABLEWINDOW_H
+#define QCAPTURABLEWINDOW_H
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCapturableWindowPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QCapturableWindowPrivate, Q_MULTIMEDIA_EXPORT)
+
+class QMediaCaptureSession;
+class QWindowCapturePrivate;
+
+class QCapturableWindow
+{
+ Q_GADGET_EXPORT(Q_MULTIMEDIA_EXPORT)
+ Q_PROPERTY(QString description READ description CONSTANT)
+ Q_PROPERTY(bool isValid READ isValid CONSTANT)
+public:
+ Q_MULTIMEDIA_EXPORT QCapturableWindow();
+
+ Q_MULTIMEDIA_EXPORT ~QCapturableWindow();
+
+ Q_MULTIMEDIA_EXPORT QCapturableWindow(const QCapturableWindow &other);
+
+ QCapturableWindow(QCapturableWindow &&other) noexcept = default;
+
+ Q_MULTIMEDIA_EXPORT QCapturableWindow& operator=(const QCapturableWindow &other);
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCapturableWindow);
+
+ void swap(QCapturableWindow &other) noexcept
+ { d.swap(other.d); }
+
+ Q_MULTIMEDIA_EXPORT friend bool operator==(const QCapturableWindow &lhs, const QCapturableWindow &rhs) noexcept;
+
+ friend bool operator!=(const QCapturableWindow &lhs, const QCapturableWindow &rhs) noexcept
+ { return !(lhs == rhs); }
+
+ Q_MULTIMEDIA_EXPORT bool isValid() const;
+
+ Q_MULTIMEDIA_EXPORT QString description() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ Q_MULTIMEDIA_EXPORT friend QDebug operator<<(QDebug, const QCapturableWindow &);
+#endif
+
+private:
+ Q_MULTIMEDIA_EXPORT QCapturableWindow(QCapturableWindowPrivate *capturablePrivate);
+ friend class QCapturableWindowPrivate;
+
+ QExplicitlySharedDataPointer<QCapturableWindowPrivate> d;
+};
+
+Q_DECLARE_SHARED(QCapturableWindow)
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QCapturableWindow)
+
+#endif // QCAPTURABLEWINDOW_H
diff --git a/src/multimedia/recording/qcapturablewindow_p.h b/src/multimedia/recording/qcapturablewindow_p.h
new file mode 100644
index 000000000..9cb186a77
--- /dev/null
+++ b/src/multimedia/recording/qcapturablewindow_p.h
@@ -0,0 +1,41 @@
+// 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 QCAPTURABLEWINDOW_P_H
+#define QCAPTURABLEWINDOW_P_H
+
+#include <QtGui/qwindowdefs.h>
+#include <QtCore/QSharedData>
+#include <QtMultimedia/qcapturablewindow.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 QCapturableWindowPrivate : public QSharedData {
+public:
+ using Id = size_t;
+
+ QString description;
+ Id id = 0;
+
+ static const QCapturableWindowPrivate *handle(const QCapturableWindow &window)
+ {
+ return window.d.get();
+ }
+
+ QCapturableWindow create() { return QCapturableWindow(this); }
+};
+
+QT_END_NAMESPACE
+
+#endif // QCAPTURABLEWINDOW_P_H
diff --git a/src/multimedia/recording/qmediacapturesession.cpp b/src/multimedia/recording/qmediacapturesession.cpp
index 10324313e..0ff804bf4 100644
--- a/src/multimedia/recording/qmediacapturesession.cpp
+++ b/src/multimedia/recording/qmediacapturesession.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 "qmediacapturesession.h"
#include "qaudiodevice.h"
@@ -43,6 +7,8 @@
#include "qmediarecorder.h"
#include "qimagecapture.h"
#include "qvideosink.h"
+#include "qscreencapture.h"
+#include "qwindowcapture.h"
#include <qpointer.h>
@@ -57,13 +23,15 @@ class QMediaCaptureSessionPrivate
{
public:
QMediaCaptureSession *q = nullptr;
- QPlatformMediaCaptureSession *captureSession;
+ QPlatformMediaCaptureSession *captureSession = nullptr;
QAudioInput *audioInput = nullptr;
QAudioOutput *audioOutput = nullptr;
- QCamera *camera = nullptr;
- QImageCapture *imageCapture = nullptr;
- QMediaRecorder *recorder = nullptr;
- QVideoSink *videoSink = nullptr;
+ QPointer<QCamera> camera;
+ QPointer<QScreenCapture> screenCapture;
+ QPointer<QWindowCapture> windowCapture;
+ QPointer<QImageCapture> imageCapture;
+ QPointer<QMediaRecorder> recorder;
+ QPointer<QVideoSink> videoSink;
QPointer<QObject> videoOutput;
void setVideoSink(QVideoSink *sink)
@@ -75,10 +43,10 @@ public:
videoSink = sink;
if (sink)
sink->setSource(q);
- captureSession->setVideoPreview(sink);
+ if (captureSession)
+ captureSession->setVideoPreview(sink);
emit q->videoOutputChanged();
}
-
};
/*!
@@ -87,17 +55,21 @@ public:
\brief The QMediaCaptureSession class allows capturing of audio and video content.
\inmodule QtMultimedia
\ingroup multimedia
+ \ingroup multimedia_video
+ \ingroup multimedia_audio
The QMediaCaptureSession is the central class that manages capturing of media on the local device.
- You can connect a camera and a microphone to QMediaCaptureSession using setCamera() and setAudioInput().
- A preview of the captured media can be seen by setting a QVideoSink of QVideoWidget using setVideoOutput()
- and heard by routing the audio to an output device using setAudioOutput().
+ 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 microphone to QMediaCaptureSession using setAudioInput().
+ 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.
- \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QMediaRecorder
+ \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QScreenCapture, QWindowCapture, QMediaRecorder, QGraphicsVideoItem
*/
/*!
@@ -116,6 +88,12 @@ public:
Connect a camera and a microphone to a CaptureSession by assigning Camera
and AudioInput objects to the relevant properties.
+ Capture a screen by connecting a ScreenCapture object to
+ the screenCapture property.
+
+ Capture a window by connecting a WindowCapture object to
+ the windowCapture property.
+
Enable a preview of the captured media by assigning a VideoOutput element to
the videoOutput property.
@@ -144,7 +122,7 @@ public:
}
\endqml
- \sa Camera, MediaDevice, MediaRecorder, ImageCapture, AudioInput, VideoOutput
+ \sa Camera, MediaDevices, MediaRecorder, ImageCapture, ScreenCapture, WindowCapture, AudioInput, VideoOutput
*/
/*!
@@ -155,8 +133,13 @@ QMediaCaptureSession::QMediaCaptureSession(QObject *parent)
d_ptr(new QMediaCaptureSessionPrivate)
{
d_ptr->q = this;
- d_ptr->captureSession = QPlatformMediaIntegration::instance()->createCaptureSession();
- Q_ASSERT(d_ptr->captureSession);
+ auto maybeCaptureSession = QPlatformMediaIntegration::instance()->createCaptureSession();
+ if (maybeCaptureSession) {
+ d_ptr->captureSession = maybeCaptureSession.value();
+ d_ptr->captureSession->setCaptureSession(this);
+ } else {
+ qWarning() << "Failed to initialize QMediaCaptureSession" << maybeCaptureSession.error();
+ }
}
/*!
@@ -164,12 +147,13 @@ QMediaCaptureSession::QMediaCaptureSession(QObject *parent)
*/
QMediaCaptureSession::~QMediaCaptureSession()
{
- if (d_ptr->camera)
- d_ptr->camera->setCaptureSession(nullptr);
- if (d_ptr->recorder)
- d_ptr->recorder->setCaptureSession(nullptr);
- if (d_ptr->imageCapture)
- d_ptr->imageCapture->setCaptureSession(nullptr);
+ setCamera(nullptr);
+ setRecorder(nullptr);
+ setImageCapture(nullptr);
+ setScreenCapture(nullptr);
+ setWindowCapture(nullptr);
+ setAudioInput(nullptr);
+ setAudioOutput(nullptr);
d_ptr->setVideoSink(nullptr);
delete d_ptr->captureSession;
delete d_ptr;
@@ -177,11 +161,12 @@ QMediaCaptureSession::~QMediaCaptureSession()
/*!
\qmlproperty AudioInput QtMultimedia::CaptureSession::audioInput
- This property holds the audio input that is being used to capture audio..
- \sa setAudioInput()
+ This property holds the audio input that is being used to capture audio.
*/
/*!
+ \property QMediaCaptureSession::audioInput
+
Returns the device that is being used to capture audio.
*/
QAudioInput *QMediaCaptureSession::audioInput() const
@@ -190,16 +175,30 @@ QAudioInput *QMediaCaptureSession::audioInput() const
}
/*!
- Sets the audio input device to \a device. If setting it to an empty
+ Sets the audio input device to \a input. If setting it to an empty
QAudioDevice the capture session will use the default input as
defined by the operating system.
*/
-void QMediaCaptureSession::setAudioInput(QAudioInput *device)
+void QMediaCaptureSession::setAudioInput(QAudioInput *input)
{
- if (d_ptr->audioInput == device)
+ QAudioInput *oldInput = d_ptr->audioInput;
+ if (oldInput == input)
return;
- d_ptr->audioInput = device;
- d_ptr->captureSession->setAudioInput(device ? device->handle() : nullptr);
+
+ // To avoid double emit of audioInputChanged
+ // from recursive setAudioInput(nullptr) call.
+ d_ptr->audioInput = nullptr;
+
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setAudioInput(nullptr);
+ if (oldInput)
+ oldInput->setDisconnectFunction({});
+ if (input) {
+ input->setDisconnectFunction([this](){ setAudioInput(nullptr); });
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setAudioInput(input->handle());
+ }
+ d_ptr->audioInput = input;
emit audioInputChanged();
}
@@ -218,7 +217,7 @@ void QMediaCaptureSession::setAudioInput(QAudioInput *device)
\brief The camera used to capture video.
Record video or take images by adding a camera to the capture session
- using this property,
+ using this property.
*/
QCamera *QMediaCaptureSession::camera() const
{
@@ -227,16 +226,123 @@ QCamera *QMediaCaptureSession::camera() const
void QMediaCaptureSession::setCamera(QCamera *camera)
{
- if (d_ptr->camera == camera)
+ // TODO: come up with an unification of the captures setup
+ QCamera *oldCamera = d_ptr->camera;
+ if (oldCamera == camera)
return;
- if (d_ptr->camera)
- d_ptr->camera->setCaptureSession(nullptr);
-
d_ptr->camera = camera;
- if (d_ptr->camera)
- d_ptr->camera->setCaptureSession(this);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setCamera(nullptr);
+ if (oldCamera) {
+ if (oldCamera->captureSession() && oldCamera->captureSession() != this)
+ oldCamera->captureSession()->setCamera(nullptr);
+ oldCamera->setCaptureSession(nullptr);
+ }
+ if (camera) {
+ if (camera->captureSession())
+ camera->captureSession()->setCamera(nullptr);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setCamera(camera->platformCamera());
+ camera->setCaptureSession(this);
+ }
emit cameraChanged();
}
+
+/*!
+ \qmlproperty ScreenCapture QtMultimedia::CaptureSession::screenCapture
+ \since 6.5
+
+ \brief The object used to capture a screen.
+
+ Record a screen by adding a screen capture objet
+ to the capture session using this property.
+*/
+
+/*!
+ \property QMediaCaptureSession::screenCapture
+ \since 6.5
+
+ \brief The object used to capture a screen.
+
+ Record a screen by adding a screen capture object
+ to the capture session using this property.
+*/
+QScreenCapture *QMediaCaptureSession::screenCapture()
+{
+ return d_ptr ? d_ptr->screenCapture : nullptr;
+}
+
+void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture)
+{
+ // TODO: come up with an unification of the captures setup
+ QScreenCapture *oldScreenCapture = d_ptr->screenCapture;
+ if (oldScreenCapture == screenCapture)
+ return;
+ d_ptr->screenCapture = screenCapture;
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setScreenCapture(nullptr);
+ if (oldScreenCapture) {
+ if (oldScreenCapture->captureSession() && oldScreenCapture->captureSession() != this)
+ oldScreenCapture->captureSession()->setScreenCapture(nullptr);
+ oldScreenCapture->setCaptureSession(nullptr);
+ }
+ if (screenCapture) {
+ if (screenCapture->captureSession())
+ screenCapture->captureSession()->setScreenCapture(nullptr);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setScreenCapture(screenCapture->platformScreenCapture());
+ screenCapture->setCaptureSession(this);
+ }
+ emit screenCaptureChanged();
+}
+
+/*!
+ \qmlproperty WindowCapture QtMultimedia::CaptureSession::windowCapture
+ \since 6.6
+
+ \brief The object used to capture a window.
+
+ Record a window by adding a window capture object
+ to the capture session using this property.
+*/
+
+/*!
+ \property QMediaCaptureSession::windowCapture
+ \since 6.6
+
+ \brief The object used to capture a window.
+
+ 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;
+}
+
+void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture)
+{
+ // TODO: come up with an unification of the captures setup
+ QWindowCapture *oldCapture = d_ptr->windowCapture;
+ if (oldCapture == windowCapture)
+ return;
+ d_ptr->windowCapture = windowCapture;
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setWindowCapture(nullptr);
+ if (oldCapture) {
+ if (oldCapture->captureSession() && oldCapture->captureSession() != this)
+ oldCapture->captureSession()->setWindowCapture(nullptr);
+ oldCapture->setCaptureSession(nullptr);
+ }
+ if (windowCapture) {
+ if (windowCapture->captureSession())
+ windowCapture->captureSession()->setWindowCapture(nullptr);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setWindowCapture(windowCapture->platformWindowCapture());
+ windowCapture->setCaptureSession(this);
+ }
+ emit windowCaptureChanged();
+}
+
/*!
\qmlproperty ImageCapture QtMultimedia::CaptureSession::imageCapture
@@ -260,14 +366,25 @@ QImageCapture *QMediaCaptureSession::imageCapture()
void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture)
{
- if (d_ptr->imageCapture == imageCapture)
+ // TODO: come up with an unification of the captures setup
+ QImageCapture *oldImageCapture = d_ptr->imageCapture;
+ if (oldImageCapture == imageCapture)
return;
- if (d_ptr->imageCapture)
- d_ptr->imageCapture->setCaptureSession(nullptr);
-
d_ptr->imageCapture = imageCapture;
- if (d_ptr->imageCapture)
- d_ptr->imageCapture->setCaptureSession(this);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setImageCapture(nullptr);
+ if (oldImageCapture) {
+ if (oldImageCapture->captureSession() && oldImageCapture->captureSession() != this)
+ oldImageCapture->captureSession()->setImageCapture(nullptr);
+ oldImageCapture->setCaptureSession(nullptr);
+ }
+ if (imageCapture) {
+ if (imageCapture->captureSession())
+ imageCapture->captureSession()->setImageCapture(nullptr);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setImageCapture(imageCapture->platformImageCapture());
+ imageCapture->setCaptureSession(this);
+ }
emit imageCaptureChanged();
}
/*!
@@ -294,14 +411,24 @@ QMediaRecorder *QMediaCaptureSession::recorder()
void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder)
{
- if (d_ptr->recorder == recorder)
+ QMediaRecorder *oldRecorder = d_ptr->recorder;
+ if (oldRecorder == recorder)
return;
- if (d_ptr->recorder)
- d_ptr->recorder->setCaptureSession(nullptr);
-
d_ptr->recorder = recorder;
- if (d_ptr->recorder)
- d_ptr->recorder->setCaptureSession(this);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setMediaRecorder(nullptr);
+ if (oldRecorder) {
+ if (oldRecorder->captureSession() && oldRecorder->captureSession() != this)
+ oldRecorder->captureSession()->setRecorder(nullptr);
+ oldRecorder->setCaptureSession(nullptr);
+ }
+ if (recorder) {
+ if (recorder->captureSession())
+ recorder->captureSession()->setRecorder(nullptr);
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setMediaRecorder(recorder->platformRecoder());
+ recorder->setCaptureSession(this);
+ }
emit recorderChanged();
}
/*!
@@ -315,6 +442,11 @@ void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder)
The previously set preview is detached.
*/
+/*!
+ \property QMediaCaptureSession::videoOutput
+
+ Returns the video output for the session.
+*/
QObject *QMediaCaptureSession::videoOutput() const
{
Q_D(const QMediaCaptureSession);
@@ -356,6 +488,10 @@ void QMediaCaptureSession::setVideoSink(QVideoSink *sink)
d->videoOutput = nullptr;
d->setVideoSink(sink);
}
+
+/*!
+ Returns the QVideoSink for the session.
+*/
QVideoSink *QMediaCaptureSession::videoSink() const
{
Q_D(const QMediaCaptureSession);
@@ -363,19 +499,43 @@ QVideoSink *QMediaCaptureSession::videoSink() const
}
/*!
Sets the audio output device to \a{output}.
+
+ Setting an audio output device enables audio routing from an audio input device.
*/
void QMediaCaptureSession::setAudioOutput(QAudioOutput *output)
{
- Q_D(QMediaCaptureSession);
- if (d->audioOutput == output)
+ QAudioOutput *oldOutput = d_ptr->audioOutput;
+ if (oldOutput == output)
return;
- d->audioOutput = output;
- d->captureSession->setAudioOutput(output ? output->handle() : nullptr);
+
+ // We don't want to end up with signal emitted
+ // twice (from recursive call setAudioInput(nullptr)
+ // from oldOutput->setDisconnectFunction():
+ d_ptr->audioOutput = nullptr;
+
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setAudioOutput(nullptr);
+ if (oldOutput)
+ oldOutput->setDisconnectFunction({});
+ if (output) {
+ output->setDisconnectFunction([this](){ setAudioOutput(nullptr); });
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setAudioOutput(output->handle());
+ }
+ d_ptr->audioOutput = output;
emit audioOutputChanged();
}
/*!
\qmlproperty AudioOutput QtMultimedia::CaptureSession::audioOutput
\brief The audio output device for the capture session.
+
+ Add an AudioOutput device to the capture session to enable
+ audio routing from an AudioInput device.
+*/
+/*!
+ \property QMediaCaptureSession::audioOutput
+
+ Returns the audio output for the session.
*/
QAudioOutput *QMediaCaptureSession::audioOutput() const
{
diff --git a/src/multimedia/recording/qmediacapturesession.h b/src/multimedia/recording/qmediacapturesession.h
index 5ae152d8e..c613c3615 100644
--- a/src/multimedia/recording/qmediacapturesession.h
+++ b/src/multimedia/recording/qmediacapturesession.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEDIACAPTURESESSION_H
#define QMEDIACAPTURESESSION_H
@@ -49,10 +13,12 @@ class QCamera;
class QAudioInput;
class QAudioOutput;
class QCameraDevice;
-class QImageCapture; // ### rename to QMediaImageCapture
+class QImageCapture;
class QMediaRecorder;
class QPlatformMediaCaptureSession;
class QVideoSink;
+class QScreenCapture;
+class QWindowCapture;
class QMediaCaptureSessionPrivate;
class Q_MULTIMEDIA_EXPORT QMediaCaptureSession : public QObject
@@ -61,6 +27,10 @@ class Q_MULTIMEDIA_EXPORT QMediaCaptureSession : public QObject
Q_PROPERTY(QAudioInput *audioInput READ audioInput WRITE setAudioInput NOTIFY audioInputChanged)
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(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)
@@ -69,7 +39,7 @@ public:
~QMediaCaptureSession();
QAudioInput *audioInput() const;
- void setAudioInput(QAudioInput *device);
+ void setAudioInput(QAudioInput *input);
QCamera *camera() const;
void setCamera(QCamera *camera);
@@ -77,6 +47,12 @@ public:
QImageCapture *imageCapture();
void setImageCapture(QImageCapture *imageCapture);
+ QScreenCapture *screenCapture();
+ void setScreenCapture(QScreenCapture *screenCapture);
+
+ QWindowCapture *windowCapture();
+ void setWindowCapture(QWindowCapture *windowCapture);
+
QMediaRecorder *recorder();
void setRecorder(QMediaRecorder *recorder);
@@ -94,6 +70,8 @@ public:
Q_SIGNALS:
void audioInputChanged();
void cameraChanged();
+ void screenCaptureChanged();
+ void windowCaptureChanged();
void imageCaptureChanged();
void recorderChanged();
void videoOutputChanged();
diff --git a/src/multimedia/recording/qmediarecorder.cpp b/src/multimedia/recording/qmediarecorder.cpp
index afa189c89..a7f5a31b8 100644
--- a/src/multimedia/recording/qmediarecorder.cpp
+++ b/src/multimedia/recording/qmediarecorder.cpp
@@ -1,49 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qmediarecorder_p.h"
-#include <private/qplatformmediaencoder_p.h>
+#include <private/qplatformmediarecorder_p.h>
#include <qaudiodevice.h>
#include <qcamera.h>
+#include <qscreencapture.h>
+#include <qwindowcapture.h>
#include <qmediacapturesession.h>
#include <private/qplatformcamera_p.h>
+#include <private/qplatformsurfacecapture_p.h>
#include <private/qplatformmediaintegration_p.h>
#include <private/qplatformmediacapture_p.h>
@@ -62,6 +29,8 @@ QT_BEGIN_NAMESPACE
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_recording
+ \ingroup multimedia_video
+ \ingroup multimedia_audio
\brief The QMediaRecorder class is used for encoding and recording a capture session.
@@ -80,48 +49,44 @@ QT_BEGIN_NAMESPACE
\ingroup multimedia_audio_qml
\ingroup multimedia_video_qml
+ The MediaRecorder element can be used within a CaptureSession to record and encode audio and
+ video captured from a microphone and camera
+
\since 6.2
- The code below shows how this qml is instantiated.
+ The code below shows a simple capture session containing a MediaRecorder using the default
+ camera and default audio input.
+
\qml
CaptureSession {
id: captureSession
camera: Camera {
id: camera
+ active: true
}
- imageCapture: ImageCapture {
- id: imageCapture
- }
-
+ audioInput: AudioInput {}
recorder: MediaRecorder {
id: recorder
}
}
\endqml
- The code below shows how some properties are used.
+ The code below shows how the recording can be started and stopped.
\qml
CameraButton {
text: "Record"
- visible: captureSession.recorder.status !== MediaRecorder.RecordingStatus
- onClicked: captureSession.recorder.record()
+ visible: recorder.recorderState !== MediaRecorder.RecordingState
+ onClicked: recorder.record()
}
CameraButton {
id: stopButton
text: "Stop"
- visible: captureSession.recorder.status === MediaRecorder.RecordingStatus
- onClicked: captureSession.recorder.stop()
- }
-
- CameraButton {
- text: "View"
- onClicked: captureControls.previewSelected()
- //don't show View button during recording
- visible: captureSession.recorder.actualLocation && !stopButton.visible
+ visible: recorder.recorderState === MediaRecorder.RecordingState
+ onClicked: recorder.stop()
}
\endqml
- \sa CaptureSession
+ \sa CaptureSession, Camera, AudioInput, ImageCapture
*/
QMediaRecorderPrivate::QMediaRecorderPrivate()
{
@@ -145,8 +110,22 @@ QMediaRecorder::QMediaRecorder(QObject *parent)
d_ptr(new QMediaRecorderPrivate)
{
Q_D(QMediaRecorder);
+
+ auto &mediaIntegration = *QPlatformMediaIntegration::instance();
+
d->q_ptr = this;
- d->control = QPlatformMediaIntegration::instance()->createEncoder(this);
+ auto maybeControl = mediaIntegration.createRecorder(this);
+ if (maybeControl) {
+ // The first format info initialization may take some time,
+ // for users it seems to be more suitable to have a delay on the object construction
+ // rather than on QMediaRecorder::record
+ mediaIntegration.formatInfo();
+
+ d->control = maybeControl.value();
+ } else {
+ d->initErrorMessage = maybeControl.error();
+ qWarning() << "Failed to initialize QMediaRecorder" << maybeControl.error();
+ }
}
/*!
@@ -155,11 +134,8 @@ QMediaRecorder::QMediaRecorder(QObject *parent)
QMediaRecorder::~QMediaRecorder()
{
- if (d_ptr->captureSession) {
- if (d_ptr->captureSession->platformSession())
- d_ptr->captureSession->platformSession()->setMediaEncoder(nullptr);
+ if (d_ptr->captureSession)
d_ptr->captureSession->setRecorder(nullptr);
- }
delete d_ptr->control;
delete d_ptr;
}
@@ -167,22 +143,18 @@ QMediaRecorder::~QMediaRecorder()
/*!
\internal
*/
+QPlatformMediaRecorder *QMediaRecorder::platformRecoder() const
+{
+ return d_ptr->control;
+}
+
+/*!
+ \internal
+*/
void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session)
{
Q_D(QMediaRecorder);
- if (d->captureSession == session)
- return;
-
d->captureSession = session;
-
- if (!d->captureSession)
- return;
-
- QPlatformMediaCaptureSession *platformSession = session->platformSession();
- if (!platformSession || !d->control)
- return;
-
- platformSession->setMediaEncoder(d->control);
}
/*!
\qmlproperty QUrl QtMultimedia::MediaRecorder::outputLocation
@@ -227,17 +199,11 @@ void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session)
*/
/*!
- \qmlproperty bool QtMultimedia::MediaRecorder::isAvailable
- \brief This property holds whether the recorder service is ready to use.
-
- Returns \c true if media recorder service ready to use.
-*/
-/*!
Returns \c true if media recorder service ready to use.
*/
bool QMediaRecorder::isAvailable() const
{
- return d_func()->control != nullptr && d_func()->captureSession;
+ return d_func()->control && d_func()->captureSession;
}
QUrl QMediaRecorder::outputLocation() const
@@ -249,7 +215,7 @@ void QMediaRecorder::setOutputLocation(const QUrl &location)
{
Q_D(QMediaRecorder);
if (!d->control) {
- emit errorOccurred(QMediaRecorder::ResourceError, tr("Not available"));
+ emit errorOccurred(QMediaRecorder::ResourceError, d->initErrorMessage);
return;
}
d->control->setOutputLocation(location);
@@ -258,6 +224,35 @@ void QMediaRecorder::setOutputLocation(const QUrl &location)
emit errorOccurred(QMediaRecorder::LocationNotWritable, tr("Output location not writable"));
}
+/*!
+ Set the output IO device for media content.
+
+ The \a device must have been opened in the \l{QIODevice::Write}{Write} or
+ \l{QIODevice::ReadWrite}{ReadWrite} modes before the recording starts.
+
+ The media recorder doesn't take ownership of the specified \a device.
+ If the recording has been started, the device must be kept alive and open until
+ the signal \c recorderStateChanged(StoppedState) is emitted.
+
+ \sa outputDevice()
+*/
+void QMediaRecorder::setOutputDevice(QIODevice *device)
+{
+ Q_D(QMediaRecorder);
+ d->control->setOutputDevice(device);
+}
+
+/*!
+ Returns the output IO device for media content.
+
+ \sa setOutputDevice()
+*/
+QIODevice *QMediaRecorder::outputDevice() const
+{
+ Q_D(const QMediaRecorder);
+ return d->control->outputDevice();
+}
+
QUrl QMediaRecorder::actualLocation() const
{
Q_D(const QMediaRecorder);
@@ -276,6 +271,8 @@ QMediaRecorder::RecorderState QMediaRecorder::recorderState() const
}
/*!
+ \property QMediaRecorder::error
+
Returns the current error state.
\sa errorString()
@@ -294,6 +291,8 @@ QMediaRecorder::Error QMediaRecorder::error() const
\sa error
*/
/*!
+ \property QMediaRecorder::errorString
+
Returns a string describing the current error state.
\sa error()
@@ -303,7 +302,7 @@ QString QMediaRecorder::errorString() const
{
Q_D(const QMediaRecorder);
- return d->control ? d->control->errorString() : tr("QMediaRecorder not supported on this platform");
+ return d->control ? d->control->errorString() : d->initErrorMessage;
}
/*!
\qmlproperty qint64 QtMultimedia::MediaRecorder::duration
@@ -322,6 +321,11 @@ qint64 QMediaRecorder::duration() const
return d_func()->control ? d_func()->control->duration() : 0;
}
/*!
+ \fn void QMediaRecorder::encoderSettingsChanged()
+
+ Signals when the encoder settings change.
+*/
+/*!
\qmlmethod QtMultimedia::MediaRecorder::record()
\brief Starts recording.
@@ -359,17 +363,18 @@ void QMediaRecorder::record()
{
Q_D(QMediaRecorder);
- if (!d->control || ! d->captureSession)
+ if (!d->control || !d->captureSession)
return;
if (d->control->state() == QMediaRecorder::PausedState) {
d->control->resume();
} else {
auto oldMediaFormat = d->encoderSettings.mediaFormat();
- auto camera = d->captureSession->camera();
- auto flags = camera && camera->isActive() ? QMediaFormat::RequiresVideo
- : QMediaFormat::NoFlags;
- d->encoderSettings.resolveFormat(flags);
+
+ auto platformSession = d->captureSession->platformSession();
+ const bool hasVideo = platformSession && !platformSession->activeVideoSources().empty();
+
+ d->encoderSettings.resolveFormat(hasVideo ? QMediaFormat::RequiresVideo : QMediaFormat::NoFlags);
d->control->clearActualLocation();
d->control->clearError();
@@ -409,17 +414,18 @@ void QMediaRecorder::pause()
}
/*!
\qmlmethod QtMultimedia::MediaRecorder::stop()
- \brief Stops recording.
+ \brief Stops the recording.
- The recorder state is changed to \c{QMediaRecorder.StoppedState}.
+ The recorder will stop the recording. Processing pending video and audio data might
+ however still take some time. The recording is finished, once the state of the media
+ recorder changes to QMediaRecorder::StoppedState.
*/
/*!
- Stops recording.
-
- The recorder state is changed to QMediaRecorder::StoppedState.
+ The recorder will stop the recording. Processing pending video and audio data might
+ however still take some time. The recording is finished, once the state of the media
+ recorder changes to QMediaRecorder::StoppedState.
*/
-
void QMediaRecorder::stop()
{
Q_D(QMediaRecorder);
@@ -434,22 +440,14 @@ void QMediaRecorder::stop()
during record(), pause() or stop() calls.
RecorderSstate may also change asynchronously when recording fails.
- \value recorderState.StoppedState The recorder is not active.
- If this is the state after recording then the actual created recording has
- finished being written to the final location and is ready on all platforms
- except on Android. On Android, due to platform limitations, there is no way
- to be certain that the recording has finished writing to the final location.
- \value recorderState.RecordingState The recording is requested.
- \value recorderState.PausedState The recorder is pause.
+ \value MediaRecorder.StoppedState The recorder is not active.
+ \value MediaRecorder.RecordingState The recording is requested.
+ \value MediaRecorder.PausedState The recorder is pause.
*/
/*!
\enum QMediaRecorder::RecorderState
\value StoppedState The recorder is not active.
- If this is the state after recording then the actual created recording has
- finished being written to the final location and is ready on all platforms
- except on Android. On Android, due to platform limitations, there is no way
- to be certain that the recording has finished writing to the final location.
\value RecordingState The recording is requested.
\value PausedState The recorder is paused.
*/
@@ -529,7 +527,7 @@ void QMediaRecorder::stop()
*/
/*!
- \qmlproperty MetaData QtMultimedia::MediaRecorder::metaData
+ \qmlproperty mediaMetaData QtMultimedia::MediaRecorder::metaData
\brief This property holds meta data associated with the recording.
@@ -538,9 +536,13 @@ void QMediaRecorder::stop()
\note Ensure that meta-data is assigned correctly by assigning it before
starting the recording.
+
+ \sa mediaMetaData
*/
/*!
+ \property QMediaRecorder::metaData
+
Returns the metaData associated with the recording.
*/
QMediaMetaData QMediaRecorder::metaData() const
@@ -564,6 +566,9 @@ void QMediaRecorder::setMetaData(const QMediaMetaData &metaData)
d->control->setMetaData(metaData);
}
+/*!
+ Adds \a metaData to the recorded media.
+*/
void QMediaRecorder::addMetaData(const QMediaMetaData &metaData)
{
auto data = this->metaData();
@@ -589,6 +594,9 @@ void QMediaRecorder::addMetaData(const QMediaMetaData &metaData)
once.
*/
+/*!
+ Returns the media capture session.
+*/
QMediaCaptureSession *QMediaRecorder::captureSession() const
{
Q_D(const QMediaRecorder);
@@ -599,11 +607,11 @@ QMediaCaptureSession *QMediaRecorder::captureSession() const
Enumerates quality encoding levels.
- \value MediaaRecorder.VeryLowQuality
- \value MediaaRecorder.LowQuality
- \value MediaaRecorder.NormalQuality
- \value MediaaRecorder.HighQuality
- \value MediaaRecorder.VeryHighQuality
+ \value MediaRecorder.VeryLowQuality
+ \value MediaRecorder.LowQuality
+ \value MediaRecorder.NormalQuality
+ \value MediaRecorder.HighQuality
+ \value MediaRecorder.VeryHighQuality
*/
/*!
\enum QMediaRecorder::Quality
@@ -637,7 +645,11 @@ QMediaCaptureSession *QMediaRecorder::captureSession() const
\brief This property holds the current MediaFormat of the recorder.
*/
+/*!
+ \property QMediaRecorder::mediaFormat
+ Returns the recording media format.
+*/
QMediaFormat QMediaRecorder::mediaFormat() const
{
Q_D(const QMediaRecorder);
@@ -654,6 +666,14 @@ void QMediaRecorder::setMediaFormat(const QMediaFormat &format)
}
/*!
+
+ \qmlproperty enumeration QtMultimedia::MediaRecorder::encodingMode
+ \since 6.6
+ \brief This property holds the encoding mode.
+ \sa QMediaRecorder::EncodingMode
+*/
+
+/*!
Returns the encoding mode.
\sa EncodingMode
@@ -665,6 +685,11 @@ QMediaRecorder::EncodingMode QMediaRecorder::encodingMode() const
}
/*!
+ \fn void QMediaRecorder::encodingModeChanged()
+
+ Signals when the encoding mode changes.
+*/
+/*!
Sets the encoding \a mode setting.
If ConstantQualityEncoding is set, the quality
@@ -682,12 +707,22 @@ void QMediaRecorder::setEncodingMode(EncodingMode mode)
emit encodingModeChanged();
}
+/*!
+ \property QMediaRecorder::quality
+
+ Returns the recording quality.
+*/
QMediaRecorder::Quality QMediaRecorder::quality() const
{
Q_D(const QMediaRecorder);
return d->encoderSettings.quality();
}
+/*!
+ \fn void QMediaRecorder::qualityChanged()
+
+ Signals when the recording quality changes.
+*/
void QMediaRecorder::setQuality(Quality quality)
{
Q_D(QMediaRecorder);
@@ -697,6 +732,15 @@ void QMediaRecorder::setQuality(Quality quality)
emit qualityChanged();
}
+/*!
+ \qmlproperty Size QtMultimedia::MediaRecorder::videoResolution
+ \since 6.6
+ \brief This property holds the resolution of the encoded video.
+
+ Set an empty Size to make the recorder choose an optimal resolution based
+ on what is available from the video source and the limitations of the codec.
+*/
+
/*!
Returns the resolution of the encoded video.
@@ -708,6 +752,11 @@ QSize QMediaRecorder::videoResolution() const
}
/*!
+ \fn void QMediaRecorder::videoResolutionChanged()
+
+ Signals when the video recording resolution changes.
+*/
+/*!
Sets the resolution of the encoded video to \a{size}.
Pass an empty QSize to make the recorder choose an optimal resolution based
@@ -730,6 +779,15 @@ void QMediaRecorder::setVideoResolution(const QSize &size)
*/
/*!
+ \qmlproperty real QtMultimedia::MediaRecorder::videoFrameRate
+ \since 6.6
+ \brief This property holds the video frame rate.
+
+ A value of 0 indicates the recorder should make an optimal choice based on what is available
+ from the video source and the limitations of the codec.
+*/
+
+/*!
Returns the video frame rate.
*/
qreal QMediaRecorder::videoFrameRate() const
@@ -739,6 +797,11 @@ qreal QMediaRecorder::videoFrameRate() const
}
/*!
+ \fn void QMediaRecorder::videoFrameRateChanged()
+
+ Signals when the recording video frame rate changes.
+*/
+/*!
Sets the video \a frameRate.
A value of 0 indicates the recorder should make an optimal choice based on what is available
@@ -754,6 +817,12 @@ void QMediaRecorder::setVideoFrameRate(qreal frameRate)
}
/*!
+ \qmlproperty int QtMultimedia::MediaRecorder::videoBitRate
+ \since 6.6
+ \brief This property holds the bit rate of the compressed video stream in bits per second.
+*/
+
+/*!
Returns the bit rate of the compressed video stream in bits per second.
*/
int QMediaRecorder::videoBitRate() const
@@ -763,6 +832,11 @@ int QMediaRecorder::videoBitRate() const
}
/*!
+ \fn void QMediaRecorder::videoBitRateChanged()
+
+ Signals when the recording video bit rate changes.
+*/
+/*!
Sets the video \a bitRate in bits per second.
*/
void QMediaRecorder::setVideoBitRate(int bitRate)
@@ -775,6 +849,12 @@ void QMediaRecorder::setVideoBitRate(int bitRate)
}
/*!
+ \qmlproperty int QtMultimedia::MediaRecorder::audioBitRate
+ \since 6.6
+ \brief This property holds the bit rate of the compressed audio stream in bits per second.
+*/
+
+/*!
Returns the bit rate of the compressed audio stream in bits per second.
*/
int QMediaRecorder::audioBitRate() const
@@ -784,6 +864,11 @@ int QMediaRecorder::audioBitRate() const
}
/*!
+ \fn void QMediaRecorder::audioBitRateChanged()
+
+ Signals when the recording audio bit rate changes.
+*/
+/*!
Sets the audio \a bitRate in bits per second.
*/
void QMediaRecorder::setAudioBitRate(int bitRate)
@@ -796,6 +881,12 @@ void QMediaRecorder::setAudioBitRate(int bitRate)
}
/*!
+ \qmlproperty int QtMultimedia::MediaRecorder::audioChannelCount
+ \since 6.6
+ \brief This property holds the number of audio channels.
+*/
+
+/*!
Returns the number of audio channels.
*/
int QMediaRecorder::audioChannelCount() const
@@ -805,6 +896,11 @@ int QMediaRecorder::audioChannelCount() const
}
/*!
+ \fn void QMediaRecorder::audioChannelCountChanged()
+
+ Signals when the recording audio channel count changes.
+*/
+/*!
Sets the number of audio \a channels.
A value of -1 indicates the recorder should make an optimal choice based on
@@ -820,6 +916,12 @@ void QMediaRecorder::setAudioChannelCount(int channels)
}
/*!
+ \qmlproperty int QtMultimedia::MediaRecorder::audioSampleRate
+ \since 6.6
+ \brief This property holds the audio sample rate in Hz.
+*/
+
+/*!
Returns the audio sample rate in Hz.
*/
int QMediaRecorder::audioSampleRate() const
@@ -827,7 +929,11 @@ int QMediaRecorder::audioSampleRate() const
Q_D(const QMediaRecorder);
return d->encoderSettings.audioSampleRate();
}
+/*!
+ \fn void QMediaRecorder::audioSampleRateChanged()
+ Signals when the recording audio sample rate changes.
+*/
/*!
Sets the audio \a sampleRate in Hz.
diff --git a/src/multimedia/recording/qmediarecorder.h b/src/multimedia/recording/qmediarecorder.h
index 85ce5365e..fed276baf 100644
--- a/src/multimedia/recording/qmediarecorder.h
+++ b/src/multimedia/recording/qmediarecorder.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMediaRecorder_H
#define QMediaRecorder_H
@@ -58,6 +22,7 @@ class QCameraDevice;
class QMediaFormat;
class QAudioDevice;
class QMediaCaptureSession;
+class QPlatformMediaRecorder;
class QMediaRecorderPrivate;
class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject
@@ -71,7 +36,14 @@ class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject
Q_PROPERTY(QMediaRecorder::Error error READ error NOTIFY errorChanged)
Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
Q_PROPERTY(QMediaFormat mediaFormat READ mediaFormat WRITE setMediaFormat NOTIFY mediaFormatChanged)
- Q_PROPERTY(Quality quality READ quality WRITE setQuality)
+ Q_PROPERTY(Quality quality READ quality WRITE setQuality NOTIFY qualityChanged)
+ Q_PROPERTY(QMediaRecorder::EncodingMode encodingMode READ encodingMode WRITE setEncodingMode NOTIFY encodingModeChanged)
+ Q_PROPERTY(QSize videoResolution READ videoResolution WRITE setVideoResolution NOTIFY videoResolutionChanged)
+ Q_PROPERTY(qreal videoFrameRate READ videoFrameRate WRITE setVideoFrameRate NOTIFY videoFrameRateChanged)
+ Q_PROPERTY(int videoBitRate READ videoBitRate WRITE setVideoBitRate NOTIFY videoBitRateChanged)
+ Q_PROPERTY(int audioBitRate READ audioBitRate WRITE setAudioBitRate NOTIFY audioBitRateChanged)
+ Q_PROPERTY(int audioChannelCount READ audioChannelCount WRITE setAudioChannelCount NOTIFY audioChannelCountChanged)
+ Q_PROPERTY(int audioSampleRate READ audioSampleRate WRITE setAudioSampleRate NOTIFY audioSampleRateChanged)
public:
enum Quality
{
@@ -118,6 +90,9 @@ public:
QUrl outputLocation() const;
void setOutputLocation(const QUrl &location);
+ void setOutputDevice(QIODevice *device);
+ QIODevice *outputDevice() const;
+
QUrl actualLocation() const;
RecorderState recorderState() const;
@@ -160,6 +135,7 @@ public:
void addMetaData(const QMediaMetaData &metaData);
QMediaCaptureSession *captureSession() const;
+ QPlatformMediaRecorder *platformRecoder() const;
public Q_SLOTS:
void record();
diff --git a/src/multimedia/recording/qmediarecorder_p.h b/src/multimedia/recording/qmediarecorder_p.h
index e0b61ace0..193aa5f00 100644
--- a/src/multimedia/recording/qmediarecorder_p.h
+++ b/src/multimedia/recording/qmediarecorder_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMediaRecorder_P_H
#define QMediaRecorder_P_H
@@ -55,14 +19,14 @@
#include "qcamera.h"
#include <QtCore/qurl.h>
#include <QtCore/qpointer.h>
-#include "private/qplatformmediaencoder_p.h"
+#include "private/qplatformmediarecorder_p.h"
QT_BEGIN_NAMESPACE
-class QPlatformMediaEncoder;
+class QPlatformMediaRecorder;
class QTimer;
-class QMediaRecorderPrivate
+class Q_MULTIMEDIA_EXPORT QMediaRecorderPrivate
{
Q_DECLARE_PUBLIC(QMediaRecorder)
@@ -72,7 +36,8 @@ public:
static QString msgFailedStartRecording();
QMediaCaptureSession *captureSession = nullptr;
- QPlatformMediaEncoder *control = nullptr;
+ QPlatformMediaRecorder *control = nullptr;
+ QString initErrorMessage;
bool settingsChanged = false;
diff --git a/src/multimedia/recording/qscreencapture-limitations.qdocinc b/src/multimedia/recording/qscreencapture-limitations.qdocinc
new file mode 100644
index 000000000..cac51df02
--- /dev/null
+++ b/src/multimedia/recording/qscreencapture-limitations.qdocinc
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 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:
+ \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 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 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.
+ \endlist
+ //! [content]
+*/
diff --git a/src/multimedia/recording/qscreencapture.cpp b/src/multimedia/recording/qscreencapture.cpp
new file mode 100644
index 000000000..c178af1c1
--- /dev/null
+++ b/src/multimedia/recording/qscreencapture.cpp
@@ -0,0 +1,261 @@
+// Copyright (C) 2022 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 "qscreencapture.h"
+#include "qmediacapturesession.h"
+#include <private/qplatformmediaintegration_p.h>
+#include <private/qplatformsurfacecapture_p.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QScreenCapture::Error toScreenCaptureError(QPlatformSurfaceCapture::Error error)
+{
+ return static_cast<QScreenCapture::Error>(error);
+}
+
+class QScreenCapturePrivate : public QObjectPrivate
+{
+public:
+ QMediaCaptureSession *captureSession = nullptr;
+ std::unique_ptr<QPlatformSurfaceCapture> platformScreenCapture;
+};
+
+/*!
+ \class QScreenCapture
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_video
+ \since 6.5
+
+ \brief This class is used for capturing a screen.
+
+ The class captures a screen. It is managed by
+ the QMediaCaptureSession class where the captured screen can be displayed
+ in a video preview object or recorded to a file.
+
+ \snippet multimedia-snippets/media.cpp Media recorder
+
+ \include qscreencapture-limitations.qdocinc {content} {Q}
+
+ \sa QWindowCapture, QMediaCaptureSession
+*/
+/*!
+ \qmltype ScreenCapture
+ \instantiates QScreenCapture
+ \brief This type is used for capturing a screen.
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_video_qml
+
+ ScreenCapture captures a screen. It is managed by
+ MediaCaptureSession where the captured screen can be displayed
+ in a video preview object or recorded to a file.
+
+ \since 6.5
+ The code below shows a simple capture session with ScreenCapture playing
+ back the captured primary screen view in VideoOutput.
+
+\qml
+ CaptureSession {
+ id: captureSession
+ screenCapture: ScreenCapture {
+ id: screenCapture
+ active: true
+ }
+ videoOutput: VideoOutput {
+ id: videoOutput
+ }
+ }
+\endqml
+
+ \include qscreencapture-limitations.qdocinc {content} {}
+
+ \sa WindowCapture, CaptureSession
+*/
+
+QScreenCapture::QScreenCapture(QObject *parent)
+ : QObject(*new QScreenCapturePrivate, parent)
+{
+ Q_D(QScreenCapture);
+
+ auto platformCapture = QPlatformMediaIntegration::instance()->createScreenCapture(this);
+ if (platformCapture) {
+ connect(platformCapture, &QPlatformSurfaceCapture::activeChanged, this,
+ &QScreenCapture::activeChanged);
+ connect(platformCapture, &QPlatformSurfaceCapture::errorChanged, this,
+ &QScreenCapture::errorChanged);
+ connect(platformCapture, &QPlatformSurfaceCapture::errorOccurred, this,
+ [this](QPlatformSurfaceCapture::Error error, QString errorString) {
+ emit errorOccurred(toScreenCaptureError(error), errorString);
+ });
+
+ connect(platformCapture,
+ qOverload<QPlatformSurfaceCapture::ScreenSource>(
+ &QPlatformSurfaceCapture::sourceChanged),
+ this, &QScreenCapture::screenChanged);
+
+ d->platformScreenCapture.reset(platformCapture);
+ }
+}
+
+QScreenCapture::~QScreenCapture()
+{
+ Q_D(QScreenCapture);
+
+ // Reset platformScreenCapture in the destructor to avoid having broken ref in the object.
+ d->platformScreenCapture.reset();
+
+ if (d->captureSession)
+ d->captureSession->setScreenCapture(nullptr);
+}
+
+/*!
+ \enum QScreenCapture::Error
+
+ Enumerates error codes that can be signaled by the QScreenCapture class.
+ errorString() provides detailed information about the error cause.
+
+ \value NoError No error
+ \value InternalError Internal screen capturing driver error
+ \value CapturingNotSupported Capturing is not supported
+ \value CaptureFailed Capturing screen failed
+ \value NotFound Selected screen not found
+*/
+
+/*!
+ Returns the capture session this QScreenCapture is connected to.
+
+ Use QMediaCaptureSession::setScreenCapture() to connect the camera to
+ a session.
+*/
+QMediaCaptureSession *QScreenCapture::captureSession() const
+{
+ Q_D(const QScreenCapture);
+
+ return d->captureSession;
+}
+
+/*!
+ \qmlproperty bool QtMultimedia::ScreenCapture::active
+ Describes whether the capturing is currently active.
+*/
+
+/*!
+ \property QScreenCapture::active
+ \brief whether the capturing is currently active.
+*/
+void QScreenCapture::setActive(bool active)
+{
+ Q_D(QScreenCapture);
+
+ if (d->platformScreenCapture)
+ d->platformScreenCapture->setActive(active);
+}
+
+bool QScreenCapture::isActive() const
+{
+ Q_D(const QScreenCapture);
+
+ return d->platformScreenCapture && d->platformScreenCapture->isActive();
+}
+
+/*!
+ \qmlproperty Screen QtMultimedia::ScreenCapture::screen
+ Describes the screen for capturing.
+*/
+
+/*!
+ \property QScreenCapture::screen
+ \brief the screen for capturing.
+*/
+
+void QScreenCapture::setScreen(QScreen *screen)
+{
+ Q_D(QScreenCapture);
+
+ if (d->platformScreenCapture)
+ d->platformScreenCapture->setSource(QPlatformSurfaceCapture::ScreenSource(screen));
+}
+
+QScreen *QScreenCapture::screen() const
+{
+ Q_D(const QScreenCapture);
+
+ return d->platformScreenCapture
+ ? d->platformScreenCapture->source<QPlatformSurfaceCapture::ScreenSource>()
+ : nullptr;
+}
+
+/*!
+ \qmlproperty enumeration QtMultimedia::ScreenCapture::error
+ Returns a code of the last error.
+*/
+
+/*!
+ \property QScreenCapture::error
+ \brief the code of the last error.
+*/
+QScreenCapture::Error QScreenCapture::error() const
+{
+ Q_D(const QScreenCapture);
+
+ return d->platformScreenCapture ? toScreenCaptureError(d->platformScreenCapture->error())
+ : CapturingNotSupported;
+}
+
+/*!
+ \fn void QScreenCapture::errorOccurred(QScreenCapture::Error error, const QString &errorString)
+
+ Signals when an \a error occurs, along with the \a errorString.
+*/
+/*!
+ \qmlproperty string QtMultimedia::ScreenCapture::errorString
+ Returns a human readable string describing the cause of error.
+*/
+
+/*!
+ \property QScreenCapture::errorString
+ \brief a human readable string describing the cause of error.
+*/
+QString QScreenCapture::errorString() const
+{
+ Q_D(const QScreenCapture);
+
+ return d->platformScreenCapture ? d->platformScreenCapture->errorString()
+ : QLatin1StringView("Capturing is not support on this platform");
+}
+/*!
+ \fn void QScreenCapture::start()
+
+ Starts screen capture.
+*/
+/*!
+ \fn void QScreenCapture::stop()
+
+ Stops screen capture.
+*/
+/*!
+ \internal
+*/
+void QScreenCapture::setCaptureSession(QMediaCaptureSession *captureSession)
+{
+ Q_D(QScreenCapture);
+
+ d->captureSession = captureSession;
+}
+
+/*!
+ \internal
+*/
+class QPlatformSurfaceCapture *QScreenCapture::platformScreenCapture() const
+{
+ Q_D(const QScreenCapture);
+
+ return d->platformScreenCapture.get();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qscreencapture.cpp"
diff --git a/src/multimedia/recording/qscreencapture.h b/src/multimedia/recording/qscreencapture.h
new file mode 100644
index 000000000..b46925bc0
--- /dev/null
+++ b/src/multimedia/recording/qscreencapture.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2022 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 QSCREENCAPTURE_H
+#define QSCREENCAPTURE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qnamespace.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qwindowdefs.h>
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaCaptureSession;
+class QPlatformSurfaceCapture;
+class QScreenCapturePrivate;
+
+class Q_MULTIMEDIA_EXPORT QScreenCapture : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
+ Q_PROPERTY(QScreen *screen READ screen WRITE setScreen NOTIFY screenChanged)
+ Q_PROPERTY(Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+
+public:
+ enum Error {
+ NoError = 0,
+ InternalError = 1,
+ CapturingNotSupported = 2,
+ CaptureFailed = 4,
+ NotFound = 5,
+ };
+ Q_ENUM(Error)
+
+ explicit QScreenCapture(QObject *parent = nullptr);
+ ~QScreenCapture() override;
+
+ QMediaCaptureSession *captureSession() const;
+
+ void setScreen(QScreen *screen);
+ QScreen *screen() const;
+
+ bool isActive() const;
+
+ Error error() const;
+ QString errorString() const;
+
+public Q_SLOTS:
+ void setActive(bool active);
+ void start() { setActive(true); }
+ void stop() { setActive(false); }
+
+Q_SIGNALS:
+ void activeChanged(bool);
+ void errorChanged();
+ void screenChanged(QScreen *);
+ void errorOccurred(QScreenCapture::Error error, const QString &errorString);
+
+private:
+ void setCaptureSession(QMediaCaptureSession *captureSession);
+ QPlatformSurfaceCapture *platformScreenCapture() const;
+ friend class QMediaCaptureSession;
+ Q_DISABLE_COPY(QScreenCapture)
+ Q_DECLARE_PRIVATE(QScreenCapture)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSCREENCAPTURE_H
diff --git a/src/multimedia/recording/qwindowcapture.cpp b/src/multimedia/recording/qwindowcapture.cpp
new file mode 100644
index 000000000..69ad60100
--- /dev/null
+++ b/src/multimedia/recording/qwindowcapture.cpp
@@ -0,0 +1,268 @@
+// 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 "qwindowcapture.h"
+#include "qplatformmediaintegration_p.h"
+#include "qmediacapturesession.h"
+#include "private/qobject_p.h"
+#include "private/qplatformsurfacecapture_p.h"
+
+QT_BEGIN_NAMESPACE
+
+static QWindowCapture::Error toWindowCaptureError(QPlatformSurfaceCapture::Error error)
+{
+ return static_cast<QWindowCapture::Error>(error);
+}
+
+class QWindowCapturePrivate : public QObjectPrivate
+{
+public:
+ QMediaCaptureSession *captureSession = nullptr;
+ std::unique_ptr<QPlatformSurfaceCapture> platformWindowCapture;
+};
+
+/*!
+ \class QWindowCapture
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_video
+ \since 6.6
+
+ \brief This class is used for capturing a window.
+
+ The class captures a window. It is managed by
+ the QMediaCaptureSession class where the captured window can be displayed
+ in a video preview object or recorded to a file.
+
+ \sa QMediaCaptureSession, QCapturableWindow
+*/
+/*!
+ \qmltype WindowCapture
+ \instantiates QWindowCapture
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_video_qml
+ \since 6.6
+
+ \brief This type is used for capturing a window.
+
+ WindowCapture captures a window. It is managed by
+ MediaCaptureSession where the captured window can be displayed
+ in a video preview object or recorded to a file.
+
+ \sa CaptureSession, CapturableWindow
+*/
+
+/*!
+ \enum QWindowCapture::Error
+
+ Enumerates error codes that can be signaled by the QWindowCapture class.
+ errorString() provides detailed information about the error cause.
+
+ \value NoError No error
+ \value InternalError Internal window capturing driver error
+ \value CapturingNotSupported Window capturing is not supported
+ \value CaptureFailed Capturing window failed
+ \value NotFound Selected window not found
+*/
+
+/*!
+ Constructs a new QWindowCapture object with \a parent.
+*/
+QWindowCapture::QWindowCapture(QObject *parent) : QObject(*new QWindowCapturePrivate, parent)
+{
+ Q_D(QWindowCapture);
+
+ qRegisterMetaType<QCapturableWindow>();
+
+ auto platformCapture = QPlatformMediaIntegration::instance()->createWindowCapture(this);
+
+ if (platformCapture) {
+ connect(platformCapture, &QPlatformSurfaceCapture::activeChanged, this,
+ &QWindowCapture::activeChanged);
+ connect(platformCapture, &QPlatformSurfaceCapture::errorChanged, this,
+ &QWindowCapture::errorChanged);
+ connect(platformCapture, &QPlatformSurfaceCapture::errorOccurred, this,
+ [this](QPlatformSurfaceCapture::Error error, QString errorString) {
+ emit errorOccurred(toWindowCaptureError(error), errorString);
+ });
+ connect(platformCapture,
+ qOverload<QCapturableWindow>(&QPlatformSurfaceCapture::sourceChanged), this,
+ &QWindowCapture::windowChanged);
+
+ d->platformWindowCapture.reset(platformCapture);
+ }
+}
+
+/*!
+ Destroys the object.
+ */
+QWindowCapture::~QWindowCapture()
+{
+ Q_D(QWindowCapture);
+
+ d->platformWindowCapture.reset();
+
+ if (d->captureSession)
+ d->captureSession->setWindowCapture(nullptr);
+}
+
+/*!
+ \qmlmethod list<CapturableWindow> QtMultimedia::WindowCapture::capturableWindows()
+
+ Returns a list of CapturableWindow objects that is available for capturing.
+*/
+/*!
+ \fn QList<QCapturableWindow> QWindowCapture::capturableWindows()
+
+ Returns a list of QCapturableWindow objects that is available for capturing.
+ */
+QList<QCapturableWindow> QWindowCapture::capturableWindows()
+{
+ return QPlatformMediaIntegration::instance()->capturableWindowsList();
+}
+
+QMediaCaptureSession *QWindowCapture::captureSession() const
+{
+ Q_D(const QWindowCapture);
+
+ return d->captureSession;
+}
+
+/*!
+ \qmlproperty Window QtMultimedia::WindowCapture::window
+ Describes the window for capturing.
+
+ \sa QtMultimedia::WindowCapture::capturableWindows
+*/
+
+/*!
+ \property QWindowCapture::window
+ \brief the window for capturing.
+
+ \sa QWindowCapture::capturableWindows
+*/
+QCapturableWindow QWindowCapture::window() const
+{
+ Q_D(const QWindowCapture);
+
+ return d->platformWindowCapture ? d->platformWindowCapture->source<QCapturableWindow>()
+ : QCapturableWindow();
+}
+
+void QWindowCapture::setWindow(QCapturableWindow window)
+{
+ Q_D(QWindowCapture);
+
+ if (d->platformWindowCapture)
+ d->platformWindowCapture->setSource(window);
+}
+
+/*!
+ \qmlproperty bool QtMultimedia::WindowCapture::active
+ Describes whether the capturing is currently active.
+*/
+
+/*!
+ \property QWindowCapture::active
+ \brief whether the capturing is currently active.
+
+ \sa start(), stop()
+*/
+bool QWindowCapture::isActive() const
+{
+ Q_D(const QWindowCapture);
+
+ return d->platformWindowCapture && d->platformWindowCapture->isActive();
+}
+
+void QWindowCapture::setActive(bool active)
+{
+ Q_D(QWindowCapture);
+
+ if (d->platformWindowCapture)
+ d->platformWindowCapture->setActive(active);
+}
+
+/*!
+ \qmlmethod QtMultimedia::WindowCapture::start
+*/
+
+/*!
+ \fn void QWindowCapture::start()
+
+ Starts capturing the \l window.
+
+ This is equivalent to setting the \l active property to true.
+*/
+
+/*!
+ \qmlmethod QtMultimedia::WindowCapture::stop
+*/
+
+/*!
+ \fn void QWindowCapture::stop()
+
+ Stops capturing.
+
+ This is equivalent to setting the \l active property to false.
+*/
+
+
+/*!
+ \qmlproperty enumeration QtMultimedia::WindowCapture::error
+ Returns a code of the last error.
+*/
+
+/*!
+ \property QWindowCapture::error
+ \brief the code of the last error.
+*/
+QWindowCapture::Error QWindowCapture::error() const
+{
+ Q_D(const QWindowCapture);
+
+ return d->platformWindowCapture ? toWindowCaptureError(d->platformWindowCapture->error())
+ : CapturingNotSupported;
+}
+
+/*!
+ \fn void QWindowCapture::errorOccurred(QWindowCapture::Error error, const QString &errorString)
+
+ Signals when an \a error occurs, along with the \a errorString.
+*/
+/*!
+ \qmlproperty string QtMultimedia::WindowCapture::errorString
+ Returns a human readable string describing the cause of error.
+*/
+
+/*!
+ \property QWindowCapture::errorString
+ \brief a human readable string describing the cause of error.
+*/
+QString QWindowCapture::errorString() const
+{
+ Q_D(const QWindowCapture);
+
+ return d->platformWindowCapture
+ ? d->platformWindowCapture->errorString()
+ : QLatin1StringView("Capturing is not support on this platform");
+}
+
+void QWindowCapture::setCaptureSession(QMediaCaptureSession *captureSession)
+{
+ Q_D(QWindowCapture);
+
+ d->captureSession = captureSession;
+}
+
+QPlatformSurfaceCapture *QWindowCapture::platformWindowCapture() const
+{
+ Q_D(const QWindowCapture);
+
+ return d->platformWindowCapture.get();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwindowcapture.cpp"
diff --git a/src/multimedia/recording/qwindowcapture.h b/src/multimedia/recording/qwindowcapture.h
new file mode 100644
index 000000000..4c8b2eac3
--- /dev/null
+++ b/src/multimedia/recording/qwindowcapture.h
@@ -0,0 +1,71 @@
+// 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 QWINDOWCAPTURE_H
+#define QWINDOWCAPTURE_H
+
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtMultimedia/qcapturablewindow.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformSurfaceCapture;
+
+class Q_MULTIMEDIA_EXPORT QWindowCapture : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
+ Q_PROPERTY(QCapturableWindow window READ window WRITE setWindow NOTIFY windowChanged)
+ Q_PROPERTY(Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+public:
+ enum Error {
+ NoError = 0,
+ InternalError = 1,
+ CapturingNotSupported = 2,
+ CaptureFailed = 4,
+ NotFound = 5,
+ };
+ Q_ENUM(Error)
+
+ explicit QWindowCapture(QObject *parent = nullptr);
+ ~QWindowCapture() override;
+
+ Q_INVOKABLE static QList<QCapturableWindow> capturableWindows();
+
+ QMediaCaptureSession *captureSession() const;
+
+ void setWindow(QCapturableWindow window);
+
+ QCapturableWindow window() const;
+
+ bool isActive() const;
+
+ Error error() const;
+ QString errorString() const;
+
+public Q_SLOTS:
+ void setActive(bool active);
+ void start() { setActive(true); }
+ void stop() { setActive(false); }
+
+Q_SIGNALS:
+ void activeChanged(bool);
+ void windowChanged(QCapturableWindow window);
+ void errorChanged();
+ void errorOccurred(QWindowCapture::Error error, const QString &errorString);
+
+private:
+ void setCaptureSession(QMediaCaptureSession *captureSession);
+ QPlatformSurfaceCapture *platformWindowCapture() const;
+
+ friend class QMediaCaptureSession;
+ Q_DISABLE_COPY(QWindowCapture)
+ Q_DECLARE_PRIVATE(QWindowCapture)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWCAPTURE_H
diff --git a/src/multimedia/shaders/abgr.frag b/src/multimedia/shaders/abgr.frag
index a09defef3..7eadb092d 100644
--- a/src/multimedia/shaders/abgr.frag
+++ b/src/multimedia/shaders/abgr.frag
@@ -1,18 +1,19 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D rgbTexture;
void main()
{
fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).abgr * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
}
diff --git a/src/multimedia/shaders/argb.frag b/src/multimedia/shaders/argb.frag
index bfe7a97b2..1adbc8dba 100644
--- a/src/multimedia/shaders/argb.frag
+++ b/src/multimedia/shaders/argb.frag
@@ -1,18 +1,19 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D rgbTexture;
void main()
{
fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).gbar * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
}
diff --git a/src/multimedia/shaders/ayuv.frag b/src/multimedia/shaders/ayuv.frag
index 4212325e6..92c3f71fe 100644
--- a/src/multimedia/shaders/ayuv.frag
+++ b/src/multimedia/shaders/ayuv.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
void main()
@@ -17,4 +14,12 @@ void main()
vec3 YUV = texture(plane1Texture, texCoord).gba;
float A = texture(plane1Texture, texCoord).r;
fragColor = ubuf.colorMatrix * vec4(YUV, 1.0) * A * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/bgra.frag b/src/multimedia/shaders/bgra.frag
index 2b2812a33..0ba0e4c9e 100644
--- a/src/multimedia/shaders/bgra.frag
+++ b/src/multimedia/shaders/bgra.frag
@@ -1,18 +1,19 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D rgbTexture;
void main()
{
fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).bgra * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
}
diff --git a/src/multimedia/shaders/colorconvert.glsl b/src/multimedia/shaders/colorconvert.glsl
new file mode 100644
index 000000000..f28a0902e
--- /dev/null
+++ b/src/multimedia/shaders/colorconvert.glsl
@@ -0,0 +1,19 @@
+#ifndef COLORCONVERT
+#define COLORCONVERT
+
+// Convert the Rec2020 RGB colorspace to sRGB using:
+// https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2407-2017-PDF-E.pdf
+// We can use the simple matrix defined there for a conversion between BT2020
+// and sRGB. Conversion has to be done in linear color space.
+vec4 convertRec2020ToSRGB(vec4 rgba)
+{
+ const mat4 mat =
+ mat4(1.6605f, -0.5876f, -0.0728f, 0.0000f,
+ -0.1246f, 1.1329f, -0.0083f, 0.0000f,
+ -0.0182f, -0.1006f, 1.1187f, 0.0000f,
+ 0.0000f, 0.0000f, 0.0000f, 1.0000f);
+
+ return rgba * mat;
+}
+
+#endif
diff --git a/src/multimedia/shaders/colortransfer.glsl b/src/multimedia/shaders/colortransfer.glsl
new file mode 100644
index 000000000..1d70ae9eb
--- /dev/null
+++ b/src/multimedia/shaders/colortransfer.glsl
@@ -0,0 +1,118 @@
+#ifndef PERCEPTUAL_QUANTIZER
+#define PERCEPTUAL_QUANTIZER
+
+// Convert Rec.709 to linear
+vec4 convertRec709ToLinear(vec4 rgba)
+{
+ const vec4 alphaMinusOne = vec4(0.099, 0.099, 0.099, 0);
+ const vec4 alpha = alphaMinusOne + 1.;
+ bvec4 cutoff = lessThan(rgba, vec4(0.081));
+ vec4 high = pow((rgba + alphaMinusOne)/alpha, vec4(1./0.45));
+ vec4 low = rgba/4.5;
+ return mix(high, low, cutoff);
+}
+
+vec4 convertSRGBToLinear(vec4 sRGB)
+{
+ // https://en.wikipedia.org/wiki/SRGB
+ const bvec3 cutoff = lessThanEqual(sRGB.rgb, vec3(0.04045));
+ const vec3 low = sRGB.rgb / 12.92;
+ const vec3 high = pow((sRGB.rgb + 0.055) / 1.055, vec3(2.4));
+ vec3 linear = mix(high, low, cutoff);
+ return vec4(linear, sRGB.a);
+}
+
+vec4 convertSRGBFromLinear(vec4 linear)
+{
+ // https://en.wikipedia.org/wiki/SRGB
+ const bvec3 cutoff = lessThanEqual(linear.rgb, vec3(0.0031308));
+ const vec3 low = linear.rgb * 12.92;
+ const vec3 high = 1.055 * pow(linear.rgb, vec3(1.0 / 2.4f)) - 0.055;
+ vec3 sRGB = mix(high, low, cutoff);
+ return vec4(sRGB, linear.a);
+}
+
+// This uses the PQ transfer function, see also https://en.wikipedia.org/wiki/Perceptual_quantizer
+// or https://ieeexplore.ieee.org/document/7291452
+const float SDR_LEVEL = 100.;
+
+vec4 convertPQToLinear(vec4 rgba)
+{
+ const vec4 one_over_m1 = vec4(8192./1305.);
+ const vec4 one_over_m2 = vec4(32./2523.);
+ const float c1 = 107./128.;
+ const float c2 = 2413./128;
+ const float c3 = 2392./128.;
+
+ vec4 e = pow(rgba, one_over_m2);
+ vec4 num = max(e - c1, 0);
+ vec4 den = c2 - c3*e;
+ return pow(num/den, one_over_m1)*10000./SDR_LEVEL;
+}
+
+vec4 convertPQFromLinear(vec4 rgba)
+{
+ const float m1 = float(1305./8192.);
+ const float m2 = float(2523./32.);
+ const float c1 = 107./128.;
+ const float c2 = 2413./128;
+ const float c3 = 2392./128.;
+
+ rgba *= SDR_LEVEL/10000.;
+ vec4 p = pow(rgba, vec4(m1));
+ vec4 num = c1 + c2*p;
+ vec4 den = 1. + c3*p;
+ return pow(num/den, vec4(m2));
+}
+
+float convertPQToLinear(float sig)
+{
+ const float one_over_m1 = float(8192./1305.);
+ const float one_over_m2 = float(32./2523.);
+ const float c1 = 107./128.;
+ const float c2 = 2413./128;
+ const float c3 = 2392./128.;
+
+ float e = pow(sig, one_over_m2);
+ float num = max(e - c1, 0);
+ float den = c2 - c3*e;
+ return pow(num/den, one_over_m1)*10000./SDR_LEVEL;
+}
+
+float convertPQFromLinear(float sig)
+{
+ const float m1 = float(1305./8192.);
+ const float m2 = float(2523./32.);
+ const float c1 = 107./128.;
+ const float c2 = 2413./128;
+ const float c3 = 2392./128.;
+
+ sig *= SDR_LEVEL/10000.;
+ float p = pow(sig, m1);
+ float num = c1 + c2*p;
+ float den = 1. + c3*p;
+ return pow(num/den, m2);
+}
+
+// This implements support for HLG transfer functions, see also https://en.wikipedia.org/wiki/Hybrid_log–gamma
+
+
+vec4 convertHLGToLinear(vec4 rgba, float maxLum)
+{
+ const float a = 0.17883277;
+ const float b = 0.28466892; // = 1 - 4a
+ const float c = 0.55991073; // = 0.5 - a ln(4a)
+
+ bvec4 cutoff = lessThan(rgba, vec4(0.5));
+ vec4 low = rgba*rgba/3;
+ vec4 high = (exp((rgba - c)/a) + b)/12.;
+ rgba = mix(high, low, cutoff);
+
+ float lum = dot(rgba, vec4(0.2627, 0.6780, 0.0593, 0.));
+ float y = pow(lum, 0.2); // gamma-1 with gamma = 1.2
+
+ rgba *= y*maxLum;
+ return rgba;
+}
+
+#endif
diff --git a/src/multimedia/shaders/compile.bat b/src/multimedia/shaders/compile.bat
index 5db604424..8a012d265 100755
--- a/src/multimedia/shaders/compile.bat
+++ b/src/multimedia/shaders/compile.bat
@@ -1,45 +1,8 @@
-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-::
:: Copyright (C) 2019 The Qt Company Ltd.
-:: Contact: https://www.qt.io/licensing/
-::
-:: This file is part of the QtQuick module of the Qt Toolkit.
-::
-:: $QT_BEGIN_LICENSE:LGPL$
-:: Commercial License Usage
-:: Licensees holding valid commercial Qt licenses may use this file in
-:: accordance with the commercial license agreement provided with the
-:: Software or, alternatively, in accordance with the terms contained in
-:: a written agreement between you and The Qt Company. For licensing terms
-:: and conditions see https://www.qt.io/terms-conditions. For further
-:: information use the contact form at https://www.qt.io/contact-us.
-::
-:: GNU Lesser General Public License Usage
-:: Alternatively, this file may be used under the terms of the GNU Lesser
-:: General Public License version 3 as published by the Free Software
-:: Foundation and appearing in the file LICENSE.LGPL3 included in the
-:: packaging of this file. Please review the following information to
-:: ensure the GNU Lesser General Public License version 3 requirements
-:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-::
-:: GNU General Public License Usage
-:: Alternatively, this file may be used under the terms of the GNU
-:: General Public License version 2.0 or (at your option) the GNU General
-:: Public license version 3 or any later version approved by the KDE Free
-:: Qt Foundation. The licenses are as published by the Free Software
-:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-:: included in the packaging of this file. Please review the following
-:: information to ensure the GNU General Public License requirements will
-:: be met: https://www.gnu.org/licenses/gpl-2.0.html and
-:: https://www.gnu.org/licenses/gpl-3.0.html.
-::
-:: $QT_END_LICENSE$
-::
-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o rgba.vert.qsb rgba.vert
qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o rgba.frag.qsb rgba.frag
-qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o bgra.frag.qsb bgra.frag
qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuv.vert.qsb yuv.vert
qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuv_yv.frag.qsb yuv_yv.frag
diff --git a/src/multimedia/shaders/externalsampler.frag b/src/multimedia/shaders/externalsampler.frag
index 6431ea773..f786bc4e1 100644
--- a/src/multimedia/shaders/externalsampler.frag
+++ b/src/multimedia/shaders/externalsampler.frag
@@ -1,15 +1,11 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
void main()
diff --git a/src/multimedia/shaders/externalsampler.vert b/src/multimedia/shaders/externalsampler.vert
index 44e09fc70..e693370dc 100644
--- a/src/multimedia/shaders/externalsampler.vert
+++ b/src/multimedia/shaders/externalsampler.vert
@@ -1,17 +1,13 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
layout(location = 0) in vec4 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 0) out vec2 texCoord;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
out gl_PerVertex { vec4 gl_Position; };
void main() {
diff --git a/src/multimedia/shaders/externalsampler_gles.frag b/src/multimedia/shaders/externalsampler_gles.frag
index 23f0b1f9f..1292acebc 100644
--- a/src/multimedia/shaders/externalsampler_gles.frag
+++ b/src/multimedia/shaders/externalsampler_gles.frag
@@ -8,6 +8,8 @@ struct buf
mat4 colorMatrix;
float opacity;
float width;
+ float masteringWhite;
+ float maxLum;
};
uniform buf ubuf;
@@ -19,4 +21,8 @@ varying vec2 texCoord;
void main()
{
gl_FragColor = texture2D(plane1Texture, texCoord).rgba * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = pow(fragColor, 2.2);
+#endif
}
diff --git a/src/multimedia/shaders/hdrtonemapper.glsl b/src/multimedia/shaders/hdrtonemapper.glsl
new file mode 100644
index 000000000..e10b6eca3
--- /dev/null
+++ b/src/multimedia/shaders/hdrtonemapper.glsl
@@ -0,0 +1,38 @@
+#ifndef HDR_TONEMAPPER
+#define HDR_TONEMAPPER
+
+#include "colortransfer.glsl"
+
+// See https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-6-2019-PDF-E.pdf, section 5.4
+//
+// masteringWhite in PQ values, not in linear. maxOutLum as defined in the doc above
+// we assume that masteringBlack == 0, and minLum == 0 to simplify the calculations
+//
+// The HDR tonemapping operates in non linear space (PQ or HLG), taking the
+// non linear luminosity as input and returning a factor by which to scale
+// the RGB signal so it fits within the outbut devices range.
+//
+// We're using the same algorithm for HLG, and do the equivalent mapping in
+// HLG space.
+float tonemapScaleForLuminosity(float y, float masteringWhite, float maxLum)
+{
+ float p = y/masteringWhite;
+
+ float ks = 1.5*maxLum - 0.5;
+
+ if (p < ks)
+ return 1.;
+
+ float t = (p - ks)/(1 - ks);
+ float t2 = t*t;
+ float t3 = t*t2;
+
+ p = (2*t3 - 3*t2 + 1)*ks + (t3 - 2*t2 + t)*(1. - ks) + (-2*t3 + 3*t2)*maxLum;
+
+ // get the linear new luminosity
+ float newY = p*masteringWhite;
+
+ return newY/y;
+}
+
+#endif
diff --git a/src/multimedia/shaders/imc2.frag b/src/multimedia/shaders/imc2.frag
index 66ed4fe17..18401d420 100644
--- a/src/multimedia/shaders/imc2.frag
+++ b/src/multimedia/shaders/imc2.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
layout(binding = 2) uniform sampler2D plane2Texture;
@@ -17,8 +14,16 @@ void main()
{
float Y = texture(plane1Texture, texCoord).r;
float x = texCoord.x/2.;
- float U = texture(plane2Texture, vec2(x, texCoord.y)).r;
- float V = texture(plane2Texture, vec2(x + .5, texCoord.y)).r;
+ float U = texture(plane2Texture, vec2(x + .5, texCoord.y)).r;
+ float V = texture(plane2Texture, vec2(x, texCoord.y)).r;
vec4 color = vec4(Y, U, V, 1.);
fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/imc4.frag b/src/multimedia/shaders/imc4.frag
index 66ed4fe17..574a5f49b 100644
--- a/src/multimedia/shaders/imc4.frag
+++ b/src/multimedia/shaders/imc4.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
layout(binding = 2) uniform sampler2D plane2Texture;
@@ -21,4 +18,12 @@ void main()
float V = texture(plane2Texture, vec2(x + .5, texCoord.y)).r;
vec4 color = vec4(Y, U, V, 1.);
fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/nv12.frag b/src/multimedia/shaders/nv12.frag
index 277f9dc0b..20399d9f0 100644
--- a/src/multimedia/shaders/nv12.frag
+++ b/src/multimedia/shaders/nv12.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
layout(binding = 2) uniform sampler2D plane2Texture;
@@ -19,4 +16,12 @@ void main()
vec2 UV = texture(plane2Texture, texCoord).rg;
vec4 color = vec4(Y, UV.x, UV.y, 1.);
fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/nv12_bt2020_hlg.frag b/src/multimedia/shaders/nv12_bt2020_hlg.frag
new file mode 100644
index 000000000..25560c9b7
--- /dev/null
+++ b/src/multimedia/shaders/nv12_bt2020_hlg.frag
@@ -0,0 +1,42 @@
+#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
+#include "colorconvert.glsl"
+#include "hdrtonemapper.glsl"
+
+layout(location = 0) in vec2 texCoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D plane1Texture;
+layout(binding = 2) uniform sampler2D plane2Texture;
+
+// This implements support HDR video using the HLG transfer functions, see also
+// https://en.wikipedia.org/wiki/Hybrid_log–gamma
+// https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-6-2019-PDF-E.pdf
+// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-E.pdf
+//
+// Tonemapping is done using the same algorithm as for the PQ transfer function, but we
+// operate in HLG space here.
+void main()
+{
+ float Y = texture(plane1Texture, texCoord).r;
+ vec2 UV = texture(plane2Texture, texCoord).rg;
+ // map to Rec.2020 color space
+ fragColor = vec4(Y, UV.x, UV.y, 1.);
+ fragColor = ubuf.colorMatrix * fragColor;
+
+ // tonemap
+ float y = (Y - 16./256.)*256./219.; // Video range (16...235)
+ float scale = tonemapScaleForLuminosity(y, ubuf.masteringWhite, ubuf.maxLum);
+ fragColor *= scale;
+
+ fragColor = convertHLGToLinear(fragColor, ubuf.maxLum);
+ fragColor = convertRec2020ToSRGB(fragColor);
+ fragColor *= ubuf.opacity;
+
+#ifndef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBFromLinear(fragColor);
+#endif
+}
diff --git a/src/multimedia/shaders/nv12_bt2020_pq.frag b/src/multimedia/shaders/nv12_bt2020_pq.frag
new file mode 100644
index 000000000..96aef068e
--- /dev/null
+++ b/src/multimedia/shaders/nv12_bt2020_pq.frag
@@ -0,0 +1,48 @@
+#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
+#include "colorconvert.glsl"
+#include "hdrtonemapper.glsl"
+
+layout(location = 0) in vec2 texCoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D plane1Texture;
+layout(binding = 2) uniform sampler2D plane2Texture;
+
+// This uses the PQ transfer function, see also https://en.wikipedia.org/wiki/Perceptual_quantizer
+// or https://ieeexplore.ieee.org/document/7291452
+//
+// Tonemapping into the RGB range supported by the output is done using
+// https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-6-2019-PDF-E.pdf, section 5.4
+//
+// masteringWhite in PQ values, not in linear. maxOutLum as defined in the doc above
+// we assume that masteringBlack == 0, and minLum == 0 to simplify the calculations
+//
+// The calculation calculates a new luminosity in non linear space and scales the UV
+// components before linearizing. This corresponds to option (2) at the end of section 5.4.
+// This option was chosen as it keeps the colors correct while as well as being computationally
+// cheapest.
+void main()
+{
+ float Y = texture(plane1Texture, texCoord).r;
+ vec2 UV = texture(plane2Texture, texCoord).rg;
+ // map to Rec.2020 color space
+ fragColor = vec4(Y, UV.x, UV.y, 1.);
+ fragColor = ubuf.colorMatrix * fragColor;
+
+ // tonemap
+ float y = (Y - 16./256.)*256./219.; // Video range (16...235)
+ float scale = tonemapScaleForLuminosity(y, ubuf.masteringWhite, ubuf.maxLum);
+ fragColor *= scale;
+
+ fragColor = convertPQToLinear(fragColor);
+ fragColor = convertRec2020ToSRGB(fragColor);
+ fragColor *= ubuf.opacity;
+
+#ifndef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBFromLinear(fragColor);
+#endif
+}
diff --git a/src/multimedia/shaders/nv21.frag b/src/multimedia/shaders/nv21.frag
index 29890c7c0..c3f641be5 100644
--- a/src/multimedia/shaders/nv21.frag
+++ b/src/multimedia/shaders/nv21.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
layout(binding = 2) uniform sampler2D plane2Texture;
@@ -19,4 +16,12 @@ void main()
vec2 UV = texture(plane2Texture, texCoord).gr;
vec4 color = vec4(Y, UV.x, UV.y, 1.);
fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/rectsampler.vert b/src/multimedia/shaders/rectsampler.vert
index 44e09fc70..e693370dc 100644
--- a/src/multimedia/shaders/rectsampler.vert
+++ b/src/multimedia/shaders/rectsampler.vert
@@ -1,17 +1,13 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
layout(location = 0) in vec4 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 0) out vec2 texCoord;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
out gl_PerVertex { vec4 gl_Position; };
void main() {
diff --git a/src/multimedia/shaders/rectsampler_bgra.frag b/src/multimedia/shaders/rectsampler_bgra.frag
index 8dc9192e1..8b1b9a4ad 100644
--- a/src/multimedia/shaders/rectsampler_bgra.frag
+++ b/src/multimedia/shaders/rectsampler_bgra.frag
@@ -1,18 +1,19 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2DRect rgbTexture;
void main()
{
- fragColor = texture(rgbTexture, texCoord).bgra * ubuf.opacity;
+ fragColor = texture(rgbTexture, texCoord).rgba * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
}
diff --git a/src/multimedia/shaders/rgba.frag b/src/multimedia/shaders/rgba.frag
index 33c4a8669..b53e0dc71 100644
--- a/src/multimedia/shaders/rgba.frag
+++ b/src/multimedia/shaders/rgba.frag
@@ -1,18 +1,19 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D rgbTexture;
void main()
{
fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).rgba * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
}
diff --git a/src/multimedia/shaders/uniformbuffer.glsl b/src/multimedia/shaders/uniformbuffer.glsl
new file mode 100644
index 000000000..c74859c5d
--- /dev/null
+++ b/src/multimedia/shaders/uniformbuffer.glsl
@@ -0,0 +1,11 @@
+// Make sure to also modify externalsampler_gles.frag when modifying this
+
+layout(std140, binding = 0) uniform buf {
+ mat4 matrix;
+ mat4 colorMatrix;
+ float opacity;
+ float width;
+ // HDR metadata required for tonemapping
+ float masteringWhite; // in PQ or HLG values
+ float maxLum; // in PQ or HLG values
+} ubuf;
diff --git a/src/multimedia/shaders/uyvy.frag b/src/multimedia/shaders/uyvy.frag
index 5ab50e3b6..26a83da3f 100644
--- a/src/multimedia/shaders/uyvy.frag
+++ b/src/multimedia/shaders/uyvy.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
void main()
@@ -19,4 +16,12 @@ void main()
float Y = rightSubPixel ? texture(plane1Texture, texCoord).a : texture(plane1Texture, texCoord).g;
vec2 UV = texture(plane1Texture, texCoord).rb;
fragColor = ubuf.colorMatrix * vec4(Y, UV, 1.0) * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/vertex.vert b/src/multimedia/shaders/vertex.vert
index 068a4157c..ce170824e 100644
--- a/src/multimedia/shaders/vertex.vert
+++ b/src/multimedia/shaders/vertex.vert
@@ -1,17 +1,13 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
layout(location = 0) in vec4 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 0) out vec2 texCoord;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
out gl_PerVertex { vec4 gl_Position; };
void main() {
diff --git a/src/multimedia/shaders/y.frag b/src/multimedia/shaders/y.frag
index 82c75ec78..8c25fc762 100644
--- a/src/multimedia/shaders/y.frag
+++ b/src/multimedia/shaders/y.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
void main()
@@ -17,4 +14,12 @@ void main()
float Y = texture(plane1Texture, texCoord).r;
vec4 color = vec4(Y, Y, Y, 1.);
fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/yuv_triplanar.frag b/src/multimedia/shaders/yuv_triplanar.frag
index 239c1dcfd..228147943 100644
--- a/src/multimedia/shaders/yuv_triplanar.frag
+++ b/src/multimedia/shaders/yuv_triplanar.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
layout(binding = 2) uniform sampler2D plane2Texture;
layout(binding = 3) uniform sampler2D plane3Texture;
@@ -21,4 +18,12 @@ void main()
float V = texture(plane3Texture, texCoord).r;
vec4 color = vec4(Y, U, V, 1.);
fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/yuv_triplanar_p10.frag b/src/multimedia/shaders/yuv_triplanar_p10.frag
new file mode 100644
index 000000000..5da0ed339
--- /dev/null
+++ b/src/multimedia/shaders/yuv_triplanar_p10.frag
@@ -0,0 +1,29 @@
+#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
+
+layout(location = 0) in vec2 texCoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D plane1Texture;
+layout(binding = 2) uniform sampler2D plane2Texture;
+layout(binding = 3) uniform sampler2D plane3Texture;
+
+void main()
+{
+ float Y = texture(plane1Texture, texCoord).r * 64;
+ float U = texture(plane2Texture, texCoord).r * 64;
+ float V = texture(plane3Texture, texCoord).r * 64;
+ vec4 color = vec4(Y, U, V, 1.);
+ fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
+}
diff --git a/src/multimedia/shaders/yuyv.frag b/src/multimedia/shaders/yuyv.frag
index 6fc3f35e9..0f6e65b6d 100644
--- a/src/multimedia/shaders/yuyv.frag
+++ b/src/multimedia/shaders/yuyv.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
void main()
@@ -19,4 +16,12 @@ void main()
float Y = rightSubPixel ? texture(plane1Texture, texCoord).b : texture(plane1Texture, texCoord).r;
vec2 UV = texture(plane1Texture, texCoord).ga;
fragColor = ubuf.colorMatrix * vec4(Y, UV, 1.0) * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/shaders/yvu_triplanar.frag b/src/multimedia/shaders/yvu_triplanar.frag
index edd9947e3..ac2cbdf63 100644
--- a/src/multimedia/shaders/yvu_triplanar.frag
+++ b/src/multimedia/shaders/yvu_triplanar.frag
@@ -1,15 +1,12 @@
#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+#include "colortransfer.glsl"
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
-layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- mat4 colorMatrix;
- float opacity;
- float width;
-} ubuf;
-
layout(binding = 1) uniform sampler2D plane1Texture;
layout(binding = 2) uniform sampler2D plane2Texture;
layout(binding = 3) uniform sampler2D plane3Texture;
@@ -21,4 +18,12 @@ void main()
float U = texture(plane3Texture, texCoord).r;
vec4 color = vec4(Y, U, V, 1.);
fragColor = ubuf.colorMatrix * color * ubuf.opacity;
+
+#ifdef QMM_OUTPUTSURFACE_LINEAR
+ fragColor = convertSRGBToLinear(fragColor);
+#endif
+
+ // Clamp output to valid range to account for out-of-range
+ // input values and numerical inaccuracies in YUV->RGB conversion
+ fragColor = clamp(fragColor, 0.0, 1.0);
}
diff --git a/src/multimedia/video/qabstractvideobuffer.cpp b/src/multimedia/video/qabstractvideobuffer.cpp
index b97a28fe1..d65438855 100644
--- a/src/multimedia/video/qabstractvideobuffer.cpp
+++ b/src/multimedia/video/qabstractvideobuffer.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qabstractvideobuffer_p.h"
#include <qvariant.h>
+#include <rhi/qrhi.h>
#include <QDebug>
@@ -114,7 +79,7 @@ QT_BEGIN_NAMESPACE
*/
QAbstractVideoBuffer::QAbstractVideoBuffer(QVideoFrame::HandleType type, QRhi *rhi)
: m_type(type),
- rhi(rhi)
+ m_rhi(rhi)
{
}
@@ -135,6 +100,14 @@ QVideoFrame::HandleType QAbstractVideoBuffer::handleType() const
return m_type;
}
+/*!
+ Returns the QRhi instance.
+*/
+QRhi *QAbstractVideoBuffer::rhi() const
+{
+ return m_rhi;
+}
+
/*! \fn uchar *QAbstractVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
Independently maps the planes of a video buffer to memory.
diff --git a/src/multimedia/video/qabstractvideobuffer_p.h b/src/multimedia/video/qabstractvideobuffer_p.h
index 1d48a8f24..2004e25f7 100644
--- a/src/multimedia/video/qabstractvideobuffer_p.h
+++ b/src/multimedia/video/qabstractvideobuffer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 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 QABSTRACTVIDEOBUFFER_H
#define QABSTRACTVIDEOBUFFER_H
@@ -55,12 +19,24 @@
#include <QtMultimedia/qvideoframe.h>
#include <QtCore/qmetatype.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/private/qglobal_p.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
class QVariant;
class QRhi;
+class QRhiTexture;
+
+class Q_MULTIMEDIA_EXPORT QVideoFrameTextures
+{
+public:
+ virtual ~QVideoFrameTextures() {}
+ virtual QRhiTexture *texture(uint plane) const = 0;
+};
class Q_MULTIMEDIA_EXPORT QAbstractVideoBuffer
{
@@ -69,6 +45,7 @@ public:
virtual ~QAbstractVideoBuffer();
QVideoFrame::HandleType handleType() const;
+ QRhi *rhi() const;
struct MapData
{
@@ -82,12 +59,15 @@ public:
virtual MapData map(QVideoFrame::MapMode mode) = 0;
virtual void unmap() = 0;
- virtual void mapTextures() {}
- virtual quint64 textureHandle(int /*plane*/) const { return 0; }
+ virtual std::unique_ptr<QVideoFrameTextures> mapTextures(QRhi *) { return {}; }
+ virtual quint64 textureHandle(QRhi *, int /*plane*/) const { return 0; }
+
+ virtual QMatrix4x4 externalTextureMatrix() const { return {}; }
+ virtual QByteArray underlyingByteArray(int /*plane*/) const { return {}; }
protected:
QVideoFrame::HandleType m_type;
- QRhi *rhi = nullptr;
+ QRhi *m_rhi = nullptr;
private:
Q_DISABLE_COPY(QAbstractVideoBuffer)
diff --git a/src/multimedia/video/qimagevideobuffer.cpp b/src/multimedia/video/qimagevideobuffer.cpp
new file mode 100644
index 000000000..bc825004e
--- /dev/null
+++ b/src/multimedia/video/qimagevideobuffer.cpp
@@ -0,0 +1,90 @@
+// 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 "qimagevideobuffer_p.h"
+#include "qvideoframeformat.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+QImage::Format fixImageFormat(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::Format_RGBA8888_Premultiplied:
+ case QImage::Format_A2BGR30_Premultiplied:
+ case QImage::Format_A2RGB30_Premultiplied:
+ case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ return QImage::Format_ARGB32_Premultiplied;
+ case QImage::Format_ARGB32:
+ case QImage::Format_RGBA8888:
+ case QImage::Format_Alpha8:
+ case QImage::Format_RGBA64:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA32FPx4:
+ return QImage::Format_ARGB32;
+ case QImage::Format_Invalid:
+ return QImage::Format_Invalid;
+ default:
+ return QImage::Format_RGB32;
+ }
+}
+
+QImage fixImage(QImage image)
+{
+ if (image.format() == QImage::Format_Invalid)
+ return image;
+
+ const auto frameFormat = QVideoFrameFormat::pixelFormatFromImageFormat(image.format());
+ if (frameFormat != QVideoFrameFormat::Format_Invalid)
+ return image;
+
+ return image.convertToFormat(fixImageFormat(image.format()));
+}
+
+} // namespace
+
+QImageVideoBuffer::QImageVideoBuffer(QImage image)
+ : QAbstractVideoBuffer(QVideoFrame::NoHandle), m_image(fixImage(std::move(image)))
+{
+}
+
+QVideoFrame::MapMode QImageVideoBuffer::mapMode() const
+{
+ return m_mapMode;
+}
+
+QAbstractVideoBuffer::MapData QImageVideoBuffer::map(QVideoFrame::MapMode mode)
+{
+ MapData mapData;
+ if (m_mapMode == QVideoFrame::NotMapped && !m_image.isNull()
+ && mode != QVideoFrame::NotMapped) {
+ m_mapMode = mode;
+
+ mapData.nPlanes = 1;
+ mapData.bytesPerLine[0] = m_image.bytesPerLine();
+ mapData.data[0] = m_image.bits();
+ mapData.size[0] = m_image.sizeInBytes();
+ }
+
+ return mapData;
+}
+
+void QImageVideoBuffer::unmap()
+{
+ m_mapMode = QVideoFrame::NotMapped;
+}
+
+QImage QImageVideoBuffer::underlyingImage() const
+{
+ return m_image;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/video/qimagevideobuffer_p.h b/src/multimedia/video/qimagevideobuffer_p.h
new file mode 100644
index 000000000..e5467563a
--- /dev/null
+++ b/src/multimedia/video/qimagevideobuffer_p.h
@@ -0,0 +1,43 @@
+// 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 QIMAGEVIDEOBUFFER_P_H
+#define QIMAGEVIDEOBUFFER_P_H
+
+#include <private/qabstractvideobuffer_p.h>
+#include <qimage.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 Q_MULTIMEDIA_EXPORT QImageVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ QImageVideoBuffer(QImage image);
+
+ QVideoFrame::MapMode mapMode() const override;
+
+ MapData map(QVideoFrame::MapMode mode) override;
+
+ void unmap() override;
+
+ QImage underlyingImage() const;
+
+private:
+ QVideoFrame::MapMode m_mapMode = QVideoFrame::NotMapped;
+ QImage m_image;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIMAGEVIDEOBUFFER_P_H
diff --git a/src/multimedia/video/qmemoryvideobuffer.cpp b/src/multimedia/video/qmemoryvideobuffer.cpp
index 8bb3eae17..bcbbe7e59 100644
--- a/src/multimedia/video/qmemoryvideobuffer.cpp
+++ b/src/multimedia/video/qmemoryvideobuffer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qmemoryvideobuffer_p.h"
@@ -53,11 +17,11 @@ QT_BEGIN_NAMESPACE
/*!
Constructs a video buffer with an image stride of \a bytesPerLine from a byte \a array.
*/
-QMemoryVideoBuffer::QMemoryVideoBuffer(const QByteArray &array, int bytesPerLine)
- : QAbstractVideoBuffer(QVideoFrame::NoHandle)
+QMemoryVideoBuffer::QMemoryVideoBuffer(QByteArray data, int bytesPerLine)
+ : QAbstractVideoBuffer(QVideoFrame::NoHandle),
+ m_bytesPerLine(bytesPerLine),
+ m_data(std::move(data))
{
- data = array;
- this->bytesPerLine = bytesPerLine;
}
/*!
@@ -79,13 +43,18 @@ QVideoFrame::MapMode QMemoryVideoBuffer::mapMode() const
QAbstractVideoBuffer::MapData QMemoryVideoBuffer::map(QVideoFrame::MapMode mode)
{
MapData mapData;
- if (m_mapMode == QVideoFrame::NotMapped && data.size() && mode != QVideoFrame::NotMapped) {
+ if (m_mapMode == QVideoFrame::NotMapped && m_data.size() && mode != QVideoFrame::NotMapped) {
m_mapMode = mode;
mapData.nPlanes = 1;
- mapData.bytesPerLine[0] = bytesPerLine;
- mapData.data[0] = reinterpret_cast<uchar *>(data.data());
- mapData.size[0] = data.size();
+ mapData.bytesPerLine[0] = m_bytesPerLine;
+ // avoid detaching and extra copying in case the underlyingByteArray is
+ // being held by textures or anything else.
+ if (mode == QVideoFrame::ReadOnly)
+ mapData.data[0] = reinterpret_cast<uchar *>(const_cast<char*>(m_data.constData()));
+ else
+ mapData.data[0] = reinterpret_cast<uchar *>(m_data.data());
+ mapData.size[0] = m_data.size();
}
return mapData;
@@ -99,4 +68,12 @@ 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 078b1af26..ec97abd4f 100644
--- a/src/multimedia/video/qmemoryvideobuffer_p.h
+++ b/src/multimedia/video/qmemoryvideobuffer_p.h
@@ -1,47 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QMEMORYVIDEOBUFFER_P_H
#define QMEMORYVIDEOBUFFER_P_H
#include <private/qabstractvideobuffer_p.h>
-#include <qvideoframe.h>
//
// W A R N I N G
@@ -59,7 +22,7 @@ QT_BEGIN_NAMESPACE
class Q_MULTIMEDIA_EXPORT QMemoryVideoBuffer : public QAbstractVideoBuffer
{
public:
- QMemoryVideoBuffer(const QByteArray &data, int bytesPerLine);
+ QMemoryVideoBuffer(QByteArray data, int bytesPerLine);
~QMemoryVideoBuffer();
QVideoFrame::MapMode mapMode() const override;
@@ -67,9 +30,11 @@ public:
MapData map(QVideoFrame::MapMode mode) override;
void unmap() override;
- int bytesPerLine = 0;
+ QByteArray underlyingByteArray(int plane) const override;
+private:
+ int m_bytesPerLine = 0;
QVideoFrame::MapMode m_mapMode = QVideoFrame::NotMapped;
- QByteArray data;
+ QByteArray m_data;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qtvideo.cpp b/src/multimedia/video/qtvideo.cpp
new file mode 100644
index 000000000..29747b776
--- /dev/null
+++ b/src/multimedia/video/qtvideo.cpp
@@ -0,0 +1,30 @@
+// 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 "qtvideo.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \namespace QtVideo
+ \since 6.7
+ \inmodule QtMultimedia
+ \brief Enumerations for camera and video functionality.
+*/
+
+/*!
+ \enum QtVideo::Rotation
+ \since 6.7
+
+ The angle of the clockwise rotation that should be applied to a video
+ frame before displaying.
+
+ \value None No rotation required, the frame has correct orientation
+ \value Clockwise90 The frame should be rotated clockwise by 90 degrees
+ \value Clockwise180 The frame should be rotated clockwise by 180 degrees
+ \value Clockwise270 The frame should be rotated clockwise by 270 degrees
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qtvideo.cpp"
diff --git a/src/multimedia/video/qtvideo.h b/src/multimedia/video/qtvideo.h
new file mode 100644
index 000000000..a5f22ea2c
--- /dev/null
+++ b/src/multimedia/video/qtvideo.h
@@ -0,0 +1,23 @@
+// 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 QTVIDEO_H
+#define QTVIDEO_H
+
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/qtconfigmacros.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtVideo
+{
+Q_NAMESPACE_EXPORT(Q_MULTIMEDIA_EXPORT)
+
+enum class Rotation { None = 0, Clockwise90 = 90, Clockwise180 = 180, Clockwise270 = 270 };
+Q_ENUM_NS(Rotation)
+}
+
+QT_END_NAMESPACE
+
+#endif // QTVIDEO_H
diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp
index a3003d0c9..90560f506 100644
--- a/src/multimedia/video/qvideoframe.cpp
+++ b/src/multimedia/video/qvideoframe.cpp
@@ -1,127 +1,26 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qvideoframe.h"
+#include "qvideoframe_p.h"
#include "qvideotexturehelper_p.h"
+#include "qmultimediautils_p.h"
#include "qmemoryvideobuffer_p.h"
-#include "qvideoframeconversionhelper_p.h"
-#include "qvideoframeformat.h"
+#include "qvideoframeconverter_p.h"
+#include "qimagevideobuffer_p.h"
#include "qpainter.h"
#include <qtextlayout.h>
#include <qimage.h>
-#include <qmutex.h>
#include <qpair.h>
#include <qsize.h>
#include <qvariant.h>
-#include <private/qrhi_p.h>
+#include <rhi/qrhi.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
-static bool pixelFormatHasAlpha[QVideoFrameFormat::NPixelFormats] =
-{
- false, //Format_Invalid,
- true, //Format_ARGB32,
- true, //Format_ARGB32_Premultiplied,
- false, //Format_XRGB32,
- true, //Format_BGRA32,
- true, //Format_BGRA32_Premultiplied,
- false, //Format_BGRX32,
- true, //Format_ABGR32,
- false, //Format_XBGR32,
- true, //Format_RGBA32,
- false, //Format_RGBX32,
-
- true, //Format_AYUV,
- true, //Format_AYUV_Premultiplied,
- false, //Format_YUV420P,
- false, //Format_YUV422P,
- false, //Format_YV12,
- false, //Format_UYVY,
- false, //Format_YUYV,
- false, //Format_NV12,
- false, //Format_NV21,
- false, //Format_IMC1,
- false, //Format_IMC2,
- false, //Format_IMC3,
- false, //Format_IMC4,
- false, //Format_Y8,
- false, //Format_Y16,
-
- false, //Format_P010,
- false, //Format_P016,
-
- false, //Format_SamplerExternalOES
- false, //Format_Jpeg,
- false, //Format_SamplerRect
-
-};
-
-
-class QVideoFramePrivate : public QSharedData
-{
-public:
- QVideoFramePrivate() = default;
- QVideoFramePrivate(const QVideoFrameFormat &format)
- : format(format)
- {
- }
-
- ~QVideoFramePrivate()
- {
- delete buffer;
- }
-
- qint64 startTime = -1;
- qint64 endTime = -1;
- QAbstractVideoBuffer::MapData mapData;
- QVideoFrameFormat format;
- QAbstractVideoBuffer *buffer = nullptr;
- int mappedCount = 0;
- QMutex mapMutex;
- QString subtitleText;
-
-private:
- Q_DISABLE_COPY(QVideoFramePrivate)
-};
QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFramePrivate);
@@ -166,7 +65,6 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFramePrivate);
Constructs a null video frame.
*/
QVideoFrame::QVideoFrame()
- : d(new QVideoFramePrivate)
{
}
@@ -179,7 +77,7 @@ QVideoFrame::QVideoFrame()
QVideoFrame::QVideoFrame(QAbstractVideoBuffer *buffer, const QVideoFrameFormat &format)
: d(new QVideoFramePrivate(format))
{
- d->buffer = buffer;
+ d->buffer.reset(buffer);
}
/*!
@@ -187,7 +85,7 @@ QVideoFrame::QVideoFrame(QAbstractVideoBuffer *buffer, const QVideoFrameFormat &
*/
QAbstractVideoBuffer *QVideoFrame::videoBuffer() const
{
- return d ? d->buffer : nullptr;
+ return d ? d->buffer.get() : nullptr;
}
/*!
@@ -205,11 +103,53 @@ QVideoFrame::QVideoFrame(const QVideoFrameFormat &format)
// Check the memory was successfully allocated.
if (!data.isEmpty())
- d->buffer = new QMemoryVideoBuffer(data, textureDescription->strideForWidth(format.frameWidth()));
+ d->buffer = std::make_unique<QMemoryVideoBuffer>(data, textureDescription->strideForWidth(format.frameWidth()));
}
}
/*!
+ Constructs a QVideoFrame from a QImage. The QImage pixels are copied
+ into the QVideoFrame's memory buffer. The resulting frame has the
+ same size as the QImage, but the number of bytes per line may
+ differ.
+
+ If the QImage::Format matches one of the formats in
+ QVideoFrameFormat::PixelFormat, the QVideoFrame will use that format
+ without any pixel format conversion. Otherwise, the image is first
+ converted to a supported (A)RGB format using QImage::convertedTo()
+ with the Qt::AutoColor flag. This may incur a performance penalty.
+
+ If QImage::isNull() evaluates to true for the input QImage, the
+ QVideoFrame will be invalid and QVideoFrameFormat::isValid() will
+ return false.
+
+ \sa QVideoFrameFormat::pixelFormatFromImageFormat()
+ \sa QImage::convertedTo()
+ \sa QImage::isNull()
+*/
+QVideoFrame::QVideoFrame(const QImage &image)
+{
+ auto buffer = std::make_unique<QImageVideoBuffer>(image);
+
+ // If the QImage::Format is not convertible to QVideoFrameFormat,
+ // QImageVideoBuffer automatically converts image to a compatible
+ // (A)RGB format.
+ const QImage &bufferImage = buffer->underlyingImage();
+
+ if (bufferImage.isNull())
+ return;
+
+ // `bufferImage` is now supported by QVideoFrameFormat::pixelFormatFromImageFormat()
+ QVideoFrameFormat format = {
+ bufferImage.size(), QVideoFrameFormat::pixelFormatFromImageFormat(bufferImage.format())
+ };
+
+ Q_ASSERT(format.isValid());
+
+ d = new QVideoFramePrivate{ std::move(format), std::move(buffer) };
+}
+
+/*!
Constructs a shallow copy of \a other. Since QVideoFrame is
explicitly shared, these two instances will reflect the same frame.
@@ -223,6 +163,12 @@ QVideoFrame::QVideoFrame(const QVideoFrame &other) = default;
*/
/*!
+ \fn void QVideoFrame::swap(QVideoFrame &other) noexcept
+
+ Swaps the current video frame with \a other.
+*/
+
+/*!
\fn QVideoFrame &QVideoFrame::operator=(QVideoFrame &&other)
Moves \a other into this QVideoFrame.
@@ -266,7 +212,7 @@ QVideoFrame::~QVideoFrame() = default;
*/
bool QVideoFrame::isValid() const
{
- return d->buffer != nullptr && d->format.pixelFormat() != QVideoFrameFormat::Format_Invalid;
+ return (d && d->buffer) && d->format.pixelFormat() != QVideoFrameFormat::Format_Invalid;
}
/*!
@@ -274,7 +220,7 @@ bool QVideoFrame::isValid() const
*/
QVideoFrameFormat::PixelFormat QVideoFrame::pixelFormat() const
{
- return d->format.pixelFormat();
+ return d ? d->format.pixelFormat() : QVideoFrameFormat::Format_Invalid;
}
/*!
@@ -282,7 +228,7 @@ QVideoFrameFormat::PixelFormat QVideoFrame::pixelFormat() const
*/
QVideoFrameFormat QVideoFrame::surfaceFormat() const
{
- return d->format;
+ return d ? d->format : QVideoFrameFormat{};
}
/*!
@@ -293,7 +239,7 @@ QVideoFrameFormat QVideoFrame::surfaceFormat() const
*/
QVideoFrame::HandleType QVideoFrame::handleType() const
{
- return d->buffer ? d->buffer->handleType() : QVideoFrame::NoHandle;
+ return (d && d->buffer) ? d->buffer->handleType() : QVideoFrame::NoHandle;
}
/*!
@@ -301,7 +247,7 @@ QVideoFrame::HandleType QVideoFrame::handleType() const
*/
QSize QVideoFrame::size() const
{
- return d->format.frameSize();
+ return d ? d->format.frameSize() : QSize();
}
/*!
@@ -334,7 +280,7 @@ int QVideoFrame::height() const
bool QVideoFrame::isMapped() const
{
- return d->buffer != nullptr && d->buffer->mapMode() != QVideoFrame::NotMapped;
+ return d && d->buffer && d->buffer->mapMode() != QVideoFrame::NotMapped;
}
/*!
@@ -353,7 +299,7 @@ bool QVideoFrame::isMapped() const
*/
bool QVideoFrame::isWritable() const
{
- return d->buffer != nullptr && (d->buffer->mapMode() & QVideoFrame::WriteOnly);
+ return d && d->buffer && (d->buffer->mapMode() & QVideoFrame::WriteOnly);
}
/*!
@@ -369,7 +315,7 @@ bool QVideoFrame::isWritable() const
*/
bool QVideoFrame::isReadable() const
{
- return d->buffer != nullptr && (d->buffer->mapMode() & QVideoFrame::ReadOnly);
+ return d && d->buffer && (d->buffer->mapMode() & QVideoFrame::ReadOnly);
}
/*!
@@ -379,7 +325,7 @@ bool QVideoFrame::isReadable() const
*/
QVideoFrame::MapMode QVideoFrame::mapMode() const
{
- return d->buffer != nullptr ? d->buffer->mapMode() : QVideoFrame::NotMapped;
+ return (d && d->buffer) ? d->buffer->mapMode() : QVideoFrame::NotMapped;
}
/*!
@@ -414,11 +360,11 @@ QVideoFrame::MapMode QVideoFrame::mapMode() const
*/
bool QVideoFrame::map(QVideoFrame::MapMode mode)
{
- QMutexLocker lock(&d->mapMutex);
- if (!d->buffer)
+ if (!d || !d->buffer)
return false;
+ QMutexLocker lock(&d->mapMutex);
if (mode == QVideoFrame::NotMapped)
return false;
@@ -469,6 +415,7 @@ bool QVideoFrame::map(QVideoFrame::MapMode mode)
// Single plane or opaque format.
break;
case QVideoFrameFormat::Format_YUV420P:
+ case QVideoFrameFormat::Format_YUV420P10:
case QVideoFrameFormat::Format_YUV422P:
case QVideoFrameFormat::Format_YV12: {
// The UV stride is usually half the Y stride and is 32-bit aligned.
@@ -523,6 +470,15 @@ bool QVideoFrame::map(QVideoFrame::MapMode mode)
}
d->mappedCount++;
+
+ // unlock mapMutex to avoid potential deadlock imageMutex <--> mapMutex
+ lock.unlock();
+
+ if ((mode & QVideoFrame::WriteOnly) != 0) {
+ QMutexLocker lock(&d->imageMutex);
+ d->image = {};
+ }
+
return true;
}
@@ -538,11 +494,11 @@ bool QVideoFrame::map(QVideoFrame::MapMode mode)
*/
void QVideoFrame::unmap()
{
- QMutexLocker lock(&d->mapMutex);
-
- if (!d->buffer)
+ if (!d || !d->buffer)
return;
+ QMutexLocker lock(&d->mapMutex);
+
if (d->mappedCount == 0) {
qWarning() << "QVideoFrame::unmap() was called more times then QVideoFrame::map()";
return;
@@ -567,6 +523,8 @@ void QVideoFrame::unmap()
int QVideoFrame::bytesPerLine(int plane) const
{
+ if (!d)
+ return 0;
return plane >= 0 && plane < d->mapData.nPlanes ? d->mapData.bytesPerLine[plane] : 0;
}
@@ -584,6 +542,8 @@ int QVideoFrame::bytesPerLine(int plane) const
*/
uchar *QVideoFrame::bits(int plane)
{
+ if (!d)
+ return nullptr;
return plane >= 0 && plane < d->mapData.nPlanes ? d->mapData.data[plane] : nullptr;
}
@@ -600,6 +560,8 @@ uchar *QVideoFrame::bits(int plane)
*/
const uchar *QVideoFrame::bits(int plane) const
{
+ if (!d)
+ return nullptr;
return plane >= 0 && plane < d->mapData.nPlanes ? d->mapData.data[plane] : nullptr;
}
@@ -612,6 +574,8 @@ const uchar *QVideoFrame::bits(int plane) const
*/
int QVideoFrame::mappedBytes(int plane) const
{
+ if (!d)
+ return 0;
return plane >= 0 && plane < d->mapData.nPlanes ? d->mapData.size[plane] : 0;
}
@@ -624,19 +588,9 @@ int QVideoFrame::mappedBytes(int plane) const
int QVideoFrame::planeCount() const
{
- return d->format.planeCount();
-}
-
-/*!
- \internal
- Returns a texture id to the video frame's buffers.
-*/
-quint64 QVideoFrame::textureHandle(int plane) const
-{
- if (!d->buffer)
+ if (!d)
return 0;
- d->buffer->mapTextures();
- return d->buffer->textureHandle(plane);
+ return d->format.planeCount();
}
/*!
@@ -647,6 +601,8 @@ quint64 QVideoFrame::textureHandle(int plane) const
*/
qint64 QVideoFrame::startTime() const
{
+ if (!d)
+ return -1;
return d->startTime;
}
@@ -658,6 +614,8 @@ qint64 QVideoFrame::startTime() const
*/
void QVideoFrame::setStartTime(qint64 time)
{
+ if (!d)
+ return;
d->startTime = time;
}
@@ -669,6 +627,8 @@ void QVideoFrame::setStartTime(qint64 time)
*/
qint64 QVideoFrame::endTime() const
{
+ if (!d)
+ return -1;
return d->endTime;
}
@@ -680,9 +640,75 @@ qint64 QVideoFrame::endTime() const
*/
void QVideoFrame::setEndTime(qint64 time)
{
+ if (!d)
+ return;
d->endTime = time;
}
+#if QT_DEPRECATED_SINCE(6, 7)
+/*!
+ \enum QVideoFrame::RotationAngle
+ \deprecated [6.7] Use QtVideo::Rotation instead.
+
+ The angle of the clockwise rotation that should be applied to a video
+ frame before displaying.
+
+ \value Rotation0 No rotation required, the frame has correct orientation
+ \value Rotation90 The frame should be rotated by 90 degrees
+ \value Rotation180 The frame should be rotated by 180 degrees
+ \value Rotation270 The frame should be rotated by 270 degrees
+*/
+
+/*!
+ \fn void QVideoFrame::setRotationAngle(RotationAngle)
+ \deprecated [6.7] Use \c QVideoFrame::setRotation instead.
+
+ Sets the \a angle the frame should be rotated clockwise before displaying.
+*/
+
+/*!
+ \fn QVideoFrame::RotationAngle QVideoFrame::rotationAngle() const
+ \deprecated [6.7] Use \c QVideoFrame::rotation instead.
+
+ Returns the angle the frame should be rotated clockwise before displaying.
+*/
+
+#endif
+
+
+/*!
+ Sets the \a angle the frame should be rotated clockwise before displaying.
+*/
+void QVideoFrame::setRotation(QtVideo::Rotation angle)
+{
+ if (d)
+ d->rotation = angle;
+}
+
+/*!
+ Returns the angle the frame should be rotated clockwise before displaying.
+ */
+QtVideo::Rotation QVideoFrame::rotation() const
+{
+ return QtVideo::Rotation(d ? d->rotation : QtVideo::Rotation::None);
+}
+
+/*!
+ Sets the \a mirrored flag for the frame.
+*/
+void QVideoFrame::setMirrored(bool mirrored)
+{
+ if (d)
+ d->mirrored = mirrored;
+}
+
+/*!
+ Returns whether the frame should be mirrored before displaying.
+*/
+bool QVideoFrame::mirrored() const
+{
+ return d && d->mirrored;
+}
/*!
Based on the pixel format converts current video frame to image.
@@ -690,32 +716,17 @@ void QVideoFrame::setEndTime(qint64 time)
*/
QImage QVideoFrame::toImage() const
{
- QVideoFrame frame = *this;
- QImage result;
-
- if (!frame.isValid() || !frame.map(QVideoFrame::ReadOnly))
- return result;
+ if (!isValid())
+ return {};
- if (frame.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
- // Load from JPG
- result.loadFromData(frame.bits(0), frame.mappedBytes(0), "JPG");
- }
+ QMutexLocker lock(&d->imageMutex);
- // Need conversion
- else {
- VideoFrameConvertFunc convert = qConverterForFormat(frame.pixelFormat());
- if (!convert) {
- qWarning() << Q_FUNC_INFO << ": unsupported pixel format" << frame.pixelFormat();
- } else {
- auto format = pixelFormatHasAlpha[frame.pixelFormat()] ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
- result = QImage(frame.width(), frame.height(), format);
- convert(frame, result.bits());
- }
+ if (d->image.isNull()) {
+ const bool mirrorY = surfaceFormat().scanLineDirection() != QVideoFrameFormat::TopToBottom;
+ d->image = qImageFromVideoFrame(*this, rotation(), mirrored(), mirrorY);
}
- frame.unmap();
-
- return result;
+ return d->image;
}
/*!
@@ -723,7 +734,7 @@ QImage QVideoFrame::toImage() const
*/
QString QVideoFrame::subtitleText() const
{
- return d->subtitleText;
+ return d ? d->subtitleText : QString();
}
/*!
@@ -731,6 +742,8 @@ QString QVideoFrame::subtitleText() const
*/
void QVideoFrame::setSubtitleText(const QString &text)
{
+ if (!d)
+ return;
d->subtitleText = text;
}
@@ -749,14 +762,12 @@ void QVideoFrame::paint(QPainter *painter, const QRectF &rect, const PaintOption
return;
}
- QVideoFrameFormat::Direction scanLineDirection = QVideoFrameFormat::TopToBottom;//format.scanLineDirection();
- bool mirrored = false;//format.isMirrored();
-
- QSizeF size = this->size();
- QRectF source = QRectF(0, 0, size.width(), size.height());
QRectF targetRect = rect;
+ QSizeF size = qRotatedFrameSize(*this);
+
+ size.scale(targetRect.size(), options.aspectRatioMode);
+
if (options.aspectRatioMode == Qt::KeepAspectRatio) {
- size.scale(targetRect.size(), Qt::KeepAspectRatio);
targetRect = QRect(0, 0, size.width(), size.height());
targetRect.moveCenter(rect.center());
// we might not be drawing every pixel, fill the leftovers black
@@ -778,33 +789,16 @@ void QVideoFrame::paint(QPainter *painter, const QRectF &rect, const PaintOption
painter->fillRect(top, Qt::black);
}
}
- } else if (options.aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
- QSizeF targetSize = targetRect.size();
- targetSize.scale(size, Qt::KeepAspectRatio);
-
- QRectF s(0, 0, targetSize.width(), targetSize.height());
- s.moveCenter(source.center());
- source = s;
}
if (map(QVideoFrame::ReadOnly)) {
- QImage image = toImage();
-
const QTransform oldTransform = painter->transform();
QTransform transform = oldTransform;
- if (scanLineDirection == QVideoFrameFormat::BottomToTop) {
- transform.scale(1, -1);
- transform.translate(0, -targetRect.bottom());
- targetRect = QRectF(targetRect.x(), 0, targetRect.width(), targetRect.height());
- }
-
- if (mirrored) {
- transform.scale(-1, 1);
- transform.translate(-targetRect.right(), 0);
- targetRect = QRectF(0, targetRect.y(), targetRect.width(), targetRect.height());
- }
+ transform.translate(targetRect.center().x() - size.width()/2,
+ targetRect.center().y() - size.height()/2);
painter->setTransform(transform);
- painter->drawImage(targetRect, image, source);
+ QImage image = toImage();
+ painter->drawImage({{}, size}, image, {{},image.size()});
painter->setTransform(oldTransform);
unmap();
@@ -822,8 +816,8 @@ void QVideoFrame::paint(QPainter *painter, const QRectF &rect, const PaintOption
text.replace(QLatin1Char('\n'), QChar::LineSeparator);
QVideoTextureHelper::SubtitleLayout layout;
- layout.updateFromVideoFrame(*this);
- layout.draw(painter, targetRect);
+ layout.update(targetRect.size().toSize(), this->subtitleText());
+ layout.draw(painter, targetRect.topLeft());
}
#ifndef QT_NO_DEBUG_STREAM
@@ -845,12 +839,12 @@ static QString qFormatTimeStamps(qint64 start, qint64 end)
if (onlyOne) {
if (start > 0)
- return QString::fromLatin1("@%1:%2:%3.%4")
+ return QStringLiteral("@%1:%2:%3.%4")
.arg(start, 1, 10, QLatin1Char('0'))
.arg(s_minutes, 2, 10, QLatin1Char('0'))
.arg(s_seconds, 2, 10, QLatin1Char('0'))
.arg(s_millis, 2, 10, QLatin1Char('0'));
- return QString::fromLatin1("@%1:%2.%3")
+ return QStringLiteral("@%1:%2.%3")
.arg(s_minutes, 2, 10, QLatin1Char('0'))
.arg(s_seconds, 2, 10, QLatin1Char('0'))
.arg(s_millis, 2, 10, QLatin1Char('0'));
@@ -859,12 +853,12 @@ static QString qFormatTimeStamps(qint64 start, qint64 end)
if (end == -1) {
// Similar to start-start, except it means keep displaying it?
if (start > 0)
- return QString::fromLatin1("%1:%2:%3.%4 - forever")
+ return QStringLiteral("%1:%2:%3.%4 - forever")
.arg(start, 1, 10, QLatin1Char('0'))
.arg(s_minutes, 2, 10, QLatin1Char('0'))
.arg(s_seconds, 2, 10, QLatin1Char('0'))
.arg(s_millis, 2, 10, QLatin1Char('0'));
- return QString::fromLatin1("%1:%2.%3 - forever")
+ return QStringLiteral("%1:%2.%3 - forever")
.arg(s_minutes, 2, 10, QLatin1Char('0'))
.arg(s_seconds, 2, 10, QLatin1Char('0'))
.arg(s_millis, 2, 10, QLatin1Char('0'));
@@ -878,7 +872,7 @@ static QString qFormatTimeStamps(qint64 start, qint64 end)
end /= 60;
if (start > 0 || end > 0)
- return QString::fromLatin1("%1:%2:%3.%4 - %5:%6:%7.%8")
+ return QStringLiteral("%1:%2:%3.%4 - %5:%6:%7.%8")
.arg(start, 1, 10, QLatin1Char('0'))
.arg(s_minutes, 2, 10, QLatin1Char('0'))
.arg(s_seconds, 2, 10, QLatin1Char('0'))
@@ -887,7 +881,7 @@ static QString qFormatTimeStamps(qint64 start, qint64 end)
.arg(e_minutes, 2, 10, QLatin1Char('0'))
.arg(e_seconds, 2, 10, QLatin1Char('0'))
.arg(e_millis, 2, 10, QLatin1Char('0'));
- return QString::fromLatin1("%1:%2.%3 - %4:%5.%6")
+ return QStringLiteral("%1:%2.%3 - %4:%5.%6")
.arg(s_minutes, 2, 10, QLatin1Char('0'))
.arg(s_seconds, 2, 10, QLatin1Char('0'))
.arg(s_millis, 2, 10, QLatin1Char('0'))
diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h
index 2bf2bd5ef..a306162e8 100644
--- a/src/multimedia/video/qvideoframe.h
+++ b/src/multimedia/video/qvideoframe.h
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QVIDEOFRAME_H
#define QVIDEOFRAME_H
#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtMultimedia/qtvideo.h>
#include <QtMultimedia/qvideoframeformat.h>
#include <QtCore/qmetatype.h>
@@ -76,15 +41,26 @@ public:
ReadWrite = ReadOnly | WriteOnly
};
+#if QT_DEPRECATED_SINCE(6, 7)
+ enum RotationAngle
+ {
+ Rotation0 Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::Rotation::None instead") = 0,
+ Rotation90 Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::Rotation::Clockwise90 instead") = 90,
+ Rotation180 Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::Rotation::Clockwise180 instead") = 180,
+ Rotation270 Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::Rotation::Clockwise270 instead") = 270
+ };
+#endif
+
QVideoFrame();
QVideoFrame(const QVideoFrameFormat &format);
+ explicit QVideoFrame(const QImage &image);
QVideoFrame(const QVideoFrame &other);
~QVideoFrame();
QVideoFrame(QVideoFrame &&other) noexcept = default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QVideoFrame)
void swap(QVideoFrame &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
QVideoFrame &operator =(const QVideoFrame &other);
@@ -118,14 +94,26 @@ public:
int mappedBytes(int plane) const;
int planeCount() const;
- quint64 textureHandle(int plane) const;
-
qint64 startTime() const;
void setStartTime(qint64 time);
qint64 endTime() const;
void setEndTime(qint64 time);
+#if QT_DEPRECATED_SINCE(6, 7)
+ QT_DEPRECATED_VERSION_X_6_7("Use QVideoFrame::setRotation(QtVideo::Rotation) instead")
+ void setRotationAngle(RotationAngle angle) { setRotation(QtVideo::Rotation(angle)); }
+
+ QT_DEPRECATED_VERSION_X_6_7("Use QVideoFrame::rotation() instead")
+ RotationAngle rotationAngle() const { return RotationAngle(rotation()); }
+#endif
+
+ void setRotation(QtVideo::Rotation angle);
+ QtVideo::Rotation rotation() const;
+
+ void setMirrored(bool);
+ bool mirrored() const;
+
QImage toImage() const;
struct PaintOptions {
@@ -147,6 +135,7 @@ public:
QAbstractVideoBuffer *videoBuffer() const;
private:
+ friend class QVideoFramePrivate;
QExplicitlySharedDataPointer<QVideoFramePrivate> d;
};
diff --git a/src/multimedia/video/qvideoframe_p.h b/src/multimedia/video/qvideoframe_p.h
new file mode 100644
index 000000000..23457e55c
--- /dev/null
+++ b/src/multimedia/video/qvideoframe_p.h
@@ -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
+
+#ifndef QVIDEOFRAME_P_H
+#define QVIDEOFRAME_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 "qvideoframe.h"
+#include "qabstractvideobuffer_p.h"
+
+#include <qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFramePrivate : public QSharedData
+{
+public:
+ QVideoFramePrivate() = default;
+ QVideoFramePrivate(const QVideoFrameFormat &format) : format(format) { }
+ QVideoFramePrivate(QVideoFrameFormat format, std::unique_ptr<QAbstractVideoBuffer> buffer)
+ : format{ std::move(format) }, buffer{ std::move(buffer) }
+ {
+ }
+
+ static QVideoFramePrivate *handle(QVideoFrame &frame) { return frame.d.get(); };
+
+ QVideoFrame adoptThisByVideoFrame()
+ {
+ QVideoFrame frame;
+ frame.d = QExplicitlySharedDataPointer(this, QAdoptSharedDataTag{});
+ return frame;
+ }
+
+ qint64 startTime = -1;
+ qint64 endTime = -1;
+ QAbstractVideoBuffer::MapData mapData;
+ QVideoFrameFormat format;
+ std::unique_ptr<QAbstractVideoBuffer> buffer;
+ int mappedCount = 0;
+ QMutex mapMutex;
+ QString subtitleText;
+ QtVideo::Rotation rotation = QtVideo::Rotation::None;
+ bool mirrored = false;
+ QImage image;
+ QMutex imageMutex;
+
+private:
+ Q_DISABLE_COPY(QVideoFramePrivate)
+};
+
+QT_END_NAMESPACE
+
+#endif // QVIDEOFRAMEPRIVATE_P_H
diff --git a/src/multimedia/video/qvideoframeconversionhelper.cpp b/src/multimedia/video/qvideoframeconversionhelper.cpp
index d4eb53f88..1b570b74f 100644
--- a/src/multimedia/video/qvideoframeconversionhelper.cpp
+++ b/src/multimedia/video/qvideoframeconversionhelper.cpp
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qvideoframeconversionhelper_p.h"
#include "qrgb.h"
+#include <mutex>
+
QT_BEGIN_NAMESPACE
#define CLAMP(n) (n > 255 ? 255 : (n < 0 ? 0 : n))
@@ -67,6 +33,7 @@ static inline void planarYUV420_to_ARGB32(const uchar *y, int yStride,
quint32 *rgb,
int width, int height)
{
+ height &= ~1;
quint32 *rgb0 = rgb;
quint32 *rgb1 = rgb + width;
@@ -103,7 +70,6 @@ static inline void planarYUV422_to_ARGB32(const uchar *y, int yStride,
int width, int height)
{
quint32 *rgb0 = rgb;
- quint32 *rgb1 = rgb + width;
for (int j = 0; j < height; ++j) {
const uchar *lineY0 = y;
@@ -119,11 +85,10 @@ static inline void planarYUV422_to_ARGB32(const uchar *y, int yStride,
*rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
}
- y += yStride << 1; // stride * 2
+ y += yStride; // stride * 2
u += uStride;
v += vStride;
rgb0 += width;
- rgb1 += width;
}
}
@@ -355,14 +320,15 @@ static void QT_FASTCALL qt_convert_to_ARGB32(const QVideoFrame &frame, uchar *ou
int x = 0;
for (; x < width - 3; x += 4) {
- *argb++ = qPremultiply(data->convert());
- ++data;
- *argb++ = qPremultiply(data->convert());
- ++data;
- *argb++ = qPremultiply(data->convert());
- ++data;
- *argb++ = qPremultiply(data->convert());
- ++data;
+ // Copy 4 pixels onto the stack in one go. This significantly increases performance
+ // in the case where the mapped memory is uncached (because it's a framebuffer)
+ Pixel p[4];
+ memcpy(p, data, 4*sizeof(Pixel));
+ *argb++ = qPremultiply(p[0].convert());
+ *argb++ = qPremultiply(p[1].convert());
+ *argb++ = qPremultiply(p[2].convert());
+ *argb++ = qPremultiply(p[3].convert());
+ data += 4;
}
// leftovers
@@ -388,14 +354,15 @@ static void QT_FASTCALL qt_convert_premultiplied_to_ARGB32(const QVideoFrame &fr
int x = 0;
for (; x < width - 3; x += 4) {
- *argb++ = data->convert();
- ++data;
- *argb++ = data->convert();
- ++data;
- *argb++ = data->convert();
- ++data;
- *argb++ = data->convert();
- ++data;
+ // Copy 4 pixels onto the stack in one go. This significantly increases performance
+ // in the case where the mapped memory is uncached (because it's a framebuffer)
+ Pixel p[4];
+ memcpy(p, data, 4*sizeof(Pixel));
+ *argb++ = p[0].convert();
+ *argb++ = p[1].convert();
+ *argb++ = p[2].convert();
+ *argb++ = p[3].convert();
+ data += 4;
}
// leftovers
@@ -415,6 +382,7 @@ static inline void planarYUV420_16bit_to_ARGB32(const uchar *y, int yStride,
quint32 *rgb,
int width, int height)
{
+ height &= ~1;
quint32 *rgb0 = rgb;
quint32 *rgb1 = rgb + width;
@@ -494,6 +462,14 @@ static void QT_FASTCALL qt_convert_Y_to_ARGB32(const QVideoFrame &frame, uchar *
MERGE_LOOPS(width, height, stride, 1)
}
+template<typename Pixel>
+static void QT_FASTCALL qt_copy_pixels_with_mask(Pixel *dst, const Pixel *src, size_t size,
+ Pixel mask)
+{
+ for (size_t x = 0; x < size; ++x)
+ dst[x] = src[x] | mask;
+}
+
static VideoFrameConvertFunc qConvertFuncs[QVideoFrameFormat::NPixelFormats] = {
/* Format_Invalid */ nullptr, // Not needed
/* Format_ARGB8888 */ qt_convert_to_ARGB32<ARGB8888>,
@@ -526,24 +502,32 @@ static VideoFrameConvertFunc qConvertFuncs[QVideoFrameFormat::NPixelFormats] = {
/* Format_Jpeg */ nullptr, // Not needed
};
-static void qInitConvertFuncsAsm()
+static PixelsCopyFunc qPixelsCopyFunc = qt_copy_pixels_with_mask<uint32_t>;
+
+static std::once_flag InitFuncsAsmFlag;
+
+static void qInitFuncsAsm()
{
#ifdef QT_COMPILER_SUPPORTS_SSE2
extern void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output);
extern void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output);
extern void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output);
extern void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output);
+ extern void QT_FASTCALL qt_copy_pixels_with_mask_sse2(uint32_t * dst, const uint32_t *src, size_t size, uint32_t mask);
+
if (qCpuHasFeature(SSE2)){
qConvertFuncs[QVideoFrameFormat::Format_ARGB8888] = qt_convert_ARGB8888_to_ARGB32_sse2;
qConvertFuncs[QVideoFrameFormat::Format_ARGB8888_Premultiplied] = qt_convert_ARGB8888_to_ARGB32_sse2;
qConvertFuncs[QVideoFrameFormat::Format_XRGB8888] = qt_convert_ARGB8888_to_ARGB32_sse2;
qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_sse2;
qConvertFuncs[QVideoFrameFormat::Format_BGRA8888_Premultiplied] = qt_convert_BGRA8888_to_ARGB32_sse2;
- qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_BGRA8888_to_ARGB32_sse2;
+ qConvertFuncs[QVideoFrameFormat::Format_BGRX8888] = qt_convert_BGRA8888_to_ARGB32_sse2;
qConvertFuncs[QVideoFrameFormat::Format_ABGR8888] = qt_convert_ABGR8888_to_ARGB32_sse2;
qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_ABGR8888_to_ARGB32_sse2;
- qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_sse2;
- qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_sse2;
+ qConvertFuncs[QVideoFrameFormat::Format_RGBA8888] = qt_convert_RGBA8888_to_ARGB32_sse2;
+ qConvertFuncs[QVideoFrameFormat::Format_RGBX8888] = qt_convert_RGBA8888_to_ARGB32_sse2;
+
+ qPixelsCopyFunc = qt_copy_pixels_with_mask_sse2;
}
#endif
#ifdef QT_COMPILER_SUPPORTS_SSSE3
@@ -557,11 +541,11 @@ static void qInitConvertFuncsAsm()
qConvertFuncs[QVideoFrameFormat::Format_XRGB8888] = qt_convert_ARGB8888_to_ARGB32_ssse3;
qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_ssse3;
qConvertFuncs[QVideoFrameFormat::Format_BGRA8888_Premultiplied] = qt_convert_BGRA8888_to_ARGB32_ssse3;
- qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_BGRA8888_to_ARGB32_ssse3;
+ qConvertFuncs[QVideoFrameFormat::Format_BGRX8888] = qt_convert_BGRA8888_to_ARGB32_ssse3;
qConvertFuncs[QVideoFrameFormat::Format_ABGR8888] = qt_convert_ABGR8888_to_ARGB32_ssse3;
qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_ABGR8888_to_ARGB32_ssse3;
- qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_ssse3;
- qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_ssse3;
+ qConvertFuncs[QVideoFrameFormat::Format_RGBA8888] = qt_convert_RGBA8888_to_ARGB32_ssse3;
+ qConvertFuncs[QVideoFrameFormat::Format_RGBX8888] = qt_convert_RGBA8888_to_ARGB32_ssse3;
}
#endif
#ifdef QT_COMPILER_SUPPORTS_AVX2
@@ -569,31 +553,82 @@ static void qInitConvertFuncsAsm()
extern void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output);
extern void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output);
extern void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output);
+ extern void QT_FASTCALL qt_copy_pixels_with_mask_avx2(uint32_t * dst, const uint32_t *src, size_t size, uint32_t mask);
if (qCpuHasFeature(AVX2)){
qConvertFuncs[QVideoFrameFormat::Format_ARGB8888] = qt_convert_ARGB8888_to_ARGB32_avx2;
qConvertFuncs[QVideoFrameFormat::Format_ARGB8888_Premultiplied] = qt_convert_ARGB8888_to_ARGB32_avx2;
qConvertFuncs[QVideoFrameFormat::Format_XRGB8888] = qt_convert_ARGB8888_to_ARGB32_avx2;
qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_avx2;
qConvertFuncs[QVideoFrameFormat::Format_BGRA8888_Premultiplied] = qt_convert_BGRA8888_to_ARGB32_avx2;
- qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_BGRA8888_to_ARGB32_avx2;
+ qConvertFuncs[QVideoFrameFormat::Format_BGRX8888] = qt_convert_BGRA8888_to_ARGB32_avx2;
qConvertFuncs[QVideoFrameFormat::Format_ABGR8888] = qt_convert_ABGR8888_to_ARGB32_avx2;
qConvertFuncs[QVideoFrameFormat::Format_XBGR8888] = qt_convert_ABGR8888_to_ARGB32_avx2;
- qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_avx2;
- qConvertFuncs[QVideoFrameFormat::Format_BGRA8888] = qt_convert_BGRA8888_to_ARGB32_avx2;
+ qConvertFuncs[QVideoFrameFormat::Format_RGBA8888] = qt_convert_RGBA8888_to_ARGB32_avx2;
+ qConvertFuncs[QVideoFrameFormat::Format_RGBX8888] = qt_convert_RGBA8888_to_ARGB32_avx2;
+
+ qPixelsCopyFunc = qt_copy_pixels_with_mask_avx2;
}
#endif
}
VideoFrameConvertFunc qConverterForFormat(QVideoFrameFormat::PixelFormat format)
{
- static bool initAsmFuncsDone = false;
- if (!initAsmFuncsDone) {
- qInitConvertFuncsAsm();
- initAsmFuncsDone = true;
- }
+ std::call_once(InitFuncsAsmFlag, &qInitFuncsAsm);
+
VideoFrameConvertFunc convert = qConvertFuncs[format];
return convert;
}
+void Q_MULTIMEDIA_EXPORT qCopyPixelsWithAlphaMask(uint32_t *dst,
+ const uint32_t *src,
+ size_t pixCount,
+ QVideoFrameFormat::PixelFormat format,
+ bool srcAlphaVaries)
+{
+ if (pixCount == 0)
+ return;
+
+ const auto mask = qAlphaMask(format);
+
+ if (srcAlphaVaries || (src[0] & mask) != mask)
+ qCopyPixelsWithMask(dst, src, pixCount, mask);
+ else
+ memcpy(dst, src, pixCount * 4);
+}
+
+void qCopyPixelsWithMask(uint32_t *dst, const uint32_t *src, size_t size, uint32_t mask)
+{
+ std::call_once(InitFuncsAsmFlag, &qInitFuncsAsm);
+
+ qPixelsCopyFunc(dst, src, size, mask);
+}
+
+uint32_t qAlphaMask(QVideoFrameFormat::PixelFormat format)
+{
+ switch (format) {
+ case QVideoFrameFormat::Format_ARGB8888:
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ case QVideoFrameFormat::Format_XRGB8888:
+ case QVideoFrameFormat::Format_ABGR8888:
+ case QVideoFrameFormat::Format_XBGR8888:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ return 0xff;
+#else
+ return 0xff000000;
+#endif
+ case QVideoFrameFormat::Format_BGRA8888:
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ case QVideoFrameFormat::Format_BGRX8888:
+ case QVideoFrameFormat::Format_RGBA8888:
+ case QVideoFrameFormat::Format_RGBX8888:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ return 0xff000000;
+#else
+ return 0xff;
+#endif
+ default:
+ return 0;
+ }
+}
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp b/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp
index c17f8a6a4..6802cca74 100644
--- a/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp
+++ b/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qvideoframeconversionhelper_p.h"
@@ -72,13 +36,13 @@ void convert_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
3 - a, 3 - r, 3 - g, 3 - b);
#endif
- using Pixel = const RgbPixel<a, r, g, b>;
+ using Pixel = const ArgbPixel<a, r, g, b>;
for (int y = 0; y < height; ++y) {
auto *pixel = reinterpret_cast<const Pixel *>(src);
int x = 0;
- ALIGN(32, argb, x, width) {
+ QT_MEDIA_ALIGN(32, argb, x, width) {
*argb = pixel->convert();
++pixel;
++argb;
@@ -114,21 +78,58 @@ void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_avx2(const QVideoFrame &frame, uc
convert_to_ARGB32_avx2<0, 1, 2, 3>(frame, output);
}
-void qt_convert_ABGR8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_avx2<0, 3, 2, 1>(frame, output);
}
-void qt_convert_RGBA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_avx2<3, 0, 1, 2>(frame, output);
}
-void qt_convert_BGRA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_avx2<3, 2, 1, 0>(frame, output);
}
+void QT_FASTCALL qt_copy_pixels_with_mask_avx2(uint32_t *dst, const uint32_t *src, size_t size, uint32_t mask)
+{
+ const auto mask256 = _mm256_set_epi32(mask, mask, mask, mask, mask, mask, mask, mask);
+
+ size_t x = 0;
+
+ QT_MEDIA_ALIGN(32, dst, x, size)
+ *(dst++) = *(src++) | mask;
+
+ for (; x < size - (8 * 4 + 1); x += 8 * 4) {
+ const auto srcData1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src));
+ const auto srcData2 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src += 8));
+ const auto srcData3 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src += 8));
+ const auto srcData4 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src += 8));
+
+ _mm256_store_si256(reinterpret_cast<__m256i *>(dst), _mm256_or_si256(srcData1, mask256));
+ _mm256_store_si256(reinterpret_cast<__m256i *>(dst += 8), _mm256_or_si256(srcData2, mask256));
+ _mm256_store_si256(reinterpret_cast<__m256i *>(dst += 8), _mm256_or_si256(srcData3, mask256));
+ _mm256_store_si256(reinterpret_cast<__m256i *>(dst += 8), _mm256_or_si256(srcData4, mask256));
+
+ src += 8;
+ dst += 8;
+ }
+
+ // leftovers
+ for (; x < size - 7; x += 8) {
+ const auto srcData = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src));
+ _mm256_store_si256(reinterpret_cast<__m256i *>(dst), _mm256_or_si256(srcData, mask256));
+
+ src += 8;
+ dst += 8;
+ }
+
+ for (; x < size; ++x)
+ *(dst++) = *(src++) | mask;
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/multimedia/video/qvideoframeconversionhelper_p.h b/src/multimedia/video/qvideoframeconversionhelper_p.h
index eeb11f833..17490a817 100644
--- a/src/multimedia/video/qvideoframeconversionhelper_p.h
+++ b/src/multimedia/video/qvideoframeconversionhelper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QVIDEOFRAMECONVERSIONHELPER_P_H
#define QVIDEOFRAMECONVERSIONHELPER_P_H
@@ -58,21 +22,58 @@ QT_BEGIN_NAMESPACE
// Converts to RGB32 or ARGB32_Premultiplied
typedef void (QT_FASTCALL *VideoFrameConvertFunc)(const QVideoFrame &frame, uchar *output);
+typedef void(QT_FASTCALL *PixelsCopyFunc)(uint32_t *dst, const uint32_t *src, size_t size, uint32_t mask);
VideoFrameConvertFunc qConverterForFormat(QVideoFrameFormat::PixelFormat format);
+void Q_MULTIMEDIA_EXPORT qCopyPixelsWithAlphaMask(uint32_t *dst,
+ const uint32_t *src,
+ size_t size,
+ QVideoFrameFormat::PixelFormat format,
+ bool srcAlphaVaries);
+
+void Q_MULTIMEDIA_EXPORT qCopyPixelsWithMask(uint32_t *dst, const uint32_t *src, size_t size, uint32_t mask);
+
+uint32_t Q_MULTIMEDIA_EXPORT qAlphaMask(QVideoFrameFormat::PixelFormat format);
+
template<int a, int r, int g, int b>
-struct RgbPixel
+struct ArgbPixel
{
- uchar data[4];
+ quint32 data;
inline quint32 convert() const
{
- return (a >= 0 ? (uint(data[a]) << 24) : 0xff000000)
- | (uint(data[r]) << 16)
- | (uint(data[g]) << 8)
- | (uint(data[b]));
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ return (((data >> (8*a)) & 0xff) << 24)
+ | (((data >> (8*r)) & 0xff) << 16)
+ | (((data >> (8*g)) & 0xff) << 8)
+ | ((data >> (8*b)) & 0xff);
+#else
+ return (((data >> (32-8*a)) & 0xff) << 24)
+ | (((data >> (32-8*r)) & 0xff) << 16)
+ | (((data >> (32-8*g)) & 0xff) << 8)
+ | ((data >> (32-8*b)) & 0xff);
+#endif
}
+};
+template<int r, int g, int b>
+struct RgbPixel
+{
+ quint32 data;
+ inline quint32 convert() const
+ {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ return 0xff000000
+ | (((data >> (8*r)) & 0xff) << 16)
+ | (((data >> (8*g)) & 0xff) << 8)
+ | ((data >> (8*b)) & 0xff);
+#else
+ return 0xff000000
+ | (((data >> (32-8*r)) & 0xff) << 16)
+ | (((data >> (32-8*g)) & 0xff) << 8)
+ | ((data >> (32-8*b)) & 0xff);
+#endif
+ }
};
template<typename Y>
@@ -92,14 +93,14 @@ struct YPixel
};
-using ARGB8888 = RgbPixel<0, 1, 2, 3>;
-using ABGR8888 = RgbPixel<0, 3, 2, 1>;
-using RGBA8888 = RgbPixel<3, 0, 1, 2>;
-using BGRA8888 = RgbPixel<3, 2, 1, 0>;
-using XRGB8888 = RgbPixel<-1, 1, 2, 3>;
-using XBGR8888 = RgbPixel<-1, 3, 2, 1>;
-using RGBX8888 = RgbPixel<-1, 0, 1, 2>;
-using BGRX8888 = RgbPixel<-1, 2, 1, 0>;
+using ARGB8888 = ArgbPixel<0, 1, 2, 3>;
+using ABGR8888 = ArgbPixel<0, 3, 2, 1>;
+using RGBA8888 = ArgbPixel<3, 0, 1, 2>;
+using BGRA8888 = ArgbPixel<3, 2, 1, 0>;
+using XRGB8888 = RgbPixel<1, 2, 3>;
+using XBGR8888 = RgbPixel<3, 2, 1>;
+using RGBX8888 = RgbPixel<0, 1, 2>;
+using BGRX8888 = RgbPixel<2, 1, 0>;
#define FETCH_INFO_PACKED(frame) \
const uchar *src = frame.bits(0); \
@@ -132,7 +133,7 @@ using BGRX8888 = RgbPixel<-1, 2, 1, 0>;
stride = 0; \
}
-#define ALIGN(boundary, ptr, x, length) \
+#define QT_MEDIA_ALIGN(boundary, ptr, x, length) \
for (; ((reinterpret_cast<qintptr>(ptr) & (boundary - 1)) != 0) && x < length; ++x)
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp b/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp
index 8c0092eb1..b7049d806 100644
--- a/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp
+++ b/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qvideoframeconversionhelper_p.h"
@@ -59,13 +23,13 @@ void convert_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
const uchar shuffle = _MM_SHUFFLE(3-a, 3-r, 3-b, 3-g);
#endif
- using Pixel = const RgbPixel<a, r, g, b>;
+ using Pixel = const ArgbPixel<a, r, g, b>;
for (int y = 0; y < height; ++y) {
auto *pixel = reinterpret_cast<const Pixel *>(src);
int x = 0;
- ALIGN(16, argb, x, width) {
+ QT_MEDIA_ALIGN(16, argb, x, width) {
*argb = pixel->convert();
++pixel;
++argb;
@@ -96,26 +60,64 @@ void convert_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
}
-void qt_convert_ARGB8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_sse2<0, 1, 2, 3>(frame, output);
}
-void qt_convert_ABGR8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_sse2<0, 3, 2, 1>(frame, output);
}
-void qt_convert_RGBA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_sse2<3, 0, 1, 2>(frame, output);
}
-void qt_convert_BGRA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_sse2<3, 2, 1, 0>(frame, output);
}
+void QT_FASTCALL qt_copy_pixels_with_mask_sse2(uint32_t *dst, const uint32_t *src, size_t size, uint32_t mask)
+{
+ const auto mask128 = _mm_set_epi32(mask, mask, mask, mask);
+
+ size_t x = 0;
+
+ QT_MEDIA_ALIGN(16, dst, x, size)
+ *(dst++) = *(src++) | mask;
+
+ for (; x < size - (4 * 4 - 1); x += 4 * 4) {
+ const auto srcData0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src));
+ const auto srcData1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src += 4));
+ const auto srcData2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src += 4));
+ const auto srcData3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src += 4));
+
+ _mm_store_si128(reinterpret_cast<__m128i *>(dst), _mm_or_si128(srcData0, mask128));
+ _mm_store_si128(reinterpret_cast<__m128i *>(dst += 4), _mm_or_si128(srcData1, mask128));
+ _mm_store_si128(reinterpret_cast<__m128i *>(dst += 4), _mm_or_si128(srcData2, mask128));
+ _mm_store_si128(reinterpret_cast<__m128i *>(dst += 4), _mm_or_si128(srcData3, mask128));
+
+ src += 4;
+ dst += 4;
+ }
+
+ for (; x < size - 3; x += 4) {
+ const auto srcData = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src));
+
+ _mm_store_si128(reinterpret_cast<__m128i *>(dst), _mm_or_si128(srcData, mask128));
+
+ src += 4;
+ dst += 4;
+ }
+
+ // leftovers
+ for (; x < size; ++x)
+ *(dst++) = *(src++) | mask;
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp b/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp
index c1acb9b08..10a244fb0 100644
--- a/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp
+++ b/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qvideoframeconversionhelper_p.h"
@@ -64,13 +28,13 @@ void convert_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
3 - a, 3 - r, 3 - g, 3 - b);
#endif
- using Pixel = const RgbPixel<a, r, g, b>;
+ using Pixel = const ArgbPixel<a, r, g, b>;
for (int y = 0; y < height; ++y) {
const auto *pixel = reinterpret_cast<const Pixel *>(src);
int x = 0;
- ALIGN(16, argb, x, width) {
+ QT_MEDIA_ALIGN(16, argb, x, width) {
*argb = pixel->convert();
++pixel;
++argb;
@@ -105,17 +69,17 @@ void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_ssse3(const QVideoFrame &frame, u
convert_to_ARGB32_ssse3<0, 1, 2, 3>(frame, output);
}
-void qt_convert_ABGR8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_ssse3<0, 3, 2, 1>(frame, output);
}
-void qt_convert_RGBA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_ssse3<3, 0, 1, 2>(frame, output);
}
-void qt_convert_BGRA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
+void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
{
convert_to_ARGB32_ssse3<3, 2, 1, 0>(frame, output);
}
diff --git a/src/multimedia/video/qvideoframeconverter.cpp b/src/multimedia/video/qvideoframeconverter.cpp
new file mode 100644
index 000000000..82e0a0af5
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconverter.cpp
@@ -0,0 +1,458 @@
+// Copyright (C) 2022 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 "qvideoframeconverter_p.h"
+#include "qvideoframeconversionhelper_p.h"
+#include "qvideoframeformat.h"
+#include "qvideoframe_p.h"
+#include "qmultimediautils_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qthreadstorage.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qoffscreensurface.h>
+#include <qpa/qplatformintegration.h>
+#include <private/qvideotexturehelper_p.h>
+#include <private/qabstractvideobuffer_p.h>
+#include <private/qguiapplication_p.h>
+#include <rhi/qrhi.h>
+
+#ifdef Q_OS_DARWIN
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static Q_LOGGING_CATEGORY(qLcVideoFrameConverter, "qt.multimedia.video.frameconverter")
+
+namespace {
+
+struct State
+{
+ QRhi *rhi = nullptr;
+#if QT_CONFIG(opengl)
+ QOffscreenSurface *fallbackSurface = nullptr;
+#endif
+ bool cpuOnly = false;
+#if defined(Q_OS_ANDROID)
+ QMetaObject::Connection appStateChangedConnection;
+#endif
+ ~State() {
+ resetRhi();
+ }
+
+ void resetRhi() {
+ delete rhi;
+ rhi = nullptr;
+#if QT_CONFIG(opengl)
+ delete fallbackSurface;
+ fallbackSurface = nullptr;
+#endif
+ cpuOnly = false;
+ }
+};
+
+}
+
+static QThreadStorage<State> g_state;
+static QHash<QString, QShader> g_shaderCache;
+
+static const float g_quad[] = {
+ // Rotation 0 CW
+ 1.f, -1.f, 1.f, 1.f,
+ 1.f, 1.f, 1.f, 0.f,
+ -1.f, -1.f, 0.f, 1.f,
+ -1.f, 1.f, 0.f, 0.f,
+ // Rotation 90 CW
+ 1.f, -1.f, 1.f, 0.f,
+ 1.f, 1.f, 0.f, 0.f,
+ -1.f, -1.f, 1.f, 1.f,
+ -1.f, 1.f, 0.f, 1.f,
+ // Rotation 180 CW
+ 1.f, -1.f, 0.f, 0.f,
+ 1.f, 1.f, 0.f, 1.f,
+ -1.f, -1.f, 1.f, 0.f,
+ -1.f, 1.f, 1.f, 1.f,
+ // Rotation 270 CW
+ 1.f, -1.f, 0.f, 1.f,
+ 1.f, 1.f, 1.f, 1.f,
+ -1.f, -1.f, 0.f, 0.f,
+ -1.f, 1.f, 1.f, 0.f,
+};
+
+static bool pixelFormatHasAlpha(QVideoFrameFormat::PixelFormat format)
+{
+ switch (format) {
+ case QVideoFrameFormat::Format_ARGB8888:
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ case QVideoFrameFormat::Format_BGRA8888:
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ case QVideoFrameFormat::Format_ABGR8888:
+ case QVideoFrameFormat::Format_RGBA8888:
+ case QVideoFrameFormat::Format_AYUV:
+ case QVideoFrameFormat::Format_AYUV_Premultiplied:
+ return true;
+ default:
+ return false;
+ }
+};
+
+static QShader vfcGetShader(const QString &name)
+{
+ QShader shader = g_shaderCache.value(name);
+ if (shader.isValid())
+ return shader;
+
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ shader = QShader::fromSerialized(f.readAll());
+
+ if (shader.isValid())
+ g_shaderCache[name] = shader;
+
+ return shader;
+}
+
+static void rasterTransform(QImage &image, QtVideo::Rotation rotation,
+ bool mirrorX, bool mirrorY)
+{
+ QTransform t;
+ if (mirrorX)
+ t.scale(-1.f, 1.f);
+ if (rotation != QtVideo::Rotation::None)
+ t.rotate(float(rotation));
+ if (mirrorY)
+ t.scale(1.f, -1.f);
+ if (!t.isIdentity())
+ image = image.transformed(t);
+}
+
+static void imageCleanupHandler(void *info)
+{
+ QByteArray *imageData = reinterpret_cast<QByteArray *>(info);
+ delete imageData;
+}
+
+static QRhi *initializeRHI(QRhi *videoFrameRhi)
+{
+ if (g_state.localData().rhi || g_state.localData().cpuOnly)
+ return g_state.localData().rhi;
+
+ QRhi::Implementation backend = videoFrameRhi ? videoFrameRhi->backend() : QRhi::Null;
+
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering)) {
+
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+ if (backend == QRhi::Metal || backend == QRhi::Null) {
+ QRhiMetalInitParams params;
+ g_state.localData().rhi = QRhi::create(QRhi::Metal, &params);
+ }
+#endif
+
+#if defined(Q_OS_WIN)
+ if (backend == QRhi::D3D11 || backend == QRhi::Null) {
+ QRhiD3D11InitParams params;
+ g_state.localData().rhi = QRhi::create(QRhi::D3D11, &params);
+ }
+#endif
+
+#if QT_CONFIG(opengl)
+ if (!g_state.localData().rhi && (backend == QRhi::OpenGLES2 || backend == QRhi::Null)) {
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)
+ && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)
+ && !QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
+
+ g_state.localData().fallbackSurface = QRhiGles2InitParams::newFallbackSurface();
+ QRhiGles2InitParams params;
+ params.fallbackSurface = g_state.localData().fallbackSurface;
+ if (backend == QRhi::OpenGLES2)
+ params.shareContext = static_cast<const QRhiGles2NativeHandles*>(videoFrameRhi->nativeHandles())->context;
+ g_state.localData().rhi = QRhi::create(QRhi::OpenGLES2, &params);
+
+#if defined(Q_OS_ANDROID)
+ // reset RHI state on application suspension, as this will be invalid after resuming
+ if (!g_state.localData().appStateChangedConnection) {
+ g_state.localData().appStateChangedConnection = QObject::connect(qApp, &QGuiApplication::applicationStateChanged, qApp, [](auto state) {
+ if (state == Qt::ApplicationSuspended)
+ g_state.localData().resetRhi();
+ });
+ }
+#endif
+ }
+ }
+#endif
+ }
+
+ if (!g_state.localData().rhi) {
+ g_state.localData().cpuOnly = true;
+ qWarning() << Q_FUNC_INFO << ": No RHI backend. Using CPU conversion.";
+ }
+
+ return g_state.localData().rhi;
+}
+
+static bool updateTextures(QRhi *rhi,
+ std::unique_ptr<QRhiBuffer> &uniformBuffer,
+ std::unique_ptr<QRhiSampler> &textureSampler,
+ std::unique_ptr<QRhiShaderResourceBindings> &shaderResourceBindings,
+ std::unique_ptr<QRhiGraphicsPipeline> &graphicsPipeline,
+ std::unique_ptr<QRhiRenderPassDescriptor> &renderPass,
+ QVideoFrame &frame,
+ const std::unique_ptr<QVideoFrameTextures> &videoFrameTextures)
+{
+ auto format = frame.surfaceFormat();
+ auto pixelFormat = format.pixelFormat();
+
+ auto textureDesc = QVideoTextureHelper::textureDescription(pixelFormat);
+
+ QRhiShaderResourceBinding bindings[4];
+ auto *b = bindings;
+ *b++ = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
+ uniformBuffer.get());
+ for (int i = 0; i < textureDesc->nplanes; ++i)
+ *b++ = QRhiShaderResourceBinding::sampledTexture(i + 1, QRhiShaderResourceBinding::FragmentStage,
+ videoFrameTextures->texture(i), textureSampler.get());
+ shaderResourceBindings->setBindings(bindings, b);
+ shaderResourceBindings->create();
+
+ graphicsPipeline.reset(rhi->newGraphicsPipeline());
+ graphicsPipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
+
+ QShader vs = vfcGetShader(QVideoTextureHelper::vertexShaderFileName(format));
+ if (!vs.isValid())
+ return false;
+
+ QShader fs = vfcGetShader(QVideoTextureHelper::fragmentShaderFileName(format));
+ if (!fs.isValid())
+ return false;
+
+ graphicsPipeline->setShaderStages({
+ { QRhiShaderStage::Vertex, vs },
+ { QRhiShaderStage::Fragment, fs }
+ });
+
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 4 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
+ });
+
+ graphicsPipeline->setVertexInputLayout(inputLayout);
+ graphicsPipeline->setShaderResourceBindings(shaderResourceBindings.get());
+ graphicsPipeline->setRenderPassDescriptor(renderPass.get());
+ graphicsPipeline->create();
+
+ return true;
+}
+
+static QImage convertJPEG(const QVideoFrame &frame, QtVideo::Rotation rotation, bool mirrorX, bool mirrorY)
+{
+ QVideoFrame varFrame = frame;
+ if (!varFrame.map(QVideoFrame::ReadOnly)) {
+ qCDebug(qLcVideoFrameConverter) << Q_FUNC_INFO << ": frame mapping failed";
+ return {};
+ }
+ QImage image;
+ image.loadFromData(varFrame.bits(0), varFrame.mappedBytes(0), "JPG");
+ varFrame.unmap();
+ rasterTransform(image, rotation, mirrorX, mirrorY);
+ return image;
+}
+
+static QImage convertCPU(const QVideoFrame &frame, QtVideo::Rotation rotation, bool mirrorX, bool mirrorY)
+{
+ VideoFrameConvertFunc convert = qConverterForFormat(frame.pixelFormat());
+ if (!convert) {
+ qCDebug(qLcVideoFrameConverter) << Q_FUNC_INFO << ": unsupported pixel format" << frame.pixelFormat();
+ return {};
+ } else {
+ QVideoFrame varFrame = frame;
+ if (!varFrame.map(QVideoFrame::ReadOnly)) {
+ qCDebug(qLcVideoFrameConverter) << Q_FUNC_INFO << ": frame mapping failed";
+ return {};
+ }
+ auto format = pixelFormatHasAlpha(varFrame.pixelFormat()) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ QImage image = QImage(varFrame.width(), varFrame.height(), format);
+ convert(varFrame, image.bits());
+ varFrame.unmap();
+ rasterTransform(image, rotation, mirrorX, mirrorY);
+ return image;
+ }
+}
+
+QImage qImageFromVideoFrame(const QVideoFrame &frame, QtVideo::Rotation rotation, bool mirrorX, bool mirrorY)
+{
+#ifdef Q_OS_DARWIN
+ QMacAutoReleasePool releasePool;
+#endif
+
+ if (!g_state.hasLocalData())
+ g_state.setLocalData({});
+
+ std::unique_ptr<QRhiRenderPassDescriptor> renderPass;
+ std::unique_ptr<QRhiBuffer> vertexBuffer;
+ std::unique_ptr<QRhiBuffer> uniformBuffer;
+ std::unique_ptr<QRhiTexture> targetTexture;
+ std::unique_ptr<QRhiTextureRenderTarget> renderTarget;
+ std::unique_ptr<QRhiSampler> textureSampler;
+ std::unique_ptr<QRhiShaderResourceBindings> shaderResourceBindings;
+ std::unique_ptr<QRhiGraphicsPipeline> graphicsPipeline;
+
+ if (frame.size().isEmpty() || frame.pixelFormat() == QVideoFrameFormat::Format_Invalid)
+ return {};
+
+ if (frame.pixelFormat() == QVideoFrameFormat::Format_Jpeg)
+ return convertJPEG(frame, rotation, mirrorX, mirrorY);
+
+ QRhi *rhi = nullptr;
+
+ if (frame.videoBuffer())
+ rhi = frame.videoBuffer()->rhi();
+
+ if (!rhi || rhi->thread() != QThread::currentThread())
+ rhi = initializeRHI(rhi);
+
+ if (!rhi || rhi->isRecordingFrame())
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+
+ // Do conversion using shaders
+
+ const QSize frameSize = qRotatedFrameSize(frame.size(), rotation);
+
+ vertexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(g_quad)));
+ vertexBuffer->create();
+
+ uniformBuffer.reset(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 64 + 4 + 4 + 4 + 4));
+ uniformBuffer->create();
+
+ textureSampler.reset(rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ textureSampler->create();
+
+ shaderResourceBindings.reset(rhi->newShaderResourceBindings());
+
+ targetTexture.reset(rhi->newTexture(QRhiTexture::RGBA8, frameSize, 1, QRhiTexture::RenderTarget));
+ if (!targetTexture->create()) {
+ qCDebug(qLcVideoFrameConverter) << "Failed to create target texture. Using CPU conversion.";
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+ }
+
+ renderTarget.reset(rhi->newTextureRenderTarget({ { targetTexture.get() } }));
+ renderPass.reset(renderTarget->newCompatibleRenderPassDescriptor());
+ renderTarget->setRenderPassDescriptor(renderPass.get());
+ renderTarget->create();
+
+ QRhiCommandBuffer *cb = nullptr;
+ QRhi::FrameOpResult r = rhi->beginOffscreenFrame(&cb);
+ if (r != QRhi::FrameOpSuccess) {
+ qCDebug(qLcVideoFrameConverter) << "Failed to set up offscreen frame. Using CPU conversion.";
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+ }
+
+ QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
+
+ rub->uploadStaticBuffer(vertexBuffer.get(), g_quad);
+
+ QVideoFrame frameTmp = frame;
+ auto videoFrameTextures = QVideoTextureHelper::createTextures(frameTmp, rhi, rub, {});
+ if (!videoFrameTextures) {
+ qCDebug(qLcVideoFrameConverter) << "Failed obtain textures. Using CPU conversion.";
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+ }
+
+ if (!updateTextures(rhi, uniformBuffer, textureSampler, shaderResourceBindings,
+ graphicsPipeline, renderPass, frameTmp, videoFrameTextures)) {
+ qCDebug(qLcVideoFrameConverter) << "Failed to update textures. Using CPU conversion.";
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+ }
+
+ float xScale = mirrorX ? -1.0 : 1.0;
+ float yScale = mirrorY ? -1.0 : 1.0;
+
+ if (rhi->isYUpInFramebuffer())
+ yScale = -yScale;
+
+ QMatrix4x4 transform;
+ transform.scale(xScale, yScale);
+
+ QByteArray uniformData(64 + 64 + 4 + 4, Qt::Uninitialized);
+ QVideoTextureHelper::updateUniformData(&uniformData, frame.surfaceFormat(), frame, transform, 1.f);
+ rub->updateDynamicBuffer(uniformBuffer.get(), 0, uniformData.size(), uniformData.constData());
+
+ cb->beginPass(renderTarget.get(), Qt::black, { 1.0f, 0 }, rub);
+ cb->setGraphicsPipeline(graphicsPipeline.get());
+
+ cb->setViewport({ 0, 0, float(frameSize.width()), float(frameSize.height()) });
+ cb->setShaderResources(shaderResourceBindings.get());
+
+ const int rotationIndex = (qToUnderlying(rotation) / 90) % 4;
+ const quint32 vertexOffset = quint32(sizeof(float)) * 16 * rotationIndex;
+ const QRhiCommandBuffer::VertexInput vbufBinding(vertexBuffer.get(), vertexOffset);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(4);
+
+ QRhiReadbackDescription readDesc(targetTexture.get());
+ QRhiReadbackResult readResult;
+ bool readCompleted = false;
+
+ readResult.completed = [&readCompleted] { readCompleted = true; };
+
+ rub = rhi->nextResourceUpdateBatch();
+ rub->readBackTexture(readDesc, &readResult);
+
+ cb->endPass(rub);
+
+ rhi->endOffscreenFrame();
+
+ if (!readCompleted) {
+ qCDebug(qLcVideoFrameConverter) << "Failed to read back texture. Using CPU conversion.";
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+ }
+
+ QByteArray *imageData = new QByteArray(readResult.data);
+
+ return QImage(reinterpret_cast<const uchar *>(imageData->constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888_Premultiplied, imageCleanupHandler, imageData);
+}
+
+QImage videoFramePlaneAsImage(QVideoFrame &frame, int plane, QImage::Format targetFormat,
+ QSize targetSize)
+{
+ if (plane >= frame.planeCount())
+ return {};
+
+ if (!frame.map(QVideoFrame::ReadOnly)) {
+ qWarning() << "Cannot map a video frame in ReadOnly mode!";
+ return {};
+ }
+
+ auto frameHandle = QVideoFramePrivate::handle(frame);
+
+ // With incrementing the reference counter, we share the mapped QVideoFrame
+ // with the target QImage. The function imageCleanupFunction is going to adopt
+ // the frameHandle by QVideoFrame and dereference it upon the destruction.
+ frameHandle->ref.ref();
+
+ auto imageCleanupFunction = [](void *data) {
+ QVideoFrame frame = reinterpret_cast<QVideoFramePrivate *>(data)->adoptThisByVideoFrame();
+ Q_ASSERT(frame.isMapped());
+ frame.unmap();
+ };
+
+ const auto bytesPerLine = frame.bytesPerLine(plane);
+ const auto height =
+ bytesPerLine ? qMin(targetSize.height(), frame.mappedBytes(plane) / bytesPerLine) : 0;
+
+ return QImage(reinterpret_cast<const uchar *>(frame.bits(plane)), targetSize.width(), height,
+ bytesPerLine, targetFormat, imageCleanupFunction, frameHandle);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/video/qvideoframeconverter_p.h b/src/multimedia/video/qvideoframeconverter_p.h
new file mode 100644
index 000000000..d22491f66
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconverter_p.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 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 QVIDEOFRAMECONVERTER_H
+#define QVIDEOFRAMECONVERTER_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 <qvideoframe.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_MULTIMEDIA_EXPORT QImage qImageFromVideoFrame(const QVideoFrame &frame, QtVideo::Rotation rotation = QtVideo::Rotation::None, bool mirrorX = false, bool mirrorY = false);
+
+/**
+ * @brief Maps the video frame and returns an image having a shared ownership for the video frame
+ * and referencing to its mapped data.
+ */
+Q_MULTIMEDIA_EXPORT QImage videoFramePlaneAsImage(QVideoFrame &frame, int plane,
+ QImage::Format targetFromat, QSize targetSize);
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/multimedia/video/qvideoframeformat.cpp b/src/multimedia/video/qvideoframeformat.cpp
index 71165e4da..b2c9dc5f1 100644
--- a/src/multimedia/video/qvideoframeformat.cpp
+++ b/src/multimedia/video/qvideoframeformat.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qvideoframeformat.h"
#include "qvideotexturehelper_p.h"
@@ -48,7 +12,7 @@
#include <qmatrix4x4.h>
static void initResource() {
- Q_INIT_RESOURCE(shaders);
+ Q_INIT_RESOURCE(qtmultimedia_shaders);
}
QT_BEGIN_NAMESPACE
@@ -74,7 +38,7 @@ public:
&& frameSize == other.frameSize
&& viewport == other.viewport
&& frameRatesEqual(frameRate, other.frameRate)
- && ycbcrColorSpace == other.ycbcrColorSpace
+ && colorSpace == other.colorSpace
&& mirrored == other.mirrored)
return true;
@@ -89,9 +53,12 @@ public:
QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
QVideoFrameFormat::Direction scanLineDirection = QVideoFrameFormat::TopToBottom;
QSize frameSize;
- QVideoFrameFormat::YCbCrColorSpace ycbcrColorSpace = QVideoFrameFormat::YCbCr_Undefined;
+ QVideoFrameFormat::ColorSpace colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
+ QVideoFrameFormat::ColorTransfer colorTransfer = QVideoFrameFormat::ColorTransfer_Unknown;
+ QVideoFrameFormat::ColorRange colorRange = QVideoFrameFormat::ColorRange_Unknown;
QRect viewport;
- qreal frameRate = 0.0;
+ float frameRate = 0.0;
+ float maxLuminance = -1.;
bool mirrored = false;
};
@@ -109,7 +76,7 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFrameFormatPrivate);
A video sink presents a stream of video frames. QVideoFrameFormat describes the type of
the frames and determines how they should be presented.
- The core properties of a video stream required to setup a video sink are the pixel format
+ The core properties of a video stream required to set up a video sink are the pixel format
given by pixelFormat(), and the frame dimensions given by frameSize().
The region of a frame that is actually displayed on a video surface is given by the viewport().
@@ -238,10 +205,15 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFrameFormatPrivate);
The frame is stored in compressed Jpeg format.
\value Format_SamplerExternalOES
- The frame is stored in external OES texture format.
+ The frame is stored in external OES texture format. This is currently only being used on Android.
\value Format_SamplerRect
- The frame is stored in rectangle texture format.
+ The frame is stored in rectangle texture format (GL_TEXTURE_RECTANGLE). This is only being used on
+ macOS with an OpenGL based Rendering Hardware interface. The underlying pixel format stored in the
+ texture is Format_BRGA8888.
+
+ \value Format_YUV420P10
+ Similar to YUV420, but uses 16bits per component, 10 of those significant.
*/
/*!
@@ -256,6 +228,8 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFrameFormatPrivate);
/*!
\enum QVideoFrameFormat::YCbCrColorSpace
+ \deprecated Use QVideoFrameFormat::ColorSpace instead.
+
Enumerates the Y'CbCr color space of video frames.
\value YCbCr_Undefined
@@ -264,22 +238,108 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFrameFormatPrivate);
\value YCbCr_BT601
A Y'CbCr color space defined by ITU-R recommendation BT.601
with Y value range from 16 to 235, and Cb/Cr range from 16 to 240.
- Used in standard definition video.
+ Used mostly by older videos that were targeting CRT displays.
\value YCbCr_BT709
- A Y'CbCr color space defined by ITU-R BT.709 with the same values range as YCbCr_BT601. Used
- for HDTV.
+ A Y'CbCr color space defined by ITU-R BT.709 with the same values range as YCbCr_BT601.
+ The most commonly used color space today.
\value YCbCr_xvYCC601
+ This value is deprecated. Please check the \l ColorRange instead.
The BT.601 color space with the value range extended to 0 to 255.
It is backward compatible with BT.601 and uses values outside BT.601 range to represent a
wider range of colors.
\value YCbCr_xvYCC709
+ This value is deprecated. Please check the \l ColorRange instead.
The BT.709 color space with the value range extended to 0 to 255.
\value YCbCr_JPEG
- The full range Y'CbCr color space used in JPEG files.
+ The full range Y'CbCr color space used in most JPEG files.
+
+ \value YCbCr_BT2020
+ The color space defined by ITU-R BT.2020. Used mainly for HDR videos.
+*/
+
+
+/*!
+ \enum QVideoFrameFormat::ColorSpace
+
+ Enumerates the color space of video frames.
+
+ \value ColorSpace_Undefined
+ No color space is specified.
+
+ \value ColorSpace_BT601
+ A color space defined by ITU-R recommendation BT.601
+ with Y value range from 16 to 235, and Cb/Cr range from 16 to 240.
+ Used mostly by older videos that were targeting CRT displays.
+
+ \value ColorSpace_BT709
+ A color space defined by ITU-R BT.709 with the same values range as ColorSpace_BT601.
+ The most commonly used color space today.
+
+ \value ColorSpace_AdobeRgb
+ The full range YUV color space used in most JPEG files.
+
+ \value ColorSpace_BT2020
+ The color space defined by ITU-R BT.2020. Used mainly for HDR videos.
+*/
+
+/*!
+ \enum QVideoFrameFormat::ColorTransfer
+
+ \value ColorTransfer_Unknown
+ The color transfer function is unknown.
+
+ \value ColorTransfer_BT709
+ Color values are encoded according to BT709. See also https://www.itu.int/rec/R-REC-BT.709/en.
+ This is close to, but not identical to a gamma curve of 2.2, and the same transfer curve as is
+ used in sRGB.
+
+ \value ColorTransfer_BT601
+ Color values are encoded according to BT601. See also https://www.itu.int/rec/R-REC-BT.601/en.
+
+ \value ColorTransfer_Linear
+ Color values are linear
+
+ \value ColorTransfer_Gamma22
+ Color values are encoded with a gamma of 2.2
+
+ \value ColorTransfer_Gamma28
+ Color values are encoded with a gamma of 2.8
+
+ \value ColorTransfer_ST2084
+ Color values are encoded using STME ST 2084. This transfer function is the most common HDR
+ transfer function and often called the 'perceptual quantizer'. See also https://www.itu.int/rec/R-REC-BT.2100
+ and https://en.wikipedia.org/wiki/Perceptual_quantizer.
+
+
+ \value ColorTransfer_STD_B67
+ Color values are encoded using ARIB STD B67. This transfer function is also often referred to as 'hybrid log gamma'.
+ See also https://www.itu.int/rec/R-REC-BT.2100 and https://en.wikipedia.org/wiki/Hybrid_log–gamma.
+*/
+
+/*!
+ \enum QVideoFrameFormat::ColorRange
+
+ Describes the color range used by the video data. Video data usually comes in either full
+ color range, where all values are being used, or a more limited range traditionally used in
+ YUV video formats, where a subset of all values is being used.
+
+ \value ColorRange_Unknown
+ The color range of the video is unknown.
+
+ \value ColorRange_Video
+
+ The color range traditionally used by most YUV video formats. For 8 bit formats, the Y component is
+ limited to values between 16 and 235. The U and V components are limited to values between 16 and 240
+
+ For higher bit depths multiply these values with 2^(depth-8).
+
+ \value ColorRange_Full
+
+ Full color range. All values from 0 to 2^depth - 1 are valid.
*/
/*!
@@ -312,6 +372,12 @@ QVideoFrameFormat::QVideoFrameFormat(const QVideoFrameFormat &other) = default;
*/
/*!
+ \fn void QVideoFrameFormat::swap(QVideoFrameFormat &other) noexcept
+
+ Swaps the current video frame format with the \a other.
+*/
+
+/*!
Assigns the values of \a other to this object.
*/
QVideoFrameFormat &QVideoFrameFormat::operator =(const QVideoFrameFormat &other) = default;
@@ -489,22 +555,83 @@ void QVideoFrameFormat::setFrameRate(qreal rate)
d->frameRate = rate;
}
+#if QT_DEPRECATED_SINCE(6, 4)
/*!
+ \deprecated Use colorSpace() instead
+
Returns the Y'CbCr color space of a video stream.
*/
QVideoFrameFormat::YCbCrColorSpace QVideoFrameFormat::yCbCrColorSpace() const
{
- return d->ycbcrColorSpace;
+ return YCbCrColorSpace(d->colorSpace);
}
/*!
+ \deprecated Use setColorSpace() instead
+
Sets the Y'CbCr color \a space of a video stream.
It is only used with raw YUV frame types.
*/
void QVideoFrameFormat::setYCbCrColorSpace(QVideoFrameFormat::YCbCrColorSpace space)
{
detach();
- d->ycbcrColorSpace = space;
+ d->colorSpace = ColorSpace(space);
+}
+#endif // QT_DEPRECATED_SINCE(6, 4)
+
+/*!
+ Returns the color space of a video stream.
+*/
+QVideoFrameFormat::ColorSpace QVideoFrameFormat::colorSpace() const
+{
+ return d->colorSpace;
+}
+
+/*!
+ Sets the \a colorSpace of a video stream.
+*/
+void QVideoFrameFormat::setColorSpace(ColorSpace colorSpace)
+{
+ detach();
+ d->colorSpace = colorSpace;
+}
+
+/*!
+ Returns the color transfer function that should be used to render the
+ video stream.
+*/
+QVideoFrameFormat::ColorTransfer QVideoFrameFormat::colorTransfer() const
+{
+ return d->colorTransfer;
+}
+
+/*!
+ Sets the color transfer function that should be used to render the
+ video stream to \a colorTransfer.
+*/
+void QVideoFrameFormat::setColorTransfer(ColorTransfer colorTransfer)
+{
+ detach();
+ d->colorTransfer = colorTransfer;
+}
+
+/*!
+ Returns the color range that should be used to render the
+ video stream.
+*/
+QVideoFrameFormat::ColorRange QVideoFrameFormat::colorRange() const
+{
+ return d->colorRange;
+}
+
+/*!
+ Sets the color transfer range that should be used to render the
+ video stream to \a range.
+*/
+void QVideoFrameFormat::setColorRange(ColorRange range)
+{
+ detach();
+ d->colorRange = range;
}
/*!
@@ -542,7 +669,7 @@ void QVideoFrameFormat::setMirrored(bool mirrored)
*/
QString QVideoFrameFormat::vertexShaderFileName() const
{
- return QVideoTextureHelper::vertexShaderFileName(d->pixelFormat);
+ return QVideoTextureHelper::vertexShaderFileName(*this);
}
/*!
@@ -550,7 +677,7 @@ QString QVideoFrameFormat::vertexShaderFileName() const
*/
QString QVideoFrameFormat::fragmentShaderFileName() const
{
- return QVideoTextureHelper::fragmentShaderFileName(d->pixelFormat);
+ return QVideoTextureHelper::fragmentShaderFileName(*this);
}
/*!
@@ -561,6 +688,32 @@ void QVideoFrameFormat::updateUniformData(QByteArray *dst, const QVideoFrame &fr
QVideoTextureHelper::updateUniformData(dst, *this, frame, transform, opacity);
}
+/*!
+ \internal
+
+ The maximum luminence in nits as set by the HDR metadata. If the video doesn't have meta data, the returned value depends on the
+ maximum that can be encoded by the transfer function.
+*/
+float QVideoFrameFormat::maxLuminance() const
+{
+ if (d->maxLuminance <= 0) {
+ if (d->colorTransfer == ColorTransfer_ST2084)
+ return 10000.; // ST2084 can encode up to 10000 nits
+ if (d->colorTransfer == ColorTransfer_STD_B67)
+ return 1500.; // SRD_B67 can encode up to 1200 nits, use a bit more for some headroom
+ return 100; // SDR
+ }
+ return d->maxLuminance;
+}
+/*!
+ Sets the maximum luminance to the given value, \a lum.
+*/
+void QVideoFrameFormat::setMaxLuminance(float lum)
+{
+ detach();
+ d->maxLuminance = lum;
+}
+
/*!
Returns a video pixel format equivalent to an image \a format. If there is no equivalent
@@ -590,7 +743,9 @@ QVideoFrameFormat::PixelFormat QVideoFrameFormat::pixelFormatFromImageFormat(QIm
case QImage::Format_RGBA8888:
return QVideoFrameFormat::Format_RGBA8888;
case QImage::Format_RGBA8888_Premultiplied:
- return QVideoFrameFormat::Format_ARGB8888_Premultiplied;
+ // QVideoFrameFormat::Format_RGBA8888_Premultiplied is to be added in 6.8
+ // Format_RGBX8888 suits the best as a workaround
+ return QVideoFrameFormat::Format_RGBX8888;
case QImage::Format_RGBX8888:
return QVideoFrameFormat::Format_RGBX8888;
case QImage::Format_Grayscale8:
@@ -648,6 +803,7 @@ QImage::Format QVideoFrameFormat::imageFormatFromPixelFormat(QVideoFrameFormat::
case QVideoFrameFormat::Format_AYUV:
case QVideoFrameFormat::Format_AYUV_Premultiplied:
case QVideoFrameFormat::Format_YUV420P:
+ case QVideoFrameFormat::Format_YUV420P10:
case QVideoFrameFormat::Format_YUV422P:
case QVideoFrameFormat::Format_YV12:
case QVideoFrameFormat::Format_UYVY:
@@ -669,7 +825,83 @@ QImage::Format QVideoFrameFormat::imageFormatFromPixelFormat(QVideoFrameFormat::
return QImage::Format_Invalid;
}
+/*!
+ Returns a string representation of the given \a pixelFormat.
+*/
+QString QVideoFrameFormat::pixelFormatToString(QVideoFrameFormat::PixelFormat pixelFormat)
+{
+ switch (pixelFormat) {
+ case QVideoFrameFormat::Format_Invalid:
+ return QStringLiteral("Invalid");
+ case QVideoFrameFormat::Format_ARGB8888:
+ return QStringLiteral("ARGB8888");
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ return QStringLiteral("ARGB8888 Premultiplied");
+ case QVideoFrameFormat::Format_XRGB8888:
+ return QStringLiteral("XRGB8888");
+ case QVideoFrameFormat::Format_BGRA8888:
+ return QStringLiteral("BGRA8888");
+ case QVideoFrameFormat::Format_BGRX8888:
+ return QStringLiteral("BGRX8888");
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ return QStringLiteral("BGRA8888 Premultiplied");
+ case QVideoFrameFormat::Format_RGBA8888:
+ return QStringLiteral("RGBA8888");
+ case QVideoFrameFormat::Format_RGBX8888:
+ return QStringLiteral("RGBX8888");
+ case QVideoFrameFormat::Format_ABGR8888:
+ return QStringLiteral("ABGR8888");
+ case QVideoFrameFormat::Format_XBGR8888:
+ return QStringLiteral("XBGR8888");
+ case QVideoFrameFormat::Format_AYUV:
+ return QStringLiteral("AYUV");
+ case QVideoFrameFormat::Format_AYUV_Premultiplied:
+ return QStringLiteral("AYUV Premultiplied");
+ case QVideoFrameFormat::Format_YUV420P:
+ return QStringLiteral("YUV420P");
+ case QVideoFrameFormat::Format_YUV420P10:
+ return QStringLiteral("YUV420P10");
+ case QVideoFrameFormat::Format_YUV422P:
+ return QStringLiteral("YUV422P");
+ case QVideoFrameFormat::Format_YV12:
+ return QStringLiteral("YV12");
+ case QVideoFrameFormat::Format_UYVY:
+ return QStringLiteral("UYVY");
+ case QVideoFrameFormat::Format_YUYV:
+ return QStringLiteral("YUYV");
+ case QVideoFrameFormat::Format_NV12:
+ return QStringLiteral("NV12");
+ case QVideoFrameFormat::Format_NV21:
+ return QStringLiteral("NV21");
+ case QVideoFrameFormat::Format_IMC1:
+ return QStringLiteral("IMC1");
+ case QVideoFrameFormat::Format_IMC2:
+ return QStringLiteral("IMC2");
+ case QVideoFrameFormat::Format_IMC3:
+ return QStringLiteral("IMC3");
+ case QVideoFrameFormat::Format_IMC4:
+ return QStringLiteral("IMC4");
+ case QVideoFrameFormat::Format_Y8:
+ return QStringLiteral("Y8");
+ case QVideoFrameFormat::Format_Y16:
+ return QStringLiteral("Y16");
+ case QVideoFrameFormat::Format_P010:
+ return QStringLiteral("P010");
+ case QVideoFrameFormat::Format_P016:
+ return QStringLiteral("P016");
+ case QVideoFrameFormat::Format_SamplerExternalOES:
+ return QStringLiteral("SamplerExternalOES");
+ case QVideoFrameFormat::Format_Jpeg:
+ return QStringLiteral("Jpeg");
+ case QVideoFrameFormat::Format_SamplerRect:
+ return QStringLiteral("SamplerRect");
+ }
+
+ return QStringLiteral("");
+}
+
#ifndef QT_NO_DEBUG_STREAM
+# if QT_DEPRECATED_SINCE(6, 4)
QDebug operator<<(QDebug dbg, QVideoFrameFormat::YCbCrColorSpace cs)
{
QDebugStateSaver saver(dbg);
@@ -690,12 +922,40 @@ QDebug operator<<(QDebug dbg, QVideoFrameFormat::YCbCrColorSpace cs)
case QVideoFrameFormat::YCbCr_xvYCC709:
dbg << "YCbCr_xvYCC709";
break;
+ case QVideoFrameFormat::YCbCr_BT2020:
+ dbg << "YCbCr_BT2020";
+ break;
default:
dbg << "YCbCr_Undefined";
break;
}
return dbg;
}
+# endif // QT_DEPRECATED_SINCE(6, 4)
+
+QDebug operator<<(QDebug dbg, QVideoFrameFormat::ColorSpace cs)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ switch (cs) {
+ case QVideoFrameFormat::ColorSpace_BT601:
+ dbg << "ColorSpace_BT601";
+ break;
+ case QVideoFrameFormat::ColorSpace_BT709:
+ dbg << "ColorSpace_BT709";
+ break;
+ case QVideoFrameFormat::ColorSpace_AdobeRgb:
+ dbg << "ColorSpace_AdobeRgb";
+ break;
+ case QVideoFrameFormat::ColorSpace_BT2020:
+ dbg << "ColorSpace_BT2020";
+ break;
+ default:
+ dbg << "ColorSpace_Undefined";
+ break;
+ }
+ return dbg;
+}
QDebug operator<<(QDebug dbg, QVideoFrameFormat::Direction dir)
{
@@ -718,12 +978,12 @@ QDebug operator<<(QDebug dbg, const QVideoFrameFormat &f)
dbg.nospace();
dbg << "QVideoFrameFormat(" << f.pixelFormat() << ", " << f.frameSize()
<< ", viewport=" << f.viewport()
- << ", yCbCrColorSpace=" << f.yCbCrColorSpace()
+ << ", colorSpace=" << f.colorSpace()
<< ')'
<< "\n pixel format=" << f.pixelFormat()
<< "\n frame size=" << f.frameSize()
<< "\n viewport=" << f.viewport()
- << "\n yCbCrColorSpace=" << f.yCbCrColorSpace()
+ << "\n colorSpace=" << f.colorSpace()
<< "\n frameRate=" << f.frameRate()
<< "\n mirrored=" << f.isMirrored();
@@ -734,70 +994,12 @@ QDebug operator<<(QDebug dbg, QVideoFrameFormat::PixelFormat pf)
{
QDebugStateSaver saver(dbg);
dbg.nospace();
- switch (pf) {
- case QVideoFrameFormat::Format_Invalid:
- return dbg << "Format_Invalid";
- case QVideoFrameFormat::Format_ARGB8888:
- return dbg << "Format_ARGB8888";
- case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
- return dbg << "Format_ARGB8888_Premultiplied";
- case QVideoFrameFormat::Format_XRGB8888:
- return dbg << "Format_XRGB8888";
- case QVideoFrameFormat::Format_BGRA8888:
- return dbg << "Format_BGRA8888";
- case QVideoFrameFormat::Format_BGRX8888:
- return dbg << "Format_BGRX8888";
- case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
- return dbg << "Format_BGRA8888_Premultiplied";
- case QVideoFrameFormat::Format_RGBA8888:
- return dbg << "Format_RGBA8888";
- case QVideoFrameFormat::Format_RGBX8888:
- return dbg << "Format_RGBX8888";
- case QVideoFrameFormat::Format_ABGR8888:
- return dbg << "Format_ABGR8888";
- case QVideoFrameFormat::Format_XBGR8888:
- return dbg << "Format_XBGR8888";
- case QVideoFrameFormat::Format_AYUV:
- return dbg << "Format_AYUV";
- case QVideoFrameFormat::Format_AYUV_Premultiplied:
- return dbg << "Format_AYUV_Premultiplied";
- case QVideoFrameFormat::Format_YUV420P:
- return dbg << "Format_YUV420P";
- case QVideoFrameFormat::Format_YUV422P:
- return dbg << "Format_YUV422P";
- case QVideoFrameFormat::Format_YV12:
- return dbg << "Format_YV12";
- case QVideoFrameFormat::Format_UYVY:
- return dbg << "Format_UYVY";
- case QVideoFrameFormat::Format_YUYV:
- return dbg << "Format_YUYV";
- case QVideoFrameFormat::Format_NV12:
- return dbg << "Format_NV12";
- case QVideoFrameFormat::Format_NV21:
- return dbg << "Format_NV21";
- case QVideoFrameFormat::Format_IMC1:
- return dbg << "Format_IMC1";
- case QVideoFrameFormat::Format_IMC2:
- return dbg << "Format_IMC2";
- case QVideoFrameFormat::Format_IMC3:
- return dbg << "Format_IMC3";
- case QVideoFrameFormat::Format_IMC4:
- return dbg << "Format_IMC4";
- case QVideoFrameFormat::Format_Y8:
- return dbg << "Format_Y8";
- case QVideoFrameFormat::Format_Y16:
- return dbg << "Format_Y16";
- case QVideoFrameFormat::Format_P010:
- return dbg << "Format_P010";
- case QVideoFrameFormat::Format_P016:
- return dbg << "Format_P016";
- case QVideoFrameFormat::Format_SamplerExternalOES:
- return dbg << "Format_SamplerExternalOES";
- case QVideoFrameFormat::Format_Jpeg:
- return dbg << "Format_Jpeg";
- case QVideoFrameFormat::Format_SamplerRect:
- return dbg << "Format_SamplerRect";
- }
+
+ auto format = QVideoFrameFormat::pixelFormatToString(pf);
+ if (format.isEmpty())
+ return dbg;
+
+ dbg.noquote() << QStringLiteral("Format_") << format;
return dbg;
}
#endif
diff --git a/src/multimedia/video/qvideoframeformat.h b/src/multimedia/video/qvideoframeformat.h
index bd4f9fc15..5fb6b3701 100644
--- a/src/multimedia/video/qvideoframeformat.h
+++ b/src/multimedia/video/qvideoframeformat.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QVIDEOSURFACEFORMAT_H
#define QVIDEOSURFACEFORMAT_H
@@ -98,9 +62,11 @@ public:
Format_SamplerExternalOES,
Format_Jpeg,
Format_SamplerRect,
+
+ Format_YUV420P10
};
#ifndef Q_QDOC
- static constexpr int NPixelFormats = Format_SamplerRect + 1;
+ static constexpr int NPixelFormats = Format_YUV420P10 + 1;
#endif
enum Direction
@@ -109,14 +75,46 @@ public:
BottomToTop
};
+#if QT_DEPRECATED_SINCE(6, 4)
enum YCbCrColorSpace
{
- YCbCr_Undefined,
- YCbCr_BT601,
- YCbCr_BT709,
- YCbCr_xvYCC601,
- YCbCr_xvYCC709,
- YCbCr_JPEG,
+ YCbCr_Undefined = 0,
+ YCbCr_BT601 = 1,
+ YCbCr_BT709 = 2,
+ YCbCr_xvYCC601 = 3,
+ YCbCr_xvYCC709 = 4,
+ YCbCr_JPEG = 5,
+ YCbCr_BT2020 = 6
+ };
+#endif
+
+ // Keep values compatible with YCbCrColorSpace
+ enum ColorSpace
+ {
+ ColorSpace_Undefined = 0,
+ ColorSpace_BT601 = 1,
+ ColorSpace_BT709 = 2,
+ ColorSpace_AdobeRgb = 5,
+ ColorSpace_BT2020 = 6
+ };
+
+ enum ColorTransfer
+ {
+ ColorTransfer_Unknown,
+ ColorTransfer_BT709,
+ ColorTransfer_BT601,
+ ColorTransfer_Linear,
+ ColorTransfer_Gamma22,
+ ColorTransfer_Gamma28,
+ ColorTransfer_ST2084,
+ ColorTransfer_STD_B67,
+ };
+
+ enum ColorRange
+ {
+ ColorRange_Unknown,
+ ColorRange_Video,
+ ColorRange_Full
};
QVideoFrameFormat();
@@ -127,7 +125,7 @@ public:
QVideoFrameFormat(QVideoFrameFormat &&other) noexcept = default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QVideoFrameFormat);
void swap(QVideoFrameFormat &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
void detach();
@@ -158,8 +156,21 @@ public:
qreal frameRate() const;
void setFrameRate(qreal rate);
+#if QT_DEPRECATED_SINCE(6, 4)
+ QT_DEPRECATED_VERSION_X_6_4("Use colorSpace()")
YCbCrColorSpace yCbCrColorSpace() const;
+ QT_DEPRECATED_VERSION_X_6_4("Use setColorSpace()")
void setYCbCrColorSpace(YCbCrColorSpace colorSpace);
+#endif
+
+ ColorSpace colorSpace() const;
+ void setColorSpace(ColorSpace colorSpace);
+
+ ColorTransfer colorTransfer() const;
+ void setColorTransfer(ColorTransfer colorTransfer);
+
+ ColorRange colorRange() const;
+ void setColorRange(ColorRange range);
bool isMirrored() const;
void setMirrored(bool mirrored);
@@ -168,9 +179,14 @@ public:
QString fragmentShaderFileName() const;
void updateUniformData(QByteArray *dst, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity) const;
+ float maxLuminance() const;
+ void setMaxLuminance(float lum);
+
static PixelFormat pixelFormatFromImageFormat(QImage::Format format);
static QImage::Format imageFormatFromPixelFormat(PixelFormat format);
+ static QString pixelFormatToString(QVideoFrameFormat::PixelFormat pixelFormat);
+
private:
QExplicitlySharedDataPointer<QVideoFrameFormatPrivate> d;
};
@@ -180,7 +196,11 @@ Q_DECLARE_SHARED(QVideoFrameFormat)
#ifndef QT_NO_DEBUG_STREAM
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QVideoFrameFormat &);
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoFrameFormat::Direction);
+#if QT_DEPRECATED_SINCE(6, 4)
+QT_DEPRECATED_VERSION_X_6_4("Use QVideoFrameFormat::ColorSpace")
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoFrameFormat::YCbCrColorSpace);
+#endif
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoFrameFormat::ColorSpace);
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoFrameFormat::PixelFormat);
#endif
diff --git a/src/multimedia/video/qvideooutputorientationhandler.cpp b/src/multimedia/video/qvideooutputorientationhandler.cpp
index 2a6781b47..c34e9e92a 100644
--- a/src/multimedia/video/qvideooutputorientationhandler.cpp
+++ b/src/multimedia/video/qvideooutputorientationhandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvideooutputorientationhandler_p.h"
@@ -51,6 +15,8 @@ QVideoOutputOrientationHandler::QVideoOutputOrientationHandler(QObject *parent)
, m_currentOrientation(0)
{
QScreen *screen = QGuiApplication::primaryScreen();
+ if (!screen)
+ return;
connect(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation)),
this, SLOT(screenOrientationChanged(Qt::ScreenOrientation)));
@@ -69,6 +35,8 @@ void QVideoOutputOrientationHandler::screenOrientationChanged(Qt::ScreenOrientat
return;
const QScreen *screen = QGuiApplication::primaryScreen();
+ if (!screen)
+ return;
const int angle = (360 - screen->angleBetween(screen->nativeOrientation(), orientation)) % 360;
@@ -80,3 +48,5 @@ void QVideoOutputOrientationHandler::screenOrientationChanged(Qt::ScreenOrientat
}
QT_END_NAMESPACE
+
+#include "moc_qvideooutputorientationhandler_p.cpp"
diff --git a/src/multimedia/video/qvideooutputorientationhandler_p.h b/src/multimedia/video/qvideooutputorientationhandler_p.h
index 604564571..ae31f333b 100644
--- a/src/multimedia/video/qvideooutputorientationhandler_p.h
+++ b/src/multimedia/video/qvideooutputorientationhandler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVIDEOOUTPUTORIENTATIONHANDLER_P_H
#define QVIDEOOUTPUTORIENTATIONHANDLER_P_H
@@ -54,6 +18,7 @@
#include <qtmultimediaglobal.h>
#include <QObject>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/multimedia/video/qvideosink.cpp b/src/multimedia/video/qvideosink.cpp
index 8e2637a1f..4551a8960 100644
--- a/src/multimedia/video/qvideosink.cpp
+++ b/src/multimedia/video/qvideosink.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 "qvideosink.h"
@@ -58,7 +22,12 @@ public:
QVideoSinkPrivate(QVideoSink *q)
: q_ptr(q)
{
- videoSink = QPlatformMediaIntegration::instance()->createVideoSink(q);
+ auto maybeVideoSink = QPlatformMediaIntegration::instance()->createVideoSink(q);
+ if (maybeVideoSink) {
+ videoSink = maybeVideoSink.value();
+ } else {
+ qWarning() << "Failed to create QVideoSink" << maybeVideoSink.error();
+ }
}
~QVideoSinkPrivate()
{
@@ -88,14 +57,13 @@ public:
\brief The QVideoSink class represents a generic sink for video data.
\inmodule QtMultimedia
\ingroup multimedia
+ \ingroup multimedia_video
The QVideoSink class can be used to retrieve video data on a frame by frame
basis from Qt Multimedia.
- QVideoSink can operate in two modes. In the first mode, it can render the video
- stream to a native window of the underlying windowing system. In the other mode,
- it will provide individual video frames to the application developer through the
- videoFrameChanged() signal.
+ QVideoSink will provide individual video frames to the application developer
+ through the videoFrameChanged() signal.
The video frame can then be used to read out the data of those frames and handle them
further. When using QPainter, the QVideoFrame can be drawing using the paint() method
@@ -123,12 +91,12 @@ QVideoSink::QVideoSink(QObject *parent)
*/
QVideoSink::~QVideoSink()
{
+ disconnect(this);
d->unregisterSource();
delete d;
}
/*!
- \internal
Returns the QRhi instance being used to create texture data in the video frames.
*/
QRhi *QVideoSink::rhi() const
@@ -146,7 +114,8 @@ void QVideoSink::setRhi(QRhi *rhi)
if (d->rhi == rhi)
return;
d->rhi = rhi;
- d->videoSink->setRhi(rhi);
+ if (d->videoSink)
+ d->videoSink->setRhi(rhi);
}
/*!
@@ -162,23 +131,31 @@ QPlatformVideoSink *QVideoSink::platformVideoSink() const
*/
QVideoFrame QVideoSink::videoFrame() const
{
- return d->videoSink->currentVideoFrame();
+ return d->videoSink ? d->videoSink->currentVideoFrame() : QVideoFrame{};
}
/*!
+ \fn void QVideoSink::videoFrameChanged(const QVideoFrame &frame) const
+
+ Signals when the video \a frame changes.
+*/
+/*!
Sets the current video \a frame.
*/
void QVideoSink::setVideoFrame(const QVideoFrame &frame)
{
- d->videoSink->setVideoFrame(frame);
+ if (d->videoSink)
+ d->videoSink->setVideoFrame(frame);
}
/*!
+ \property QVideoSink::subtitleText
+
Returns the current subtitle text.
*/
QString QVideoSink::subtitleText() const
{
- return d->videoSink->subtitleText();
+ return d->videoSink ? d->videoSink->subtitleText() : QString{};
}
/*!
@@ -186,10 +163,13 @@ QString QVideoSink::subtitleText() const
*/
void QVideoSink::setSubtitleText(const QString &subtitle)
{
- d->videoSink->setSubtitleText(subtitle);
+ if (d->videoSink)
+ d->videoSink->setSubtitleText(subtitle);
}
/*!
+ \property QVideoSink::videoSize
+
Returns the size of the video currently being played back. If no video is
being played, this method returns an invalid size.
*/
diff --git a/src/multimedia/video/qvideosink.h b/src/multimedia/video/qvideosink.h
index 0e7f3d8cd..1a2e77834 100644
--- a/src/multimedia/video/qvideosink.h
+++ b/src/multimedia/video/qvideosink.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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 QABSTRACTVIDEOSINK_H
#define QABSTRACTVIDEOSINK_H
@@ -57,6 +21,8 @@ class QRhi;
class Q_MULTIMEDIA_EXPORT QVideoSink : public QObject
{
Q_OBJECT
+ Q_PROPERTY(QString subtitleText READ subtitleText WRITE setSubtitleText NOTIFY subtitleTextChanged)
+ Q_PROPERTY(QSize videoSize READ videoSize NOTIFY videoSizeChanged)
public:
QVideoSink(QObject *parent = nullptr);
~QVideoSink();
@@ -74,9 +40,8 @@ public:
QPlatformVideoSink *platformVideoSink() const;
Q_SIGNALS:
- void videoFrameChanged(const QVideoFrame &frame) const;
- void subtitleTextChanged(const QString &subtitleText) const;
-
+ void videoFrameChanged(const QVideoFrame &frame) QT6_ONLY(const);
+ void subtitleTextChanged(const QString &subtitleText) QT6_ONLY(const);
void videoSizeChanged();
private:
diff --git a/src/multimedia/video/qvideotexturehelper.cpp b/src/multimedia/video/qvideotexturehelper.cpp
index 44b323056..937ff33cb 100644
--- a/src/multimedia/video/qvideotexturehelper.cpp
+++ b/src/multimedia/video/qvideotexturehelper.cpp
@@ -1,49 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvideotexturehelper_p.h"
-#include "qvideoframe.h"
-#ifdef Q_OS_ANDROID
-#include <private/qandroidvideooutput_p.h>
-#endif
+#include "qabstractvideobuffer_p.h"
+#include "qvideoframeconverter_p.h"
#include <qpainter.h>
+#include <qloggingcategory.h>
QT_BEGIN_NAMESPACE
@@ -78,19 +41,19 @@ static const TextureDescription descriptions[QVideoFrameFormat::NPixelFormats] =
// Format_BGRA8888
{ 1, 4,
[](int stride, int height) { return stride*height; },
- { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
{ { 1, 1 }, { 1, 1 }, { 1, 1 } }
},
// Format_BGRA8888_Premultiplied
{ 1, 4,
[](int stride, int height) { return stride*height; },
- { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
{ { 1, 1 }, { 1, 1 }, { 1, 1 } }
},
// Format_BGRX8888
{ 1, 4,
[](int stride, int height) { return stride*height; },
- { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
{ { 1, 1 }, { 1, 1 }, { 1, 1 } }
},
// Format_ABGR8888
@@ -137,7 +100,7 @@ static const TextureDescription descriptions[QVideoFrameFormat::NPixelFormats] =
},
// Format_YUV422P
{ 3, 1,
- [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ [](int stride, int height) { return stride * height * 2; },
{ QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
{ { 1, 1 }, { 2, 1 }, { 2, 1 } }
},
@@ -237,18 +200,24 @@ static const TextureDescription descriptions[QVideoFrameFormat::NPixelFormats] =
{ { 1, 1 }, { 1, 1 }, { 1, 1 } }
},
// Format_Jpeg
- { 1, 0,
- [](int, int) { return 0; },
- { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
{ { 1, 1 }, { 1, 1 }, { 1, 1 } }
},
// Format_SamplerRect
{
1, 0,
[](int, int) { return 0; },
- { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
{ { 1, 1 }, { 1, 1 }, { 1, 1 } }
- }
+ },
+ // Format_YUV420P10
+ { 3, 1,
+ [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ { QRhiTexture::R16, QRhiTexture::R16, QRhiTexture::R16 },
+ { { 1, 1 }, { 2, 2 }, { 2, 2 } }
+ },
};
const TextureDescription *textureDescription(QVideoFrameFormat::PixelFormat format)
@@ -256,144 +225,256 @@ const TextureDescription *textureDescription(QVideoFrameFormat::PixelFormat form
return descriptions + format;
}
-QString vertexShaderFileName(QVideoFrameFormat::PixelFormat format)
+QString vertexShaderFileName(const QVideoFrameFormat &format)
{
- Q_UNUSED(format);
+ auto fmt = format.pixelFormat();
+ Q_UNUSED(fmt);
#if 1//def Q_OS_ANDROID
- if (format == QVideoFrameFormat::Format_SamplerExternalOES)
+ if (fmt == QVideoFrameFormat::Format_SamplerExternalOES)
return QStringLiteral(":/qt-project.org/multimedia/shaders/externalsampler.vert.qsb");
#endif
#if 1//def Q_OS_MACOS
- if (format == QVideoFrameFormat::Format_SamplerRect)
+ if (fmt == QVideoFrameFormat::Format_SamplerRect)
return QStringLiteral(":/qt-project.org/multimedia/shaders/rectsampler.vert.qsb");
#endif
return QStringLiteral(":/qt-project.org/multimedia/shaders/vertex.vert.qsb");
}
-QString fragmentShaderFileName(QVideoFrameFormat::PixelFormat format)
+QString fragmentShaderFileName(const QVideoFrameFormat &format, QRhiSwapChain::Format surfaceFormat)
{
- switch (format) {
+ const char *shader = nullptr;
+ switch (format.pixelFormat()) {
case QVideoFrameFormat::Format_Y8:
case QVideoFrameFormat::Format_Y16:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/y.frag.qsb");
+ shader = "y";
+ break;
case QVideoFrameFormat::Format_AYUV:
case QVideoFrameFormat::Format_AYUV_Premultiplied:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/ayuv.frag.qsb");
+ shader = "ayuv";
+ break;
case QVideoFrameFormat::Format_ARGB8888:
case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
case QVideoFrameFormat::Format_XRGB8888:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/argb.frag.qsb");
- case QVideoFrameFormat::Format_BGRA8888:
- case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
- case QVideoFrameFormat::Format_BGRX8888:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/bgra.frag.qsb");
+ shader = "argb";
+ break;
case QVideoFrameFormat::Format_ABGR8888:
case QVideoFrameFormat::Format_XBGR8888:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/abgr.frag.qsb");
+ shader = "abgr";
+ break;
+ case QVideoFrameFormat::Format_Jpeg: // Jpeg is decoded transparently into an ARGB texture
+ shader = "bgra";
+ break;
case QVideoFrameFormat::Format_RGBA8888:
case QVideoFrameFormat::Format_RGBX8888:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/rgba.frag.qsb");
+ case QVideoFrameFormat::Format_BGRA8888:
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ case QVideoFrameFormat::Format_BGRX8888:
+ shader = "rgba";
+ break;
case QVideoFrameFormat::Format_YUV420P:
case QVideoFrameFormat::Format_YUV422P:
case QVideoFrameFormat::Format_IMC3:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/yuv_triplanar.frag.qsb");
+ shader = "yuv_triplanar";
+ break;
+ case QVideoFrameFormat::Format_YUV420P10:
+ shader = "yuv_triplanar_p10";
+ break;
case QVideoFrameFormat::Format_YV12:
case QVideoFrameFormat::Format_IMC1:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/yvu_triplanar.frag.qsb");
+ shader = "yvu_triplanar";
+ break;
case QVideoFrameFormat::Format_IMC2:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/imc2.frag.qsb");
+ shader = "imc2";
+ break;
case QVideoFrameFormat::Format_IMC4:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/imc4.frag.qsb");
+ shader = "imc4";
+ break;
case QVideoFrameFormat::Format_UYVY:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/uyvy.frag.qsb");
+ shader = "uyvy";
+ break;
case QVideoFrameFormat::Format_YUYV:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/yuyv.frag.qsb");
- case QVideoFrameFormat::Format_NV12:
+ shader = "yuyv";
+ break;
case QVideoFrameFormat::Format_P010:
case QVideoFrameFormat::Format_P016:
// P010/P016 have the same layout as NV12, just 16 instead of 8 bits per pixel
- return QStringLiteral(":/qt-project.org/multimedia/shaders/nv12.frag.qsb");
+ if (format.colorTransfer() == QVideoFrameFormat::ColorTransfer_ST2084) {
+ shader = "nv12_bt2020_pq";
+ break;
+ }
+ if (format.colorTransfer() == QVideoFrameFormat::ColorTransfer_STD_B67) {
+ shader = "nv12_bt2020_hlg";
+ break;
+ }
+ // Fall through, should be bt709
+ Q_FALLTHROUGH();
+ case QVideoFrameFormat::Format_NV12:
+ shader = "nv12";
+ break;
case QVideoFrameFormat::Format_NV21:
- return QStringLiteral(":/qt-project.org/multimedia/shaders/nv21.frag.qsb");
+ shader = "nv21";
+ break;
case QVideoFrameFormat::Format_SamplerExternalOES:
#if 1//def Q_OS_ANDROID
- return QStringLiteral(":/qt-project.org/multimedia/shaders/externalsampler.frag.qsb");
+ shader = "externalsampler";
+ break;
#endif
case QVideoFrameFormat::Format_SamplerRect:
#if 1//def Q_OS_MACOS
- return QStringLiteral(":/qt-project.org/multimedia/shaders/rectsampler_bgra.frag.qsb");
+ shader = "rectsampler_bgra";
+ break;
#endif
// fallthrough
case QVideoFrameFormat::Format_Invalid:
- case QVideoFrameFormat::Format_Jpeg:
default:
- return QString();
+ break;
}
+ if (!shader)
+ return QString();
+ QString shaderFile = QStringLiteral(":/qt-project.org/multimedia/shaders/") + QString::fromLatin1(shader);
+ if (surfaceFormat == QRhiSwapChain::HDRExtendedSrgbLinear)
+ shaderFile += QLatin1String("_linear");
+ shaderFile += QStringLiteral(".frag.qsb");
+ return shaderFile;
}
-
-static QMatrix4x4 colorMatrix(QVideoFrameFormat::YCbCrColorSpace colorSpace)
+// Matrices are calculated from
+// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf
+// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf
+// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2020-2-201510-I!!PDF-E.pdf
+//
+// For BT2020, we also need to convert the Rec2020 RGB colorspace to sRGB see
+// shaders/colorconvert.glsl for details.
+//
+// Doing the math gives the following (Y, U & V normalized to [0..1] range):
+//
+// Y = a*R + b*G + c*B
+// R = Y + e*V
+// G = Y - c*d/b*U - a*e/b*V
+// B = Y + d*U
+
+// BT2020:
+// a = .2627, b = 0.6780, c = 0.0593
+// d = 1.8814
+// e = 1.4746
+//
+// BT709:
+// a = 0.2126, b = 0.7152, c = 0.0722
+// d = 1.8556
+// e = 1.5748
+//
+// BT601:
+// a = 0.299, b = 0.578, c = 0.114
+// d = 1.42
+// e = 1.772
+//
+
+// clang-format off
+static QMatrix4x4 colorMatrix(const QVideoFrameFormat &format)
{
+ auto colorSpace = format.colorSpace();
+ if (colorSpace == QVideoFrameFormat::ColorSpace_Undefined) {
+ if (format.frameHeight() > 576)
+ // HD video, assume BT709
+ colorSpace = QVideoFrameFormat::ColorSpace_BT709;
+ else
+ // SD video, assume BT601
+ colorSpace = QVideoFrameFormat::ColorSpace_BT601;
+ }
switch (colorSpace) {
- case QVideoFrameFormat::YCbCr_JPEG:
- return QMatrix4x4(
+ case QVideoFrameFormat::ColorSpace_AdobeRgb:
+ return {
1.0f, 0.000f, 1.402f, -0.701f,
1.0f, -0.344f, -0.714f, 0.529f,
1.0f, 1.772f, 0.000f, -0.886f,
- 0.0f, 0.000f, 0.000f, 1.0000f);
- case QVideoFrameFormat::YCbCr_BT709:
- case QVideoFrameFormat::YCbCr_xvYCC709:
- return QMatrix4x4(
- 1.164f, 0.000f, 1.793f, -0.5727f,
- 1.164f, -0.534f, -0.213f, 0.3007f,
- 1.164f, 2.115f, 0.000f, -1.1302f,
- 0.0f, 0.000f, 0.000f, 1.0000f);
- default: //BT 601:
- return QMatrix4x4(
+ 0.0f, 0.000f, 0.000f, 1.000f
+ };
+ default:
+ case QVideoFrameFormat::ColorSpace_BT709:
+ if (format.colorRange() == QVideoFrameFormat::ColorRange_Full)
+ return {
+ 1.0f, 0.0f, 1.5748f, -0.790488f,
+ 1.0f, -0.187324f, -0.468124f, 0.329010f,
+ 1.0f, 1.855600f, 0.0f, -0.931439f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ return {
+ 1.1644f, 0.0000f, 1.7927f, -0.9729f,
+ 1.1644f, -0.2132f, -0.5329f, 0.3015f,
+ 1.1644f, 2.1124f, 0.0000f, -1.1334f,
+ 0.0000f, 0.0000f, 0.0000f, 1.0000f
+ };
+ case QVideoFrameFormat::ColorSpace_BT2020:
+ if (format.colorRange() == QVideoFrameFormat::ColorRange_Full)
+ return {
+ 1.f, 0.0000f, 1.4746f, -0.7402f,
+ 1.f, -0.1646f, -0.5714f, 0.3694f,
+ 1.f, 1.8814f, 0.000f, -0.9445f,
+ 0.0f, 0.0000f, 0.000f, 1.0000f
+ };
+ return {
+ 1.1644f, 0.000f, 1.6787f, -0.9157f,
+ 1.1644f, -0.1874f, -0.6504f, 0.3475f,
+ 1.1644f, 2.1418f, 0.0000f, -1.1483f,
+ 0.0000f, 0.0000f, 0.0000f, 1.0000f
+ };
+ case QVideoFrameFormat::ColorSpace_BT601:
+ // Corresponds to the primaries used by NTSC BT601. For PAL BT601, we use the BT709 conversion
+ // as those are very close.
+ if (format.colorRange() == QVideoFrameFormat::ColorRange_Full)
+ return {
+ 1.f, 0.000f, 1.772f, -0.886f,
+ 1.f, -0.1646f, -0.57135f, 0.36795f,
+ 1.f, 1.42f, 0.000f, -0.71f,
+ 0.0f, 0.000f, 0.000f, 1.0000f
+ };
+ return {
1.164f, 0.000f, 1.596f, -0.8708f,
1.164f, -0.392f, -0.813f, 0.5296f,
- 1.164f, 2.017f, 0.000f, -1.081f,
- 0.0f, 0.000f, 0.000f, 1.0000f);
+ 1.164f, 2.017f, 0.000f, -1.0810f,
+ 0.000f, 0.000f, 0.000f, 1.0000f
+ };
}
}
+// clang-format on
-#if 0
-static QMatrix4x4 yuvColorCorrectionMatrix(float brightness, float contrast, float hue, float saturation)
+// PQ transfer function, see also https://en.wikipedia.org/wiki/Perceptual_quantizer
+// or https://ieeexplore.ieee.org/document/7291452
+static float convertPQFromLinear(float sig)
{
- // Color correction in YUV space is done as follows:
-
- // The formulas assumes values in range 0-255, and a blackpoint of Y=16, whitepoint of Y=235
- //
- // Bightness: b
- // Contrast: c
- // Hue: h
- // Saturation: s
- //
- // Y' = (Y - 16)*c + b + 16
- // U' = ((U - 128)*cos(h) + (V - 128)*sin(h))*c*s + 128
- // V' = ((V - 128)*cos(h) - (U - 128)*sin(h))*c*s + 128
- //
- // For normalized YUV values (0-1 range) as we have them in the pixel shader, this translates to:
- //
- // Y' = (Y - .0625)*c + b + .0625
- // U' = ((U - .5)*cos(h) + (V - .5)*sin(h))*c*s + .5
- // V' = ((V - .5)*cos(h) - (U - .5)*sin(h))*c*s + .5
- //
- // The values need to be clamped to 0-1 after the correction and before converting to RGB
- // The transformation can be encoded in a 4x4 matrix assuming we have an A component of 1
-
- float chcs = cos(hue)*contrast*saturation;
- float shcs = sin(hue)*contrast*saturation;
- return QMatrix4x4(contrast, 0, 0, .0625*(1 - contrast) + brightness,
- 0, chcs, shcs, .5*(1 - chcs - shcs),
- 0, -shcs, chcs, .5*(1 + shcs - chcs),
- 0, 0, 0, 1);
+ const float m1 = 1305.f/8192.f;
+ const float m2 = 2523.f/32.f;
+ const float c1 = 107.f/128.f;
+ const float c2 = 2413.f/128.f;
+ const float c3 = 2392.f/128.f;
+
+ const float SDR_LEVEL = 100.f;
+ sig *= SDR_LEVEL/10000.f;
+ float psig = powf(sig, m1);
+ float num = c1 + c2*psig;
+ float den = 1 + c3*psig;
+ return powf(num/den, m2);
+}
+
+float convertHLGFromLinear(float sig)
+{
+ const float a = 0.17883277f;
+ const float b = 0.28466892f; // = 1 - 4a
+ const float c = 0.55991073f; // = 0.5 - a ln(4a)
+
+ if (sig < 1.f/12.f)
+ return sqrtf(3.f*sig);
+ return a*logf(12.f*sig - b) + c;
+}
+
+static float convertSDRFromLinear(float sig)
+{
+ return sig;
}
-#endif
-void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity)
+void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity, float maxNits)
{
#ifndef Q_OS_ANDROID
Q_UNUSED(frame);
@@ -402,9 +483,9 @@ void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const Q
QMatrix4x4 cmat;
switch (format.pixelFormat()) {
case QVideoFrameFormat::Format_Invalid:
- case QVideoFrameFormat::Format_Jpeg:
return;
+ case QVideoFrameFormat::Format_Jpeg:
case QVideoFrameFormat::Format_ARGB8888:
case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
case QVideoFrameFormat::Format_XRGB8888:
@@ -426,6 +507,7 @@ void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const Q
case QVideoFrameFormat::Format_AYUV:
case QVideoFrameFormat::Format_AYUV_Premultiplied:
case QVideoFrameFormat::Format_YUV420P:
+ case QVideoFrameFormat::Format_YUV420P10:
case QVideoFrameFormat::Format_YUV422P:
case QVideoFrameFormat::Format_YV12:
case QVideoFrameFormat::Format_UYVY:
@@ -434,16 +516,11 @@ void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const Q
case QVideoFrameFormat::Format_NV21:
case QVideoFrameFormat::Format_P010:
case QVideoFrameFormat::Format_P016:
- cmat = colorMatrix(format.yCbCrColorSpace());
+ cmat = colorMatrix(format);
break;
case QVideoFrameFormat::Format_SamplerExternalOES:
-#ifdef Q_OS_ANDROID
- {
// get Android specific transform for the externalsampler texture
- if (auto *buffer = static_cast<AndroidTextureVideoBuffer *>(frame.videoBuffer()))
- cmat = buffer->externalTextureMatrix();
- }
-#endif
+ cmat = frame.videoBuffer()->externalTextureMatrix();
break;
case QVideoFrameFormat::Format_SamplerRect:
{
@@ -456,97 +533,232 @@ void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const Q
}
break;
}
- // { matrix, colorMatrix, opacity, width }
- Q_ASSERT(dst->size() >= 64 + 64 + 4 + 4);
- char *data = dst->data();
- memcpy(data, transform.constData(), 64);
- memcpy(data + 64, cmat.constData(), 64);
- memcpy(data + 64 + 64, &opacity, 4);
- float width = format.frameWidth();
- memcpy(data + 64 + 64 + 4, &width, 4);
+
+ // HDR with a PQ or HLG transfer function uses a BT2390 based tone mapping to cut off the HDR peaks
+ // This requires that we pass the max luminance the tonemapper should clip to over to the fragment
+ // shader. To reduce computations there, it's precomputed in PQ values here.
+ auto fromLinear = convertSDRFromLinear;
+ switch (format.colorTransfer()) {
+ case QVideoFrameFormat::ColorTransfer_ST2084:
+ fromLinear = convertPQFromLinear;
+ break;
+ case QVideoFrameFormat::ColorTransfer_STD_B67:
+ fromLinear = convertHLGFromLinear;
+ break;
+ default:
+ break;
+ }
+
+ if (dst->size() < qsizetype(sizeof(UniformData)))
+ dst->resize(sizeof(UniformData));
+
+ auto ud = reinterpret_cast<UniformData*>(dst->data());
+ memcpy(ud->transformMatrix, transform.constData(), sizeof(ud->transformMatrix));
+ memcpy(ud->colorMatrix, cmat.constData(), sizeof(ud->transformMatrix));
+ ud->opacity = opacity;
+ ud->width = float(format.frameWidth());
+ ud->masteringWhite = fromLinear(float(format.maxLuminance())/100.f);
+ ud->maxLum = fromLinear(float(maxNits)/100.f);
}
-int updateRhiTextures(QVideoFrame frame, QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates, QRhiTexture **textures)
+enum class UpdateTextureWithMapResult : uint8_t {
+ Failed,
+ UpdatedWithDataCopy,
+ UpdatedWithDataReference
+};
+
+static UpdateTextureWithMapResult updateTextureWithMap(const QVideoFrame &frame, QRhi *rhi,
+ QRhiResourceUpdateBatch *rub, int plane,
+ std::unique_ptr<QRhiTexture> &tex)
{
+ Q_ASSERT(frame.isMapped());
+
QVideoFrameFormat fmt = frame.surfaceFormat();
QVideoFrameFormat::PixelFormat pixelFormat = fmt.pixelFormat();
QSize size = fmt.frameSize();
- const TextureDescription *description = descriptions + pixelFormat;
+ const TextureDescription &texDesc = descriptions[pixelFormat];
+ QSize planeSize(size.width()/texDesc.sizeScale[plane].x, size.height()/texDesc.sizeScale[plane].y);
+
+ bool needsRebuild = !tex || tex->pixelSize() != planeSize || tex->format() != texDesc.textureFormat[plane];
+ if (!tex) {
+ tex.reset(rhi->newTexture(texDesc.textureFormat[plane], planeSize, 1, {}));
+ if (!tex) {
+ qWarning("Failed to create new texture (size %dx%d)", planeSize.width(), planeSize.height());
+ return UpdateTextureWithMapResult::Failed;
+ }
+ }
+
+ if (needsRebuild) {
+ tex->setFormat(texDesc.textureFormat[plane]);
+ tex->setPixelSize(planeSize);
+ if (!tex->create()) {
+ qWarning("Failed to create texture (size %dx%d)", planeSize.width(), planeSize.height());
+ return UpdateTextureWithMapResult::Failed;
+ }
+ }
+
+ auto result = UpdateTextureWithMapResult::UpdatedWithDataCopy;
+
+ QRhiTextureSubresourceUploadDescription subresDesc;
+
+ if (pixelFormat == QVideoFrameFormat::Format_Jpeg) {
+ Q_ASSERT(plane == 0);
+
+ QImage image;
+
+ // calling QVideoFrame::toImage is not accurate. To be fixed.
+ image = frame.toImage();
+ image.convertTo(QImage::Format_ARGB32);
+ subresDesc.setImage(image);
+
+ } else {
+ // Note, QByteArray::fromRawData creare QByteArray as a view without data copying
+ subresDesc.setData(QByteArray::fromRawData(
+ reinterpret_cast<const char *>(frame.bits(plane)), frame.mappedBytes(plane)));
+ subresDesc.setDataStride(frame.bytesPerLine(plane));
+ result = UpdateTextureWithMapResult::UpdatedWithDataReference;
+ }
+
+ QRhiTextureUploadEntry entry(0, 0, subresDesc);
+ QRhiTextureUploadDescription desc({ entry });
+ rub->uploadTexture(tex.get(), desc);
+
+ return result;
+}
+
+static std::unique_ptr<QRhiTexture> createTextureFromHandle(const QVideoFrame &frame, QRhi *rhi, int plane)
+{
+ QVideoFrameFormat fmt = frame.surfaceFormat();
+ QVideoFrameFormat::PixelFormat pixelFormat = fmt.pixelFormat();
+ QSize size = fmt.frameSize();
- QSize planeSizes[TextureDescription::maxPlanes];
- for (int plane = 0; plane < description->nplanes; ++plane)
- planeSizes[plane] = QSize(size.width()/description->sizeScale[plane].x, size.height()/description->sizeScale[plane].y);
+ const TextureDescription &texDesc = descriptions[pixelFormat];
+ QSize planeSize(size.width()/texDesc.sizeScale[plane].x, size.height()/texDesc.sizeScale[plane].y);
- if (frame.handleType() == QVideoFrame::RhiTextureHandle) {
- QRhiTexture::Flags textureFlags = {};
- if (pixelFormat == QVideoFrameFormat::Format_SamplerExternalOES) {
+ QRhiTexture::Flags textureFlags = {};
+ if (pixelFormat == QVideoFrameFormat::Format_SamplerExternalOES) {
#ifdef Q_OS_ANDROID
- if (rhi->backend() == QRhi::OpenGLES2)
- textureFlags |= QRhiTexture::ExternalOES;
+ if (rhi->backend() == QRhi::OpenGLES2)
+ textureFlags |= QRhiTexture::ExternalOES;
#endif
- }
- if (pixelFormat == QVideoFrameFormat::Format_SamplerRect) {
+ }
+ if (pixelFormat == QVideoFrameFormat::Format_SamplerRect) {
#ifdef Q_OS_MACOS
- if (rhi->backend() == QRhi::OpenGLES2)
- textureFlags |= QRhiTexture::TextureRectangleGL;
+ if (rhi->backend() == QRhi::OpenGLES2)
+ textureFlags |= QRhiTexture::TextureRectangleGL;
#endif
- }
- for (int plane = 0; plane < description->nplanes; ++plane) {
- quint64 nativeTexture = frame.textureHandle(plane);
- if (!nativeTexture)
- qWarning("Texture from QVideoFrame is 0, this cannot be right");
- textures[plane] = rhi->newTexture(description->textureFormat[plane], planeSizes[plane], 1, textureFlags);
- if (!textures[plane]->createFrom({nativeTexture, 0}))
- qWarning("Failed to initialize QRhiTexture wrapper for native texture object %llu", nativeTexture);
- }
- return description->nplanes;
}
- // need to upload textures
- bool mapped = frame.map(QVideoFrame::ReadOnly);
- if (!mapped) {
- qWarning() << "could not map data of QVideoFrame for upload";
- return 0;
+ if (quint64 handle = frame.videoBuffer()->textureHandle(rhi, plane); handle) {
+ std::unique_ptr<QRhiTexture> tex(rhi->newTexture(texDesc.textureFormat[plane], planeSize, 1, textureFlags));
+ if (tex->createFrom({handle, 0}))
+ return tex;
+
+ qWarning("Failed to initialize QRhiTexture wrapper for native texture object %llu",handle);
+ }
+ return {};
+}
+
+class QVideoFrameTexturesArray : public QVideoFrameTextures
+{
+public:
+ using TextureArray = std::array<std::unique_ptr<QRhiTexture>, TextureDescription::maxPlanes>;
+ QVideoFrameTexturesArray(TextureArray &&textures, QVideoFrame mappedFrame = {})
+ : m_textures(std::move(textures)), m_mappedFrame(std::move(mappedFrame))
+ {
+ Q_ASSERT(!m_mappedFrame.isValid() || m_mappedFrame.isReadable());
}
- Q_ASSERT(frame.planeCount() == description->nplanes);
- for (int plane = 0; plane < description->nplanes; ++plane) {
+ // We keep the source frame mapped during the target texture lifetime.
+ // Alternatively, we may use setting a custom image to QRhiTextureSubresourceUploadDescription,
+ // unsig videoFramePlaneAsImage, however, the OpenGL rendering pipeline in QRhi
+ // may keep QImage, and consequently the mapped QVideoFrame,
+ // even after the target texture is deleted: QTBUG-123174.
+ ~QVideoFrameTexturesArray() { m_mappedFrame.unmap(); }
+
+ QRhiTexture *texture(uint plane) const override
+ {
+ return plane < std::size(m_textures) ? m_textures[plane].get() : nullptr;
+ }
- bool needsRebuild = !textures[plane] || textures[plane]->pixelSize() != planeSizes[plane];
- if (!textures[plane])
- textures[plane] = rhi->newTexture(description->textureFormat[plane], planeSizes[plane], 1, {});
+ TextureArray takeTextures() { return std::move(m_textures); }
- if (needsRebuild) {
- textures[plane]->setPixelSize(planeSizes[plane]);
- bool created = textures[plane]->create();
- if (!created) {
- qWarning("Failed to create texture (size %dx%d)", planeSizes[plane].width(), planeSizes[plane].height());
- return 0;
- }
- }
+private:
+ TextureArray m_textures;
+ QVideoFrame m_mappedFrame;
+};
- auto data = QByteArray::fromRawData((const char *)frame.bits(plane), frame.mappedBytes(plane));
- QRhiTextureSubresourceUploadDescription subresDesc(data);
- subresDesc.setDataStride(frame.bytesPerLine(plane));
- QRhiTextureUploadEntry entry(0, 0, subresDesc);
- QRhiTextureUploadDescription desc({ entry });
- resourceUpdates->uploadTexture(textures[plane], desc);
+static std::unique_ptr<QVideoFrameTextures> createTexturesFromHandles(const QVideoFrame &frame, QRhi *rhi)
+{
+ const TextureDescription &texDesc = descriptions[frame.surfaceFormat().pixelFormat()];
+ bool ok = true;
+ QVideoFrameTexturesArray::TextureArray textures;
+ for (quint8 plane = 0; plane < texDesc.nplanes; ++plane) {
+ textures[plane] = QVideoTextureHelper::createTextureFromHandle(frame, rhi, plane);
+ ok &= bool(textures[plane]);
+ }
+ if (ok)
+ return std::make_unique<QVideoFrameTexturesArray>(std::move(textures));
+ else
+ return {};
+}
+
+static std::unique_ptr<QVideoFrameTextures> createTexturesFromMemory(QVideoFrame frame, QRhi *rhi, QRhiResourceUpdateBatch *rub, QVideoFrameTextures *old)
+{
+ const TextureDescription &texDesc = descriptions[frame.surfaceFormat().pixelFormat()];
+ QVideoFrameTexturesArray::TextureArray textures;
+ auto oldArray = dynamic_cast<QVideoFrameTexturesArray *>(old);
+ if (oldArray)
+ textures = oldArray->takeTextures();
+
+ if (!frame.map(QVideoFrame::ReadOnly)) {
+ qWarning() << "Cannot map a video frame in ReadOnly mode!";
+ return {};
+ }
+
+ auto unmapFrameGuard = qScopeGuard([&frame] { frame.unmap(); });
+
+ bool shouldKeepMapping = false;
+ for (quint8 plane = 0; plane < texDesc.nplanes; ++plane) {
+ const auto result = updateTextureWithMap(frame, rhi, rub, plane, textures[plane]);
+ if (result == UpdateTextureWithMapResult::Failed)
+ return {};
+
+ if (result == UpdateTextureWithMapResult::UpdatedWithDataReference)
+ shouldKeepMapping = true;
}
- return description->nplanes;
+
+ // as QVideoFrame::unmap does nothing with null frames, we just move the frame to the result
+ return std::make_unique<QVideoFrameTexturesArray>(
+ std::move(textures), shouldKeepMapping ? std::move(frame) : QVideoFrame());
+}
+
+std::unique_ptr<QVideoFrameTextures> createTextures(QVideoFrame &frame, QRhi *rhi, QRhiResourceUpdateBatch *rub, std::unique_ptr<QVideoFrameTextures> &&oldTextures)
+{
+ QAbstractVideoBuffer *vf = frame.videoBuffer();
+ if (!vf)
+ return {};
+
+ if (auto vft = vf->mapTextures(rhi))
+ return vft;
+
+ if (auto vft = createTexturesFromHandles(frame, rhi))
+ return vft;
+
+ return createTexturesFromMemory(frame, rhi, rub, oldTextures.get());
}
-bool SubtitleLayout::updateFromVideoFrame(const QVideoFrame &frame)
+bool SubtitleLayout::update(const QSize &frameSize, QString text)
{
- auto text = frame.subtitleText();
text.replace(QLatin1Char('\n'), QChar::LineSeparator);
- if (layout.text() == text && videoSize == frame.size())
+ if (layout.text() == text && videoSize == frameSize)
return false;
- videoSize = frame.size();
+ videoSize = frameSize;
QFont font;
// 0.045 - based on this https://www.md-subs.com/saa-subtitle-font-size
- qreal fontSize = videoSize.height() * 0.045;
+ qreal fontSize = frameSize.height() * 0.045;
font.setPointSize(fontSize);
layout.setText(text);
@@ -591,11 +803,10 @@ bool SubtitleLayout::updateFromVideoFrame(const QVideoFrame &frame)
return true;
}
-void SubtitleLayout::draw(QPainter *painter, const QRectF &videoRect) const
+void SubtitleLayout::draw(QPainter *painter, const QPointF &translate) const
{
painter->save();
- painter->translate(videoRect.topLeft());
- painter->scale(videoRect.width()/videoSize.width(), videoRect.height()/videoSize.height());
+ painter->translate(translate);
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
QColor bgColor = Qt::black;
diff --git a/src/multimedia/video/qvideotexturehelper_p.h b/src/multimedia/video/qvideotexturehelper_p.h
index 168ce8a86..982c1b48a 100644
--- a/src/multimedia/video/qvideotexturehelper_p.h
+++ b/src/multimedia/video/qvideotexturehelper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVIDEOTEXTUREHELPER_H
#define QVIDEOTEXTUREHELPER_H
@@ -52,7 +16,7 @@
//
#include <qvideoframeformat.h>
-#include <private/qrhi_p.h>
+#include <rhi/qrhi.h>
#include <QtGui/qtextlayout.h>
@@ -60,6 +24,7 @@ QT_BEGIN_NAMESPACE
class QVideoFrame;
class QTextLayout;
+class QVideoFrameTextures;
namespace QVideoTextureHelper
{
@@ -95,11 +60,20 @@ struct TextureDescription
Q_MULTIMEDIA_EXPORT const TextureDescription *textureDescription(QVideoFrameFormat::PixelFormat format);
-Q_MULTIMEDIA_EXPORT QString vertexShaderFileName(QVideoFrameFormat::PixelFormat format);
-Q_MULTIMEDIA_EXPORT QString fragmentShaderFileName(QVideoFrameFormat::PixelFormat format);
-Q_MULTIMEDIA_EXPORT void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity);
-Q_MULTIMEDIA_EXPORT int updateRhiTextures(QVideoFrame frame, QRhi *rhi,
- QRhiResourceUpdateBatch *resourceUpdates, QRhiTexture **textures);
+Q_MULTIMEDIA_EXPORT QString vertexShaderFileName(const QVideoFrameFormat &format);
+Q_MULTIMEDIA_EXPORT QString fragmentShaderFileName(const QVideoFrameFormat &format, QRhiSwapChain::Format surfaceFormat = QRhiSwapChain::SDR);
+Q_MULTIMEDIA_EXPORT void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const QVideoFrame &frame,
+ const QMatrix4x4 &transform, float opacity, float maxNits = 100);
+Q_MULTIMEDIA_EXPORT std::unique_ptr<QVideoFrameTextures> createTextures(QVideoFrame &frame, QRhi *rhi, QRhiResourceUpdateBatch *rub, std::unique_ptr<QVideoFrameTextures> &&oldTextures);
+
+struct UniformData {
+ float transformMatrix[4][4];
+ float colorMatrix[4][4];
+ float opacity;
+ float width;
+ float masteringWhite;
+ float maxLum;
+};
struct Q_MULTIMEDIA_EXPORT SubtitleLayout
{
@@ -107,8 +81,8 @@ struct Q_MULTIMEDIA_EXPORT SubtitleLayout
QRectF bounds;
QTextLayout layout;
- bool updateFromVideoFrame(const QVideoFrame &frame);
- void draw(QPainter *painter, const QRectF &videoRect) const;
+ bool update(const QSize &frameSize, QString text);
+ void draw(QPainter *painter, const QPointF &translate) const;
QImage toImage() const;
};
diff --git a/src/multimedia/video/qvideowindow.cpp b/src/multimedia/video/qvideowindow.cpp
index f0ae26b98..9cab23f5f 100644
--- a/src/multimedia/video/qvideowindow.cpp
+++ b/src/multimedia/video/qvideowindow.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvideowindow_p.h"
#include <QPlatformSurfaceEvent>
#include <qfile.h>
#include <qpainter.h>
#include <private/qguiapplication_p.h>
+#include <private/qmemoryvideobuffer_p.h>
+#include <private/qmultimediautils_p.h>
#include <qpa/qplatformintegration.h>
QT_BEGIN_NAMESPACE
@@ -54,13 +20,18 @@ static QSurface::SurfaceType platformSurfaceType()
return QSurface::Direct3DSurface;
#endif
- if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL))
+ auto *integration = QGuiApplicationPrivate::platformIntegration();
+
+ if (!integration->hasCapability(QPlatformIntegration::OpenGL))
return QSurface::RasterSurface;
- if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)
- || QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets))
+
+ if (QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets))
return QSurface::RasterSurface;
- return QSurface::RasterGLSurface;
+ if (integration->hasCapability(QPlatformIntegration::RasterGLSurface))
+ return QSurface::RasterGLSurface;
+
+ return QSurface::OpenGLSurface;
}
QVideoWindowPrivate::QVideoWindowPrivate(QVideoWindow *q)
@@ -99,18 +70,36 @@ QVideoWindowPrivate::QVideoWindowPrivate(QVideoWindow *q)
QVideoWindowPrivate::~QVideoWindowPrivate()
{
- freeTextures();
+ QObject::disconnect(m_sink.get(), &QVideoSink::videoFrameChanged,
+ q, &QVideoWindow::setVideoFrame);
}
-
-static const float g_quad[] = {
+static const float g_vw_quad[] = {
+ // 4 clockwise rotation of texture vertexes (the second pair)
+ // Rotation 0
-1.f, -1.f, 0.f, 0.f,
-1.f, 1.f, 0.f, 1.f,
1.f, -1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f,
+ // Rotation 90
+ -1.f, -1.f, 0.f, 1.f,
+ -1.f, 1.f, 1.f, 1.f,
+ 1.f, -1.f, 0.f, 0.f,
+ 1.f, 1.f, 1.f, 0.f,
+
+ // Rotation 180
+ -1.f, -1.f, 1.f, 1.f,
+ -1.f, 1.f, 1.f, 0.f,
+ 1.f, -1.f, 0.f, 1.f,
+ 1.f, 1.f, 0.f, 0.f,
+ // Rotation 270
+ -1.f, -1.f, 1.f, 0.f,
+ -1.f, 1.f, 0.f, 0.f,
+ 1.f, -1.f, 1.f, 1.f,
+ 1.f, 1.f, 0.f, 1.f
};
-static QShader getShader(const QString &name)
+static QShader vwGetShader(const QString &name)
{
QFile f(name);
if (f.open(QIODevice::ReadOnly))
@@ -168,11 +157,11 @@ void QVideoWindowPrivate::initRhi()
m_renderPass.reset(m_swapChain->newCompatibleRenderPassDescriptor());
m_swapChain->setRenderPassDescriptor(m_renderPass.get());
- m_vertexBuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(g_quad)));
+ m_vertexBuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(g_vw_quad)));
m_vertexBuf->create();
m_vertexBufReady = false;
- m_uniformBuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 64 + 4 + 4));
+ m_uniformBuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, sizeof(QVideoTextureHelper::UniformData)));
m_uniformBuf->create();
m_textureSampler.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
@@ -182,17 +171,19 @@ void QVideoWindowPrivate::initRhi()
m_shaderResourceBindings.reset(m_rhi->newShaderResourceBindings());
m_subtitleResourceBindings.reset(m_rhi->newShaderResourceBindings());
- m_subtitleUniformBuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 64 + 4 + 4));
+ m_subtitleUniformBuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, sizeof(QVideoTextureHelper::UniformData)));
m_subtitleUniformBuf->create();
+
+ Q_ASSERT(NVideoFrameSlots >= m_rhi->resourceLimit(QRhi::FramesInFlight));
}
-void QVideoWindowPrivate::setupGraphicsPipeline(QRhiGraphicsPipeline *pipeline, QRhiShaderResourceBindings *bindings, QVideoFrameFormat::PixelFormat fmt)
+void QVideoWindowPrivate::setupGraphicsPipeline(QRhiGraphicsPipeline *pipeline, QRhiShaderResourceBindings *bindings, const QVideoFrameFormat &fmt)
{
pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
- QShader vs = getShader(QVideoTextureHelper::vertexShaderFileName(fmt));
+ QShader vs = vwGetShader(QVideoTextureHelper::vertexShaderFileName(fmt));
Q_ASSERT(vs.isValid());
- QShader fs = getShader(QVideoTextureHelper::fragmentShaderFileName(fmt));
+ QShader fs = vwGetShader(QVideoTextureHelper::fragmentShaderFileName(fmt, m_swapChain->format()));
Q_ASSERT(fs.isValid());
pipeline->setShaderStages({
{ QRhiShaderStage::Vertex, vs },
@@ -216,34 +207,26 @@ void QVideoWindowPrivate::updateTextures(QRhiResourceUpdateBatch *rub)
{
m_texturesDirty = false;
- auto fmt = m_currentFrame.pixelFormat();
- if (fmt == QVideoFrameFormat::Format_Invalid)
- // We render a 1x1 black pixel when we don't have a video
- fmt = QVideoFrameFormat::Format_RGBA8888;
-
- auto textureDesc = QVideoTextureHelper::textureDescription(fmt);
-
- m_frameSize = m_currentFrame.isValid() ? m_currentFrame.size() : QSize(1, 1);
-
- freeTextures();
- if (m_currentFrame.isValid()) {
- QVideoTextureHelper::updateRhiTextures(m_currentFrame, m_rhi.get(), rub, m_frameTextures);
- } else {
- Q_ASSERT(fmt == QVideoFrameFormat::Format_RGBA8888);
- QImage img(QSize(1, 1), QImage::Format_RGBA8888);
- img.fill(Qt::black);
- m_frameTextures[0] = m_rhi->newTexture(QRhiTexture::RGBA8, m_frameSize, 1);
- m_frameTextures[0]->create();
- rub->uploadTexture(m_frameTextures[0], img);
- }
+ // We render a 1x1 black pixel when we don't have a video
+ if (!m_currentFrame.isValid())
+ m_currentFrame = QVideoFrame(new QMemoryVideoBuffer(QByteArray{4, 0}, 4),
+ QVideoFrameFormat(QSize(1,1), QVideoFrameFormat::Format_RGBA8888));
+
+ m_frameTextures = QVideoTextureHelper::createTextures(m_currentFrame, m_rhi.get(), rub, std::move(m_frameTextures));
+ if (!m_frameTextures)
+ return;
QRhiShaderResourceBinding bindings[4];
auto *b = bindings;
*(b++) = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
m_uniformBuf.get());
+
+ auto fmt = m_currentFrame.surfaceFormat();
+ auto textureDesc = QVideoTextureHelper::textureDescription(fmt.pixelFormat());
+
for (int i = 0; i < textureDesc->nplanes; ++i)
(*b++) = QRhiShaderResourceBinding::sampledTexture(i + 1, QRhiShaderResourceBinding::FragmentStage,
- m_frameTextures[i], m_textureSampler.get());
+ m_frameTextures->texture(i), m_textureSampler.get());
m_shaderResourceBindings->setBindings(bindings, b);
m_shaderResourceBindings->create();
@@ -256,14 +239,14 @@ void QVideoWindowPrivate::updateTextures(QRhiResourceUpdateBatch *rub)
}
}
-void QVideoWindowPrivate::updateSubtitle(QRhiResourceUpdateBatch *rub)
+void QVideoWindowPrivate::updateSubtitle(QRhiResourceUpdateBatch *rub, const QSize &frameSize)
{
m_subtitleDirty = false;
m_hasSubtitle = !m_currentFrame.subtitleText().isEmpty();
if (!m_hasSubtitle)
return;
- m_subtitleLayout.updateFromVideoFrame(m_currentFrame);
+ m_subtitleLayout.update(frameSize, m_currentFrame.subtitleText());
QSize size = m_subtitleLayout.bounds.size().toSize();
QImage img = m_subtitleLayout.toImage();
@@ -288,16 +271,7 @@ void QVideoWindowPrivate::updateSubtitle(QRhiResourceUpdateBatch *rub)
QRhiGraphicsPipeline::TargetBlend blend;
blend.enable = true;
m_subtitlePipeline->setTargetBlends({ blend });
- setupGraphicsPipeline(m_subtitlePipeline.get(), m_subtitleResourceBindings.get(), QVideoFrameFormat::Format_RGBA8888);
- }
-}
-
-void QVideoWindowPrivate::freeTextures()
-{
- for (int i = 0; i < 3; ++i) {
- if (m_frameTextures[i])
- delete m_frameTextures[i];
- m_frameTextures[i] = nullptr;
+ setupGraphicsPipeline(m_subtitlePipeline.get(), m_subtitleResourceBindings.get(), QVideoFrameFormat(QSize(1, 1), QVideoFrameFormat::Format_RGBA8888));
}
}
@@ -357,17 +331,34 @@ void QVideoWindowPrivate::render()
return;
}
- QSize scaled = m_currentFrame.size().scaled(rect.size(), aspectRatioMode);
+ const int frameRotationIndex = (static_cast<int>(m_currentFrame.rotation()) / 90) % 4;
+ QSize frameSize = m_currentFrame.size();
+ if (frameRotationIndex % 2)
+ frameSize.transpose();
+ QSize scaled = frameSize.scaled(rect.size(), aspectRatioMode);
QRect videoRect = QRect(QPoint(0, 0), scaled);
videoRect.moveCenter(rect.center());
+ QRect subtitleRect = videoRect.intersected(rect);
+
+ if (!m_hasSwapChain || (m_swapChain->currentPixelSize() != m_swapChain->surfacePixelSize()))
+ resizeSwapChain();
- if (m_swapChain->currentPixelSize() != m_swapChain->surfacePixelSize())
+ const auto requiredSwapChainFormat =
+ qGetRequiredSwapChainFormat(m_currentFrame.surfaceFormat());
+ if (qShouldUpdateSwapChainFormat(m_swapChain.get(), requiredSwapChainFormat)) {
+ releaseSwapChain();
+ m_swapChain->setFormat(requiredSwapChainFormat);
resizeSwapChain();
+ }
if (!m_hasSwapChain)
return;
QRhi::FrameOpResult r = m_rhi->beginFrame(m_swapChain.get());
+
+ // keep the video frames alive until we know that they are not needed anymore
+ m_videoFrameSlots[m_rhi->currentFrameSlot()] = m_currentFrame;
+
if (r == QRhi::FrameOpSwapChainOutOfDate) {
resizeSwapChain();
if (!m_hasSwapChain)
@@ -384,44 +375,44 @@ void QVideoWindowPrivate::render()
if (!m_vertexBufReady) {
m_vertexBufReady = true;
- rub->uploadStaticBuffer(m_vertexBuf.get(), g_quad);
+ rub->uploadStaticBuffer(m_vertexBuf.get(), g_vw_quad);
}
if (m_texturesDirty)
updateTextures(rub);
- if (m_subtitleDirty)
- updateSubtitle(rub);
+ if (m_subtitleDirty || m_subtitleLayout.videoSize != subtitleRect.size())
+ updateSubtitle(rub, subtitleRect.size());
+
+ float mirrorFrame = m_currentFrame.mirrored() ? -1.f : 1.f;
+ float xscale = mirrorFrame * float(videoRect.width())/float(rect.width());
+ float yscale = -1.f * float(videoRect.height())/float(rect.height());
- float xscale = 1.f - float(rect.width() - videoRect.width())/float(rect.width());
- float yscale = -1.f + float(rect.height() - videoRect.height())/float(rect.height());
+ QMatrix4x4 transform;
+ transform.scale(xscale, yscale);
- QMatrix4x4 transform = {
- xscale, 0, 0, 0,
- 0, yscale, 0, 0,
- 0, 0, 1.f, 0,
- 0, 0, 0, 1.f
- };
+ float maxNits = 100;
+ if (m_swapChain->format() == QRhiSwapChain::HDRExtendedSrgbLinear) {
+ auto info = m_swapChain->hdrInfo();
+ if (info.limitsType == QRhiSwapChainHdrInfo::ColorComponentValue)
+ maxNits = 100 * info.limits.colorComponentValue.maxColorComponentValue;
+ else
+ maxNits = info.limits.luminanceInNits.maxLuminance;
+ }
- QByteArray uniformData(64 + 64 + 4 + 4, Qt::Uninitialized);
- QVideoTextureHelper::updateUniformData(&uniformData, m_currentFrame.surfaceFormat(), m_currentFrame, transform, 1.f);
+ QByteArray uniformData;
+ QVideoTextureHelper::updateUniformData(&uniformData, m_currentFrame.surfaceFormat(), m_currentFrame, transform, 1.f, maxNits);
rub->updateDynamicBuffer(m_uniformBuf.get(), 0, uniformData.size(), uniformData.constData());
if (m_hasSubtitle) {
- QMatrix4x4 t = {
- xscale, 0, 0, 0,
- 0, yscale, 0, 0,
- 0, 0, 1.f, 0,
- 0, 0, 0, 1.f
- };
- QSizeF frameSize = m_currentFrame.size();
- t.translate(0, 2.*m_subtitleLayout.bounds.center().y()/frameSize.height() - 1.);
- t.scale(m_subtitleLayout.bounds.width()/frameSize.width(),
- m_subtitleLayout.bounds.height()/frameSize.height());
-
- QByteArray uniformData(64 + 64 + 4 + 4, Qt::Uninitialized);
+ QMatrix4x4 st;
+ st.translate(0, -2.f * (float(m_subtitleLayout.bounds.center().y()) + float(subtitleRect.top()))/ float(rect.height()) + 1.f);
+ st.scale(float(m_subtitleLayout.bounds.width())/float(rect.width()),
+ -1.f * float(m_subtitleLayout.bounds.height())/float(rect.height()));
+
+ QByteArray uniformData;
QVideoFrameFormat fmt(m_subtitleLayout.bounds.size().toSize(), QVideoFrameFormat::Format_ARGB8888);
- QVideoTextureHelper::updateUniformData(&uniformData, fmt, QVideoFrame(), t, 1.f);
+ QVideoTextureHelper::updateUniformData(&uniformData, fmt, QVideoFrame(), st, 1.f);
rub->updateDynamicBuffer(m_subtitleUniformBuf.get(), 0, uniformData.size(), uniformData.constData());
}
@@ -432,7 +423,8 @@ void QVideoWindowPrivate::render()
cb->setViewport({ 0, 0, float(size.width()), float(size.height()) });
cb->setShaderResources(m_shaderResourceBindings.get());
- const QRhiCommandBuffer::VertexInput vbufBinding(m_vertexBuf.get(), 0);
+ quint32 vertexOffset = quint32(sizeof(float)) * 16 * frameRotationIndex;
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vertexBuf.get(), vertexOffset);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(4);
@@ -502,7 +494,7 @@ bool QVideoWindow::event(QEvent *e)
case QEvent::Expose:
d->isExposed = isExposed();
if (d->isExposed)
- requestUpdate();
+ d->render();
return true;
default:
@@ -532,3 +524,5 @@ void QVideoWindow::setVideoFrame(const QVideoFrame &frame)
}
QT_END_NAMESPACE
+
+#include "moc_qvideowindow_p.cpp"
diff --git a/src/multimedia/video/qvideowindow_p.h b/src/multimedia/video/qvideowindow_p.h
index c7324ec3f..3305d3b40 100644
--- a/src/multimedia/video/qvideowindow_p.h
+++ b/src/multimedia/video/qvideowindow_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVIDEOWINDOW_P_H
#define QVIDEOWINDOW_P_H
@@ -52,23 +16,9 @@
//
#include <QWindow>
-#include <qtextlayout.h>
-
-#include <QtGui/private/qrhinull_p.h>
-#if QT_CONFIG(opengl)
-#include <QtGui/private/qrhigles2_p.h>
#include <QOffscreenSurface>
-#endif
-#if QT_CONFIG(vulkan)
-#include <QtGui/private/qrhivulkan_p.h>
-#endif
-#ifdef Q_OS_WIN
-#include <QtGui/private/qrhid3d11_p.h>
-#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
-#include <QtGui/private/qrhimetal_p.h>
-#endif
-
+#include <qtextlayout.h>
+#include <rhi/qrhi.h>
#include <qvideoframe.h>
#include <private/qplatformvideosink_p.h>
#include <private/qvideotexturehelper_p.h>
@@ -95,10 +45,9 @@ public:
void releaseSwapChain();
void updateTextures(QRhiResourceUpdateBatch *rub);
- void updateSubtitle(QRhiResourceUpdateBatch *rub);
- void freeTextures();
+ void updateSubtitle(QRhiResourceUpdateBatch *rub, const QSize &frameSize);
- void setupGraphicsPipeline(QRhiGraphicsPipeline *pipeline, QRhiShaderResourceBindings *bindings, QVideoFrameFormat::PixelFormat fmt);
+ void setupGraphicsPipeline(QRhiGraphicsPipeline *pipeline, QRhiShaderResourceBindings *bindings, const QVideoFrameFormat &fmt);
QVideoWindow *q = nullptr;
Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio;
@@ -115,7 +64,7 @@ public:
std::unique_ptr<QRhiBuffer> m_vertexBuf;
bool m_vertexBufReady = false;
std::unique_ptr<QRhiBuffer> m_uniformBuf;
- QRhiTexture *m_frameTextures[3] = {};
+ std::unique_ptr<QVideoFrameTextures> m_frameTextures;
std::unique_ptr<QRhiSampler> m_textureSampler;
std::unique_ptr<QRhiShaderResourceBindings> m_shaderResourceBindings;
std::unique_ptr<QRhiGraphicsPipeline> m_graphicsPipeline;
@@ -127,10 +76,12 @@ public:
std::unique_ptr<QVideoSink> m_sink;
QRhi::Implementation m_graphicsApi = QRhi::Null;
- QSize m_frameSize = QSize(-1, -1);
QVideoFrame m_currentFrame;
QVideoTextureHelper::SubtitleLayout m_subtitleLayout;
+ enum { NVideoFrameSlots = 4 };
+ QVideoFrame m_videoFrameSlots[NVideoFrameSlots];
+
bool initialized = false;
bool isExposed = false;
bool m_useRhi = true;
@@ -138,7 +89,7 @@ public:
bool m_texturesDirty = true;
bool m_subtitleDirty = false;
bool m_hasSubtitle = false;
- QVideoFrameFormat::PixelFormat format = QVideoFrameFormat::Format_Invalid;
+ QVideoFrameFormat format;
};
class Q_MULTIMEDIA_EXPORT QVideoWindow : public QWindow
diff --git a/src/multimedia/wasm/qwasmaudiodevice.cpp b/src/multimedia/wasm/qwasmaudiodevice.cpp
new file mode 100644
index 000000000..c87a0ad54
--- /dev/null
+++ b/src/multimedia/wasm/qwasmaudiodevice.cpp
@@ -0,0 +1,56 @@
+// 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 "qwasmaudiodevice_p.h"
+#include <emscripten.h>
+#include <emscripten/val.h>
+#include <emscripten/bind.h>
+
+#include <AL/al.h>
+#include <AL/alc.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmAudioDevice::QWasmAudioDevice(const char *device, const char *desc, bool isDef, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(device, mode)
+{
+ description = QString::fromUtf8(desc);
+
+ isDefault = isDef;
+ minimumChannelCount = 1;
+ maximumChannelCount = 2;
+ minimumSampleRate = 8000;
+ maximumSampleRate = 96000; // js AudioContext max according to docs
+
+ // native openAL formats
+ supportedSampleFormats.append(QAudioFormat::UInt8);
+ supportedSampleFormats.append(QAudioFormat::Int16);
+
+ // Browsers use 32bit floats as native, but emscripten reccomends checking for the exension.
+ if (alIsExtensionPresent("AL_EXT_float32"))
+ supportedSampleFormats.append(QAudioFormat::Float);
+
+ preferredFormat.setChannelCount(2);
+
+ // FIXME: firefox
+ // An AudioContext was prevented from starting automatically.
+ // It must be created or resumed after a user gesture on the page.
+ emscripten::val audioContext = emscripten::val::global("window")["AudioContext"].new_();
+ if (audioContext == emscripten::val::undefined())
+ audioContext = emscripten::val::global("window")["webkitAudioContext"].new_();
+
+ if (audioContext != emscripten::val::undefined()) {
+ audioContext.call<void>("resume");
+ int sRate = audioContext["sampleRate"].as<int>();
+ audioContext.call<void>("close");
+ preferredFormat.setSampleRate(sRate);
+ }
+
+ auto f = QAudioFormat::Float;
+
+ if (!supportedSampleFormats.contains(f))
+ f = QAudioFormat::Int16;
+ preferredFormat.setSampleFormat(f);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/wasm/qwasmaudiodevice_p.h b/src/multimedia/wasm/qwasmaudiodevice_p.h
new file mode 100644
index 000000000..cc86c1575
--- /dev/null
+++ b/src/multimedia/wasm/qwasmaudiodevice_p.h
@@ -0,0 +1,31 @@
+// 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
+
+#ifndef QWASMAUDIODEVICEINFO_H
+#define QWASMAUDIODEVICEINFO_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qaudiodevice_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWasmAudioDevice : public QAudioDevicePrivate
+{
+public:
+ QWasmAudioDevice(const char *device, const char *description, bool isDefault, QAudioDevice::Mode mode);
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMAUDIODEVICEINFO_H
diff --git a/src/multimedia/platform/wasm/audio/qwasmaudiosink.cpp b/src/multimedia/wasm/qwasmaudiosink.cpp
index 82456e0b6..d1068e744 100644
--- a/src/multimedia/platform/wasm/audio/qwasmaudiosink.cpp
+++ b/src/multimedia/wasm/qwasmaudiosink.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwasmaudiosink_p.h"
@@ -77,11 +41,14 @@ protected:
qint64 writeData(const char *data, qint64 len) override;
};
-QWasmAudioSink::QWasmAudioSink(const QByteArray &device) : m_name(device)
+QWasmAudioSink::QWasmAudioSink(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSink(parent),
+ m_name(device),
+ m_timer(new QTimer(this))
{
- m_timer.setSingleShot(false);
+ m_timer->setSingleShot(false);
aldata = new ALData();
- connect(&m_timer, &QTimer::timeout, this, [this](){
+ connect(m_timer, &QTimer::timeout, this, [this](){
if (m_pullMode)
nextALBuffers();
else {
@@ -177,7 +144,6 @@ void QWasmAudioSink::start(bool mode)
}
alcMakeContextCurrent(aldata->context);
-
alGenSources(1, &aldata->source);
if (m_bufferSize > 0)
@@ -192,8 +158,8 @@ void QWasmAudioSink::start(bool mode)
alSourcef(aldata->source, AL_GAIN, m_volume);
if (m_pullMode)
loadALBuffers();
- m_timer.setInterval(DEFAULT_BUFFER_DURATION / 3000);
- m_timer.start();
+ m_timer->setInterval(DEFAULT_BUFFER_DURATION / 3000);
+ m_timer->start();
if (m_pullMode)
alSourcePlay(aldata->source);
m_running = true;
@@ -208,7 +174,7 @@ void QWasmAudioSink::stop()
m_elapsedTimer.invalidate();
alSourceStop(aldata->source);
alSourceRewind(aldata->source);
- m_timer.stop();
+ m_timer->stop();
m_bufferFragmentsBusyCount = 0;
alDeleteSources(1, &aldata->source);
alDeleteBuffers(m_bufferFragmentsCount, aldata->buffers);
@@ -234,6 +200,7 @@ void QWasmAudioSink::suspend()
if (!m_running)
return;
+ m_suspendedInState = m_state;
alSourcePause(aldata->source);
}
@@ -245,15 +212,15 @@ void QWasmAudioSink::resume()
alSourcePlay(aldata->source);
}
-int QWasmAudioSink::bytesFree() const
+qsizetype QWasmAudioSink::bytesFree() const
{
int processed;
alGetSourcei(aldata->source, AL_BUFFERS_PROCESSED, &processed);
return m_running ? m_bufferFragmentSize * (m_bufferFragmentsCount - m_bufferFragmentsBusyCount
- + processed) : 0;
+ + (qsizetype)processed) : 0;
}
-void QWasmAudioSink::setBufferSize(int value)
+void QWasmAudioSink::setBufferSize(qsizetype value)
{
if (m_running)
return;
@@ -261,7 +228,7 @@ void QWasmAudioSink::setBufferSize(int value)
m_bufferSize = value;
}
-int QWasmAudioSink::bufferSize() const
+qsizetype QWasmAudioSink::bufferSize() const
{
return m_bufferSize;
}
@@ -334,8 +301,12 @@ void QWasmAudioSink::loadALBuffers()
if (m_bufferFragmentsBusyCount == m_bufferFragmentsCount)
return;
+ if (m_device->bytesAvailable() == 0) {
+ return;
+ }
+
auto size = m_device->read(m_tmpData + m_tmpDataOffset, m_bufferFragmentSize -
- m_tmpDataOffset);
+ m_tmpDataOffset);
m_tmpDataOffset += size;
if (!m_tmpDataOffset || (m_tmpDataOffset != m_bufferFragmentSize &&
m_bufferFragmentsBusyCount >= m_bufferFragmentsCount * 2 / 3))
@@ -393,7 +364,7 @@ void QWasmAudioSink::nextALBuffers()
loadALBuffers();
ALint state;
alGetSourcei(aldata->source, AL_SOURCE_STATE, &state);
- if (state != AL_PLAYING)
+ if (state != AL_PLAYING && m_error == QAudio::NoError)
alSourcePlay(aldata->source);
updateState();
}
@@ -405,7 +376,7 @@ void QWasmAudioSink::updateState()
return;
m_state = current;
- if (m_state == QAudio::IdleState && m_running)
+ if (m_state == QAudio::IdleState && m_running && m_device->bytesAvailable() == 0)
setError(QAudio::UnderrunError);
emit stateChanged(m_state);
@@ -417,10 +388,16 @@ void QWasmAudioSink::setError(QAudio::Error error)
if (error == m_error)
return;
m_error = error;
+ if (error != QAudio::NoError) {
+ m_timer->stop();
+ alSourceRewind(aldata->source);
+ }
+
emit errorChanged(error);
}
-QWasmAudioSinkDevice::QWasmAudioSinkDevice(QWasmAudioSink *parent) : QIODevice(parent),
+QWasmAudioSinkDevice::QWasmAudioSinkDevice(QWasmAudioSink *parent)
+ : QIODevice(parent),
m_out(parent)
{
}
diff --git a/src/multimedia/wasm/qwasmaudiosink_p.h b/src/multimedia/wasm/qwasmaudiosink_p.h
new file mode 100644
index 000000000..975b7f6cc
--- /dev/null
+++ b/src/multimedia/wasm/qwasmaudiosink_p.h
@@ -0,0 +1,89 @@
+// 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
+
+#ifndef QWASMAUDIOSINK_H
+#define QWASMAUDIOSINK_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qaudiosystem_p.h>
+#include <QTimer>
+#include <QElapsedTimer>
+
+class ALData;
+class QIODevice;
+
+QT_BEGIN_NAMESPACE
+
+class QWasmAudioSink : public QPlatformAudioSink
+{
+ Q_OBJECT
+
+ QByteArray m_name;
+ ALData *aldata = nullptr;
+ QTimer *m_timer = nullptr;
+ QIODevice *m_device = nullptr;
+ QAudioFormat m_format;
+ QAudio::Error m_error = QAudio::NoError;
+ bool m_running = false;
+ QAudio::State m_state = QAudio::StoppedState;
+ QAudio::State m_suspendedInState = QAudio::SuspendedState;
+ int m_bufferSize = 0;
+ quint64 m_processed = 0;
+ QElapsedTimer m_elapsedTimer;
+ int m_bufferFragmentsCount = 10;
+ int m_notifyInterval = 0;
+ char *m_tmpData = nullptr;
+ int m_bufferFragmentSize = 0;
+ int m_lastNotified = 0;
+ int m_tmpDataOffset = 0;
+ int m_bufferFragmentsBusyCount = 0;
+ bool m_pullMode;
+ qreal m_volume = 1;
+
+ void loadALBuffers();
+ void unloadALBuffers();
+ void nextALBuffers();
+
+private slots:
+ void updateState();
+ void setError(QAudio::Error);
+
+public:
+ QWasmAudioSink(const QByteArray &device, QObject *parent);
+ ~QWasmAudioSink();
+
+public:
+ void start(QIODevice *device) override;
+ QIODevice *start() override;
+ void start(bool mode);
+ 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 &fmt) override;
+ QAudioFormat format() const override;
+ void setVolume(qreal volume) override;
+ qreal volume() const override;
+
+ friend class QWasmAudioSinkDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMAUDIOSINK_H
diff --git a/src/multimedia/platform/wasm/audio/qwasmaudiosource.cpp b/src/multimedia/wasm/qwasmaudiosource.cpp
index 981eeefc0..81f222c4b 100644
--- a/src/multimedia/platform/wasm/audio/qwasmaudiosource.cpp
+++ b/src/multimedia/wasm/qwasmaudiosource.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwasmaudiosource_p.h"
@@ -100,18 +64,21 @@ void QWasmAudioSource::writeBuffer()
m_device->write(m_tmpData,bytes);
}
-QWasmAudioSource::QWasmAudioSource(const QByteArray &device)
- : QPlatformAudioSource(), m_name(device)
+QWasmAudioSource::QWasmAudioSource(const QByteArray &device , QObject *parent)
+ : QPlatformAudioSource(parent),
+ m_name(device),
+ m_timer(new QTimer(this))
{
- aldata = new ALData();
- connect(&m_timer, &QTimer::timeout, this, [this](){
- Q_ASSERT(m_running);
- if (m_pullMode)
- writeBuffer();
- else
- if (bytesReady() > 0)
+ if (device.contains("Emscripten")) {
+ aldata = new ALData();
+ connect(m_timer, &QTimer::timeout, this, [this](){
+ Q_ASSERT(m_running);
+ if (m_pullMode)
+ writeBuffer();
+ else if (bytesReady() > 0)
emit m_device->readyRead();
- });
+ });
+ }
}
void QWasmAudioSource::start(QIODevice *device)
@@ -182,8 +149,10 @@ void QWasmAudioSource::start(bool mode)
m_tmpData = new char[m_bufferSize];
else
m_tmpData = nullptr;
- m_timer.setInterval(m_format.durationForBytes(m_bufferSize) / 3'000);
+ m_timer->setInterval(m_format.durationForBytes(m_bufferSize) / 3000);
+ m_timer->start();
+ alcGetError(aldata->device); // clear error state
aldata->device = alcCaptureOpenDevice(m_name.data(), m_format.sampleRate(), format,
m_format.framesForBytes(m_bufferSize));
@@ -201,7 +170,6 @@ void QWasmAudioSource::start(bool mode)
}
m_processed = 0;
m_running = true;
- m_timer.start();
}
void QWasmAudioSource::stop()
@@ -217,7 +185,7 @@ void QWasmAudioSource::stop()
}
if (!m_pullMode)
m_device->deleteLater();
- m_timer.stop();
+ m_timer->stop();
m_running = false;
}
@@ -251,7 +219,7 @@ void QWasmAudioSource::resume()
alcCaptureStart(aldata->device);
}
-int QWasmAudioSource::bytesReady() const
+qsizetype QWasmAudioSource::bytesReady() const
{
if (!m_running)
return 0;
@@ -260,14 +228,14 @@ int QWasmAudioSource::bytesReady() const
return m_format.bytesForFrames(samples);
}
-void QWasmAudioSource::setBufferSize(int value)
+void QWasmAudioSource::setBufferSize(qsizetype value)
{
if (!m_running)
return;
m_bufferSize = value;
}
-int QWasmAudioSource::bufferSize() const
+qsizetype QWasmAudioSource::bufferSize() const
{
return m_bufferSize;
}
diff --git a/src/multimedia/wasm/qwasmaudiosource_p.h b/src/multimedia/wasm/qwasmaudiosource_p.h
new file mode 100644
index 000000000..97b4ec52a
--- /dev/null
+++ b/src/multimedia/wasm/qwasmaudiosource_p.h
@@ -0,0 +1,75 @@
+// 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
+
+#ifndef QWASMAUDIOSOURCE_H
+#define QWASMAUDIOSOURCE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qaudiosystem_p.h>
+#include <QTimer>
+#include <QElapsedTimer>
+
+QT_BEGIN_NAMESPACE
+
+class ALData;
+
+class QWasmAudioSource : public QPlatformAudioSource
+{
+ Q_OBJECT
+
+ QByteArray m_name;
+ ALData *aldata = nullptr;
+ QTimer *m_timer = nullptr;
+ QIODevice *m_device = nullptr;
+ QAudioFormat m_format;
+ qreal m_volume = 1;
+ qsizetype m_bufferSize;
+ bool m_running = false;
+ bool m_suspended = false;
+ QAudio::Error m_error;
+ bool m_pullMode;
+ char *m_tmpData = nullptr;
+ QElapsedTimer m_elapsedTimer;
+ int m_notifyInterval = 0;
+ quint64 m_processed = 0;
+
+ void writeBuffer();
+public:
+ QWasmAudioSource(const QByteArray &device, QObject *parent);
+
+public:
+ void start(QIODevice *device) override;
+ QIODevice *start() override;
+ void start(bool mode);
+ 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 &fmt) override;
+ QAudioFormat format() const override;
+ void setVolume(qreal volume) override;
+ qreal volume() const override;
+
+ friend class QWasmAudioSourceDevice;
+ void setError(const QAudio::Error &error);
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMAUDIOSOURCE_H
diff --git a/src/multimedia/wasm/qwasmmediadevices.cpp b/src/multimedia/wasm/qwasmmediadevices.cpp
new file mode 100644
index 000000000..4e59fd161
--- /dev/null
+++ b/src/multimedia/wasm/qwasmmediadevices.cpp
@@ -0,0 +1,276 @@
+// 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 "qwasmmediadevices_p.h"
+#include "private/qcameradevice_p.h"
+#include "private/qplatformmediaintegration_p.h"
+#include "qwasmaudiosource_p.h"
+#include "qwasmaudiosink_p.h"
+#include "qwasmaudiodevice_p.h"
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#include <QMap>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qWasmMediaDevices, "qt.multimedia.wasm.mediadevices")
+
+QWasmCameraDevices::QWasmCameraDevices(QPlatformMediaIntegration *integration)
+ : QPlatformVideoDevices(integration)
+{
+ m_mediaDevices = QPlatformMediaIntegration::instance()->mediaDevices();
+}
+
+QList<QCameraDevice> QWasmCameraDevices::videoDevices() const
+{
+ QWasmMediaDevices *wasmMediaDevices = reinterpret_cast<QWasmMediaDevices *>(m_mediaDevices);
+ return wasmMediaDevices ? wasmMediaDevices->videoInputs() : QList<QCameraDevice>();
+}
+
+QWasmMediaDevices::QWasmMediaDevices()
+{
+ initDevices();
+}
+
+void QWasmMediaDevices::initDevices()
+{
+ if (m_initDone)
+ return;
+
+ m_initDone = true;
+ getOpenALAudioDevices();
+ getMediaDevices(); // asynchronous
+}
+
+QList<QAudioDevice> QWasmMediaDevices::audioInputs() const
+{
+ return m_audioInputs.values();
+}
+
+QList<QAudioDevice> QWasmMediaDevices::audioOutputs() const
+{
+ return m_audioOutputs.values();
+}
+
+QList<QCameraDevice> QWasmMediaDevices::videoInputs() const
+{
+ return m_cameraDevices.values();
+}
+
+QPlatformAudioSource *QWasmMediaDevices::createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QWasmAudioSource(deviceInfo.id(), parent);
+}
+
+QPlatformAudioSink *QWasmMediaDevices::createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ return new QWasmAudioSink(deviceInfo.id(), parent);
+}
+
+void QWasmMediaDevices::parseDevices(emscripten::val devices)
+{
+ if (devices.isNull() || devices.isUndefined()) {
+ qWarning() << "Something went wrong enumerating devices";
+ return;
+ }
+
+ QList<std::string> cameraDevicesToRemove = m_cameraDevices.keys();
+ QList<std::string> audioOutputsToRemove;
+ QList<std::string> audioInputsToRemove;
+
+ if (m_firstInit) {
+ m_firstInit = false;
+ qWarning() << "m_audioInputs count" << m_audioInputs.count();
+
+ } else {
+ audioOutputsToRemove = m_audioOutputs.keys();
+ audioInputsToRemove = m_audioInputs.keys();
+ m_audioInputsAdded = false;
+ m_audioOutputsAdded = false;
+ }
+ m_videoInputsAdded = false;
+
+ bool m_videoInputsRemoved = false;
+ bool m_audioInputsRemoved = false;
+ bool m_audioOutputsRemoved = false;
+
+ for (int i = 0; i < devices["length"].as<int>(); i++) {
+
+ emscripten::val mediaDevice = devices[i];
+
+ std::string defaultDeviceLabel = "";
+
+ const std::string deviceKind = mediaDevice["kind"].as<std::string>();
+ const std::string label = mediaDevice["label"].as<std::string>();
+ const std::string deviceId = mediaDevice["deviceId"].as<std::string>();
+
+ qCDebug(qWasmMediaDevices) << QString::fromStdString(deviceKind)
+ << QString::fromStdString(deviceId)
+ << QString::fromStdString(label);
+
+ if (deviceKind.empty())
+ continue;
+
+ if (deviceId == std::string("default")) {
+ // chrome specifies the default device with this as deviceId
+ // and then prepends "Default - " with the name of the device
+ // in the label
+ if (label.empty())
+ continue;
+
+ defaultDeviceLabel = label;
+ continue;
+ }
+
+ const bool isDefault = false; // FIXME
+ // (defaultDeviceLabel.find(label) != std::string::npos);
+
+ if (deviceKind == std::string("videoinput")) {
+ if (!m_cameraDevices.contains(deviceId)) {
+ QCameraDevicePrivate *camera = new QCameraDevicePrivate; // QSharedData
+ camera->id = QString::fromStdString(deviceId).toUtf8();
+ camera->description = QString::fromUtf8(label.c_str());
+ camera->isDefault = isDefault;
+
+ m_cameraDevices.insert(deviceId, camera->create());
+ m_videoInputsAdded = true;
+ }
+ cameraDevicesToRemove.removeOne(deviceId);
+ } else if (deviceKind == std::string("audioinput")) {
+ if (!m_audioInputs.contains(deviceId)) {
+ m_audioInputs.insert(deviceId,
+ (new QWasmAudioDevice(deviceId.c_str(), label.c_str(),
+ isDefault, QAudioDevice::Input))
+ ->create());
+
+ m_audioInputsAdded = true;
+ }
+ audioInputsToRemove.removeOne(deviceId);
+ } else if (deviceKind == std::string("audiooutput")) {
+ if (!m_audioOutputs.contains(deviceId)) {
+ m_audioOutputs.insert(deviceId,
+ (new QWasmAudioDevice(deviceId.c_str(), label.c_str(),
+ isDefault, QAudioDevice::Input))
+ ->create());
+
+ m_audioOutputsAdded = true;
+ }
+ audioOutputsToRemove.removeOne(deviceId);
+ }
+ // if permissions are given label will hold the actual
+ // camera name, such as "Live! Cam Sync 1080p (041e:409d)"
+ }
+ if (!m_firstInit)
+ getOpenALAudioDevices();
+
+ // any left here were removed
+ int j = 0;
+ for (; j < cameraDevicesToRemove.count(); j++) {
+ m_cameraDevices.remove(cameraDevicesToRemove.at(j));
+ }
+ m_videoInputsRemoved = !cameraDevicesToRemove.isEmpty();
+
+ for (j = 0; j < audioInputsToRemove.count(); j++) {
+ m_audioInputs.remove(audioInputsToRemove.at(j));
+ }
+ m_audioInputsRemoved = !audioInputsToRemove.isEmpty();
+
+ for (j = 0; j < audioOutputsToRemove.count(); j++) {
+ m_audioOutputs.remove(audioOutputsToRemove.at(j));
+ }
+ m_audioOutputsRemoved = !audioOutputsToRemove.isEmpty();
+
+ if (m_videoInputsAdded || m_videoInputsRemoved)
+ emit videoInputsChanged();
+ if (m_audioInputsAdded || m_audioInputsRemoved)
+ emit audioInputsChanged();
+ if (m_audioOutputsAdded || m_audioOutputsRemoved)
+ emit audioOutputsChanged();
+
+ m_firstInit = false;
+
+}
+
+void QWasmMediaDevices::getMediaDevices()
+{
+ emscripten::val navigator = emscripten::val::global("navigator");
+ m_jsMediaDevicesInterface = navigator["mediaDevices"];
+
+ if (m_jsMediaDevicesInterface.isNull() || m_jsMediaDevicesInterface.isUndefined()) {
+ qWarning() << "No media devices found";
+ return;
+ }
+
+ if (qstdweb::haveAsyncify()) {
+#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
+ emscripten::val devicesList = m_jsMediaDevicesInterface.call<emscripten::val>("enumerateDevices").await();
+ if (devicesList.isNull() || devicesList.isUndefined()) {
+ qWarning() << "devices list error";
+ return;
+ }
+
+ parseDevices(devicesList);
+#endif
+ } else {
+ qstdweb::PromiseCallbacks enumerateDevicesCallback{
+ .thenFunc =
+ [&](emscripten::val devices) {
+ parseDevices(devices);
+ },
+ .catchFunc =
+ [this](emscripten::val error) {
+ qWarning() << "mediadevices enumerateDevices fail"
+ << QString::fromStdString(error["name"].as<std::string>())
+ << QString::fromStdString(error["message"].as<std::string>());
+ m_initDone = false;
+ }
+ };
+
+ qstdweb::Promise::make(m_jsMediaDevicesInterface,
+ QStringLiteral("enumerateDevices"),
+ std::move(enumerateDevicesCallback));
+
+ // setup devicechange monitor
+ m_deviceChangedCallback = std::make_unique<qstdweb::EventCallback>(
+ m_jsMediaDevicesInterface, "devicechange",
+ [this, enumerateDevicesCallback](emscripten::val) {
+ qstdweb::Promise::make(m_jsMediaDevicesInterface,
+ QStringLiteral("enumerateDevices"),
+ std::move(enumerateDevicesCallback));
+ });
+ }
+
+}
+
+void QWasmMediaDevices::getOpenALAudioDevices()
+{
+ // VM3959:4 The AudioContext was not allowed to start.
+ // It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
+ auto capture = alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
+ // present even if there is no capture device
+ if (capture && !m_audioOutputs.contains(capture)) {
+ m_audioInputs.insert(capture,
+ (new QWasmAudioDevice(capture, "WebAssembly audio capture device",
+ true, QAudioDevice::Input))
+ ->create());
+ m_audioInputsAdded = true;
+ emit audioInputsChanged();
+ }
+
+ auto playback = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
+ // present even if there is no playback device
+ if (playback && !m_audioOutputs.contains(capture)) {
+ m_audioOutputs.insert(playback,
+ (new QWasmAudioDevice(playback, "WebAssembly audio playback device",
+ true, QAudioDevice::Output))
+ ->create());
+ emit audioOutputsChanged();
+ }
+ m_firstInit = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/wasm/qwasmmediadevices_p.h b/src/multimedia/wasm/qwasmmediadevices_p.h
new file mode 100644
index 000000000..b97036f97
--- /dev/null
+++ b/src/multimedia/wasm/qwasmmediadevices_p.h
@@ -0,0 +1,89 @@
+// 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
+
+#ifndef QWASMMEDIADEVICES_H
+#define QWASMMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+
+#include <private/qplatformvideodevices_p.h>
+
+#include <QtCore/private/qstdweb_p.h>
+#include <qaudio.h>
+#include <qaudiodevice.h>
+#include <qcameradevice.h>
+#include <qset.h>
+#include <QtCore/qloggingcategory.h>
+
+#include <emscripten.h>
+#include <emscripten/val.h>
+#include <emscripten/bind.h>
+#include <QMapIterator>
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(qWasmMediaDevices)
+
+class QWasmAudioEngine;
+
+class QWasmCameraDevices : public QPlatformVideoDevices
+{
+ Q_OBJECT
+public:
+ QWasmCameraDevices(QPlatformMediaIntegration *integration);
+
+ QList<QCameraDevice> videoDevices() const override;
+private:
+ // weak
+ QPlatformMediaDevices *m_mediaDevices;
+};
+
+class QWasmMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QWasmMediaDevices();
+
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QList<QCameraDevice> videoInputs() const;
+
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+ void initDevices();
+
+private:
+ void updateCameraDevices();
+ void getMediaDevices();
+ void getOpenALAudioDevices();
+ void parseDevices(emscripten::val devices);
+
+ QMap <std::string, QAudioDevice> m_audioOutputs;
+ QMap <std::string, QAudioDevice> m_audioInputs;
+ QMap <std::string, QCameraDevice> m_cameraDevices;
+
+
+ std::unique_ptr<qstdweb::EventCallback> m_deviceChangedCallback;
+
+ bool m_videoInputsAdded = false;
+ bool m_audioInputsAdded = false;
+ bool m_audioOutputsAdded = false;
+ emscripten::val m_jsMediaDevicesInterface = emscripten::val::undefined();
+ bool m_initDone = false;
+ bool m_firstInit = false;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/windows/qcomptr_p.h b/src/multimedia/windows/qcomptr_p.h
new file mode 100644
index 000000000..befc97f11
--- /dev/null
+++ b/src/multimedia/windows/qcomptr_p.h
@@ -0,0 +1,33 @@
+// 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
+
+#ifndef QCOMPTR_P_H
+#define QCOMPTR_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 <qt_windows.h>
+#include <wrl/client.h>
+
+using Microsoft::WRL::ComPtr;
+
+template<typename T, typename... Args>
+ComPtr<T> makeComObject(Args &&...args)
+{
+ ComPtr<T> p;
+ // Don't use Attach because of MINGW64 bug
+ // #892 Microsoft::WRL::ComPtr::Attach leaks references
+ *p.GetAddressOf() = new T(std::forward<Args>(args)...);
+ return p;
+}
+
+#endif
diff --git a/src/multimedia/windows/qcomtaskresource_p.h b/src/multimedia/windows/qcomtaskresource_p.h
new file mode 100644
index 000000000..90554da5e
--- /dev/null
+++ b/src/multimedia/windows/qcomtaskresource_p.h
@@ -0,0 +1,152 @@
+// 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
+
+//
+// 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.
+//
+
+#ifndef QCOMTASKRESOURCE_P_H
+#define QCOMTASKRESOURCE_P_H
+
+#include <QtCore/qassert.h>
+
+#include <objbase.h>
+#include <algorithm>
+#include <type_traits>
+#include <utility>
+
+class QEmptyDeleter final
+{
+public:
+ template<typename T>
+ void operator()(T /*element*/) const
+ {
+ }
+};
+
+class QComDeleter final
+{
+public:
+ template<typename T>
+ void operator()(T element) const
+ {
+ element->Release();
+ }
+};
+
+template<typename T>
+class QComTaskResourceBase
+{
+public:
+ QComTaskResourceBase(const QComTaskResourceBase<T> &source) = delete;
+ QComTaskResourceBase &operator=(const QComTaskResourceBase<T> &right) = delete;
+
+ explicit operator bool() const { return m_resource != nullptr; }
+
+ T *get() const { return m_resource; }
+
+protected:
+ QComTaskResourceBase() = default;
+ explicit QComTaskResourceBase(T *const resource) : m_resource(resource) { }
+
+ T *release() { return std::exchange(m_resource, nullptr); }
+
+ void reset(T *const resource = nullptr)
+ {
+ if (m_resource != resource) {
+ if (m_resource)
+ CoTaskMemFree(m_resource);
+ m_resource = resource;
+ }
+ }
+
+ T *m_resource = nullptr;
+};
+
+template<typename T, typename TElementDeleter = QEmptyDeleter>
+class QComTaskResource final : public QComTaskResourceBase<T>
+{
+ using Base = QComTaskResourceBase<T>;
+
+public:
+ using Base::QComTaskResourceBase;
+
+ ~QComTaskResource() { reset(); }
+
+ T *operator->() const { return m_resource; }
+ T &operator*() const { return *m_resource; }
+
+ T **address()
+ {
+ Q_ASSERT(m_resource == nullptr);
+ return &m_resource;
+ }
+
+ using Base::release;
+ using Base::reset;
+
+private:
+ using Base::m_resource;
+};
+
+template<typename T, typename TElementDeleter>
+class QComTaskResource<T[], TElementDeleter> final : public QComTaskResourceBase<T>
+{
+ using Base = QComTaskResourceBase<T>;
+
+public:
+ QComTaskResource() = default;
+ explicit QComTaskResource(T *const resource, const std::size_t size)
+ : Base(resource), m_size(size)
+ {
+ }
+
+ ~QComTaskResource() { reset(); }
+
+ T &operator[](const std::size_t index) const
+ {
+ Q_ASSERT(index < m_size);
+ return m_resource[index];
+ }
+
+ T *release()
+ {
+ m_size = 0;
+
+ return Base::release();
+ }
+
+ void reset() { reset(nullptr, 0); }
+
+ void reset(T *const resource, const std::size_t size)
+ {
+ if (m_resource != resource) {
+ resetElements();
+
+ Base::reset(resource);
+
+ m_size = size;
+ }
+ }
+
+private:
+ void resetElements()
+ {
+ if constexpr (!std::is_same_v<TElementDeleter, QEmptyDeleter>) {
+ std::for_each(m_resource, m_resource + m_size, TElementDeleter());
+ }
+ }
+
+ std::size_t m_size = 0;
+
+ using Base::m_resource;
+};
+
+#endif
diff --git a/src/multimedia/platform/windows/audio/qwindowsaudiodevice.cpp b/src/multimedia/windows/qwindowsaudiodevice.cpp
index 793d1472f..f22567cbf 100644
--- a/src/multimedia/platform/windows/audio/qwindowsaudiodevice.cpp
+++ b/src/multimedia/windows/qwindowsaudiodevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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
@@ -48,34 +12,57 @@
// INTERNAL USE ONLY: Do NOT use for any other purpose.
//
+#include "qwindowsaudiodevice_p.h"
+#include "qwindowsaudioutils_p.h"
#include <QtCore/qt_windows.h>
#include <QtCore/QDataStream>
#include <QtCore/QIODevice>
+
+#include <audioclient.h>
#include <mmsystem.h>
-#include "qwindowsaudiodevice_p.h"
-#include "qwindowsaudioutils_p.h"
+
+#include <initguid.h>
+#include <wtypes.h>
+#include <propkeydef.h>
+#include <mmdeviceapi.h>
QT_BEGIN_NAMESPACE
-QWindowsAudioDeviceInfo::QWindowsAudioDeviceInfo(QByteArray dev, int waveID, const QString &description, QAudioDevice::Mode mode)
+QWindowsAudioDeviceInfo::QWindowsAudioDeviceInfo(QByteArray dev, ComPtr<IMMDevice> immDev, int waveID, const QString &description, QAudioDevice::Mode mode)
: QAudioDevicePrivate(dev, mode),
- devId(waveID)
+ m_devId(waveID),
+ m_immDev(std::move(immDev))
{
+ Q_ASSERT(m_immDev);
+
this->description = description;
- preferredFormat.setSampleRate(44100);
- preferredFormat.setChannelCount(2);
- preferredFormat.setSampleFormat(QAudioFormat::Int16);
+
+ ComPtr<IAudioClient> audioClient;
+ HRESULT hr = m_immDev->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr,
+ (void **)audioClient.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ WAVEFORMATEX *pwfx = nullptr;
+ hr = audioClient->GetMixFormat(&pwfx);
+ if (SUCCEEDED(hr))
+ preferredFormat = QWindowsAudioUtils::waveFormatExToFormat(*pwfx);
+ }
+
+ if (!preferredFormat.isValid()) {
+ preferredFormat.setSampleRate(44100);
+ preferredFormat.setChannelCount(2);
+ preferredFormat.setSampleFormat(QAudioFormat::Int16);
+ }
DWORD fmt = 0;
if(mode == QAudioDevice::Output) {
WAVEOUTCAPS woc;
- if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
+ if (waveOutGetDevCaps(m_devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
fmt = woc.dwFormats;
} else {
WAVEINCAPS woc;
- if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
+ if (waveInGetDevCaps(m_devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
fmt = woc.dwFormats;
}
@@ -204,6 +191,18 @@ QWindowsAudioDeviceInfo::QWindowsAudioDeviceInfo(QByteArray dev, int waveID, con
break;
}
}
+
+ channelConfiguration = QAudioFormat::defaultChannelConfigForChannelCount(maximumChannelCount);
+
+ ComPtr<IPropertyStore> props;
+ hr = m_immDev->OpenPropertyStore(STGM_READ, props.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ PROPVARIANT var;
+ PropVariantInit(&var);
+ hr = props->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &var);
+ if (SUCCEEDED(hr) && var.uintVal != 0)
+ channelConfiguration = QWindowsAudioUtils::maskToChannelConfig(var.uintVal, maximumChannelCount);
+ }
}
QWindowsAudioDeviceInfo::~QWindowsAudioDeviceInfo()
@@ -213,13 +212,13 @@ QWindowsAudioDeviceInfo::~QWindowsAudioDeviceInfo()
bool QWindowsAudioDeviceInfo::testSettings(const QAudioFormat& format) const
{
WAVEFORMATEXTENSIBLE wfx;
- if (qt_convertFormat(format, &wfx)) {
+ if (QWindowsAudioUtils::formatToWaveFormatExtensible(format, wfx)) {
// query only, do not open device
if (mode == QAudioDevice::Output) {
- return (waveOutOpen(NULL, UINT_PTR(devId), &wfx.Format, 0, 0,
+ return (waveOutOpen(NULL, UINT_PTR(m_devId), &wfx.Format, 0, 0,
WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
} else { // AudioInput
- return (waveInOpen(NULL, UINT_PTR(devId), &wfx.Format, 0, 0,
+ return (waveInOpen(NULL, UINT_PTR(m_devId), &wfx.Format, 0, 0,
WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
}
}
diff --git a/src/multimedia/windows/qwindowsaudiodevice_p.h b/src/multimedia/windows/qwindowsaudiodevice_p.h
new file mode 100644
index 000000000..b2af4bfe0
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudiodevice_p.h
@@ -0,0 +1,60 @@
+// 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 QWINDOWSAUDIODEVICEINFO_H
+#define QWINDOWSAUDIODEVICEINFO_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudiodevice.h>
+#include <private/qaudiosystem_p.h>
+#include <private/qaudiodevice_p.h>
+#include <qcomptr_p.h>
+
+struct IMMDevice;
+
+QT_BEGIN_NAMESPACE
+
+const unsigned int MAX_SAMPLE_RATES = 5;
+const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 };
+
+class QWindowsAudioDeviceInfo : public QAudioDevicePrivate
+{
+public:
+ QWindowsAudioDeviceInfo(QByteArray dev, ComPtr<IMMDevice> immdev, int waveID, const QString &description, QAudioDevice::Mode mode);
+ ~QWindowsAudioDeviceInfo();
+
+ bool open();
+ void close();
+
+ bool testSettings(const QAudioFormat& format) const;
+
+ int waveId() const { return m_devId; }
+ ComPtr<IMMDevice> immDev() const { return m_immDev; }
+
+private:
+ quint32 m_devId;
+ ComPtr<IMMDevice> m_immDev;
+};
+
+
+
+QT_END_NAMESPACE
+
+
+#endif // QWINDOWSAUDIODEVICEINFO_H
diff --git a/src/multimedia/windows/qwindowsaudiosink.cpp b/src/multimedia/windows/qwindowsaudiosink.cpp
new file mode 100644
index 000000000..404496970
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudiosink.cpp
@@ -0,0 +1,388 @@
+// 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.
+//
+// INTERNAL USE ONLY: Do NOT use for any other purpose.
+//
+
+#include "qwindowsaudiosink_p.h"
+#include "qwindowsaudioutils_p.h"
+#include "qwindowsmultimediautils_p.h"
+#include "qcomtaskresource_p.h"
+
+#include <QtCore/QDataStream>
+#include <QtCore/qtimer.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpointer.h>
+
+#include <private/qaudiohelpers_p.h>
+
+#include <audioclient.h>
+#include <mmdeviceapi.h>
+
+QT_BEGIN_NAMESPACE
+
+static Q_LOGGING_CATEGORY(qLcAudioOutput, "qt.multimedia.audiooutput")
+
+using namespace QWindowsMultimediaUtils;
+
+class OutputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ OutputPrivate(QWindowsAudioSink &audio) : QIODevice(&audio), audioDevice(audio) {}
+ ~OutputPrivate() override = default;
+
+ qint64 readData(char *, qint64) override { return 0; }
+ qint64 writeData(const char *data, qint64 len) override { return audioDevice.push(data, len); }
+
+private:
+ QWindowsAudioSink &audioDevice;
+};
+
+std::optional<quint32> audioClientFramesAvailable(IAudioClient *client)
+{
+ auto framesAllocated = QWindowsAudioUtils::audioClientFramesAllocated(client);
+ auto framesInUse = QWindowsAudioUtils::audioClientFramesInUse(client);
+
+ if (framesAllocated && framesInUse)
+ return *framesAllocated - *framesInUse;
+ return {};
+}
+
+QWindowsAudioSink::QWindowsAudioSink(ComPtr<IMMDevice> device, QObject *parent) :
+ QPlatformAudioSink(parent),
+ m_timer(new QTimer(this)),
+ m_pushSource(new OutputPrivate(*this)),
+ m_device(std::move(device))
+{
+ m_pushSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
+ m_timer->setSingleShot(true);
+ m_timer->setTimerType(Qt::PreciseTimer);
+}
+
+QWindowsAudioSink::~QWindowsAudioSink()
+{
+ close();
+}
+
+qint64 QWindowsAudioSink::remainingPlayTimeUs()
+{
+ auto framesInUse = QWindowsAudioUtils::audioClientFramesInUse(m_audioClient.Get());
+ return m_resampler.outputFormat().durationForFrames(framesInUse ? *framesInUse : 0);
+}
+
+void QWindowsAudioSink::deviceStateChange(QAudio::State state, QAudio::Error error)
+{
+ if (state != deviceState) {
+ if (state == QAudio::ActiveState) {
+ m_audioClient->Start();
+ qCDebug(qLcAudioOutput) << "Audio client started";
+
+ } else if (deviceState == QAudio::ActiveState) {
+ m_timer->stop();
+ m_audioClient->Stop();
+ qCDebug(qLcAudioOutput) << "Audio client stopped";
+ }
+
+ QPointer<QWindowsAudioSink> thisGuard(this);
+ deviceState = state;
+ emit stateChanged(deviceState);
+ if (!thisGuard)
+ return;
+ }
+
+ if (error != errorState) {
+ errorState = error;
+ emit errorChanged(error);
+ }
+}
+
+QAudioFormat QWindowsAudioSink::format() const
+{
+ return m_format;
+}
+
+void QWindowsAudioSink::setFormat(const QAudioFormat& fmt)
+{
+ if (deviceState == QAudio::StoppedState)
+ m_format = fmt;
+}
+
+void QWindowsAudioSink::pullSource()
+{
+ qCDebug(qLcAudioOutput) << "Pull source";
+ if (!m_pullSource)
+ return;
+
+ auto bytesAvailable = m_pullSource->isOpen() ? qsizetype(m_pullSource->bytesAvailable()) : 0;
+ auto readLen = qMin(bytesFree(), bytesAvailable);
+ if (readLen > 0) {
+ QByteArray samples = m_pullSource->read(readLen);
+ if (samples.size() == 0) {
+ deviceStateChange(QAudio::IdleState, QAudio::IOError);
+ return;
+ } else {
+ write(samples.data(), samples.size());
+ }
+ }
+
+ auto playTimeUs = remainingPlayTimeUs();
+ if (playTimeUs == 0) {
+ deviceStateChange(QAudio::IdleState, m_pullSource->atEnd() ? QAudio::NoError : QAudio::UnderrunError);
+ } else {
+ deviceStateChange(QAudio::ActiveState, QAudio::NoError);
+ m_timer->start(playTimeUs / 2000);
+ }
+}
+
+void QWindowsAudioSink::start(QIODevice* device)
+{
+ qCDebug(qLcAudioOutput) << "start(ioDevice)" << deviceState;
+ if (deviceState != QAudio::StoppedState)
+ close();
+
+ if (device == nullptr)
+ return;
+
+ if (!open()) {
+ errorState = QAudio::OpenError;
+ emit errorChanged(QAudio::OpenError);
+ return;
+ }
+
+ m_pullSource = device;
+
+ connect(device, &QIODevice::readyRead, this, &QWindowsAudioSink::pullSource);
+ m_timer->disconnect();
+ m_timer->callOnTimeout(this, &QWindowsAudioSink::pullSource);
+ pullSource();
+}
+
+qint64 QWindowsAudioSink::push(const char *data, qint64 len)
+{
+ if (deviceState == QAudio::StoppedState)
+ return -1;
+
+ qint64 written = write(data, len);
+ if (written > 0) {
+ deviceStateChange(QAudio::ActiveState, QAudio::NoError);
+ m_timer->start(remainingPlayTimeUs() /1000);
+ }
+
+ return written;
+}
+
+QIODevice* QWindowsAudioSink::start()
+{
+ qCDebug(qLcAudioOutput) << "start()";
+ if (deviceState != QAudio::StoppedState)
+ close();
+
+ if (!open()) {
+ errorState = QAudio::OpenError;
+ emit errorChanged(QAudio::OpenError);
+ return nullptr;
+ }
+
+ deviceStateChange(QAudio::IdleState, QAudio::NoError);
+
+ m_timer->disconnect();
+ m_timer->callOnTimeout(this, [this](){
+ deviceStateChange(QAudio::IdleState, QAudio::UnderrunError);
+ });
+
+ return m_pushSource.get();
+}
+
+bool QWindowsAudioSink::open()
+{
+ if (m_audioClient)
+ return true;
+
+ HRESULT hr = m_device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER,
+ nullptr, (void**)m_audioClient.GetAddressOf());
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioOutput) << "Failed to activate audio device" << errorString(hr);
+ return false;
+ }
+
+ auto resetClient = qScopeGuard([this](){ m_audioClient.Reset(); });
+
+ QComTaskResource<WAVEFORMATEX> pwfx;
+ hr = m_audioClient->GetMixFormat(pwfx.address());
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioOutput) << "Format unsupported" << errorString(hr);
+ return false;
+ }
+
+ if (!m_resampler.setup(m_format, QWindowsAudioUtils::waveFormatExToFormat(*pwfx))) {
+ qCWarning(qLcAudioOutput) << "Failed to set up resampler";
+ return false;
+ }
+
+ if (m_bufferSize == 0)
+ m_bufferSize = m_format.sampleRate() * m_format.bytesPerFrame() / 2;
+
+ REFERENCE_TIME requestedDuration = m_format.durationForBytes(m_bufferSize) * 10;
+
+ hr = m_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, requestedDuration, 0, pwfx.get(),
+ nullptr);
+
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioOutput) << "Failed to initialize audio client" << errorString(hr);
+ return false;
+ }
+
+ auto framesAllocated = QWindowsAudioUtils::audioClientFramesAllocated(m_audioClient.Get());
+ if (!framesAllocated) {
+ qCWarning(qLcAudioOutput) << "Failed to get audio client buffer size";
+ return false;
+ }
+
+ m_bufferSize = m_format.bytesForDuration(
+ m_resampler.outputFormat().durationForFrames(*framesAllocated));
+
+ hr = m_audioClient->GetService(__uuidof(IAudioRenderClient), (void**)m_renderClient.GetAddressOf());
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioOutput) << "Failed to obtain audio client rendering service"
+ << errorString(hr);
+ return false;
+ }
+
+ resetClient.dismiss();
+
+ return true;
+}
+
+void QWindowsAudioSink::close()
+{
+ qCDebug(qLcAudioOutput) << "close()";
+ if (deviceState == QAudio::StoppedState)
+ return;
+
+ deviceStateChange(QAudio::StoppedState, QAudio::NoError);
+
+ if (m_pullSource)
+ disconnect(m_pullSource, &QIODevice::readyRead, this, &QWindowsAudioSink::pullSource);
+ m_audioClient.Reset();
+ m_renderClient.Reset();
+ m_pullSource = nullptr;
+}
+
+qsizetype QWindowsAudioSink::bytesFree() const
+{
+ if (!m_audioClient)
+ return 0;
+
+ auto framesAvailable = audioClientFramesAvailable(m_audioClient.Get());
+ if (framesAvailable)
+ return m_resampler.inputBufferSize(*framesAvailable * m_resampler.outputFormat().bytesPerFrame());
+ return 0;
+}
+
+void QWindowsAudioSink::setBufferSize(qsizetype value)
+{
+ if (!m_audioClient)
+ m_bufferSize = value;
+}
+
+qint64 QWindowsAudioSink::processedUSecs() const
+{
+ if (!m_audioClient)
+ return 0;
+
+ return m_format.durationForBytes(m_resampler.totalInputBytes());
+}
+
+qint64 QWindowsAudioSink::write(const char *data, qint64 len)
+{
+ Q_ASSERT(m_audioClient);
+ Q_ASSERT(m_renderClient);
+
+ qCDebug(qLcAudioOutput) << "write()" << len;
+
+ auto framesAvailable = audioClientFramesAvailable(m_audioClient.Get());
+ if (!framesAvailable)
+ return -1;
+
+ auto maxBytesCanWrite = m_format.bytesForDuration(
+ m_resampler.outputFormat().durationForFrames(*framesAvailable));
+ qsizetype writeSize = qMin(maxBytesCanWrite, len);
+
+ QByteArray writeBytes = m_resampler.resample({data, writeSize});
+ qint32 writeFramesNum = m_resampler.outputFormat().framesForBytes(writeBytes.size());
+
+ quint8 *buffer = nullptr;
+ HRESULT hr = m_renderClient->GetBuffer(writeFramesNum, &buffer);
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioOutput) << "Failed to get buffer" << errorString(hr);
+ return -1;
+ }
+
+ if (m_volume < qreal(1.0))
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_resampler.outputFormat(), writeBytes.data(), buffer, writeBytes.size());
+ else
+ std::memcpy(buffer, writeBytes.data(), writeBytes.size());
+
+ DWORD flags = writeBytes.isEmpty() ? AUDCLNT_BUFFERFLAGS_SILENT : 0;
+ hr = m_renderClient->ReleaseBuffer(writeFramesNum, flags);
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioOutput) << "Failed to return buffer" << errorString(hr);
+ return -1;
+ }
+
+ return writeSize;
+}
+
+void QWindowsAudioSink::resume()
+{
+ qCDebug(qLcAudioOutput) << "resume()";
+ if (deviceState == QAudio::SuspendedState) {
+ if (m_pullSource) {
+ pullSource();
+ } else {
+ deviceStateChange(suspendedInState, QAudio::NoError);
+ if (remainingPlayTimeUs() > 0)
+ m_audioClient->Start();
+ }
+ }
+}
+
+void QWindowsAudioSink::suspend()
+{
+ qCDebug(qLcAudioOutput) << "suspend()";
+ if (deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState) {
+ suspendedInState = deviceState;
+ deviceStateChange(QAudio::SuspendedState, QAudio::NoError);
+ }
+}
+
+void QWindowsAudioSink::setVolume(qreal v)
+{
+ if (qFuzzyCompare(m_volume, v))
+ return;
+
+ m_volume = qBound(qreal(0), v, qreal(1));
+}
+
+void QWindowsAudioSink::stop() {
+ // TODO: investigate and find a way to drain and stop instead of closing
+ close();
+}
+
+void QWindowsAudioSink::reset()
+{
+ close();
+}
+
+QT_END_NAMESPACE
+
+#include "qwindowsaudiosink.moc"
diff --git a/src/multimedia/windows/qwindowsaudiosink_p.h b/src/multimedia/windows/qwindowsaudiosink_p.h
new file mode 100644
index 000000000..1a98bc296
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudiosink_p.h
@@ -0,0 +1,97 @@
+// 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 QWINDOWSAUDIOOUTPUT_H
+#define QWINDOWSAUDIOOUTPUT_H
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qpointer.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodevice.h>
+#include <private/qaudiosystem_p.h>
+#include <qcomptr_p.h>
+#include <qwindowsresampler_p.h>
+
+#include <audioclient.h>
+#include <mmdeviceapi.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsResampler;
+
+class QWindowsAudioSink : public QPlatformAudioSink
+{
+ Q_OBJECT
+public:
+ QWindowsAudioSink(ComPtr<IMMDevice> device, QObject *parent);
+ ~QWindowsAudioSink();
+
+ void setFormat(const QAudioFormat& fmt) override;
+ QAudioFormat format() const override;
+ QIODevice* start() override;
+ void start(QIODevice* device) 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 { return m_bufferSize; }
+ qint64 processedUSecs() const override;
+ QAudio::Error error() const override { return errorState; }
+ QAudio::State state() const override { return deviceState; }
+ void setVolume(qreal) override;
+ qreal volume() const override { return m_volume; }
+
+private:
+ friend class OutputPrivate;
+ qint64 write(const char *data, qint64 len);
+ qint64 push(const char *data, qint64 len);
+
+ bool open();
+ void close();
+
+ void deviceStateChange(QAudio::State, QAudio::Error);
+
+ void pullSource();
+ qint64 remainingPlayTimeUs();
+
+ QAudioFormat m_format;
+ QAudio::Error errorState = QAudio::NoError;
+ QAudio::State deviceState = QAudio::StoppedState;
+ QAudio::State suspendedInState = QAudio::SuspendedState;
+
+ qsizetype m_bufferSize = 0;
+ qreal m_volume = 1.0;
+ QTimer *m_timer = nullptr;
+ QScopedPointer<QIODevice> m_pushSource;
+ QPointer<QIODevice> m_pullSource;
+ ComPtr<IMMDevice> m_device;
+ ComPtr<IAudioClient> m_audioClient;
+ ComPtr<IAudioRenderClient> m_renderClient;
+ QWindowsResampler m_resampler;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QWINDOWSAUDIOOUTPUT_H
diff --git a/src/multimedia/windows/qwindowsaudiosource.cpp b/src/multimedia/windows/qwindowsaudiosource.cpp
new file mode 100644
index 000000000..85fc454ad
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudiosource.cpp
@@ -0,0 +1,406 @@
+// 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.
+//
+// INTERNAL USE ONLY: Do NOT use for any other purpose.
+//
+
+
+#include "qwindowsaudiosource_p.h"
+#include "qwindowsmultimediautils_p.h"
+#include "qcomtaskresource_p.h"
+
+#include <QtCore/QDataStream>
+#include <QtCore/qtimer.h>
+
+#include <private/qaudiohelpers_p.h>
+
+#include <qloggingcategory.h>
+#include <qdebug.h>
+#include <audioclient.h>
+#include <mmdeviceapi.h>
+
+QT_BEGIN_NAMESPACE
+
+static Q_LOGGING_CATEGORY(qLcAudioSource, "qt.multimedia.audiosource")
+
+using namespace QWindowsMultimediaUtils;
+
+class OurSink : public QIODevice
+{
+public:
+ OurSink(QWindowsAudioSource& source) : QIODevice(&source), m_audioSource(source) {}
+
+ qint64 bytesAvailable() const override { return m_audioSource.bytesReady(); }
+ qint64 readData(char* data, qint64 len) override { return m_audioSource.read(data, len); }
+ qint64 writeData(const char*, qint64) override { return 0; }
+
+private:
+ QWindowsAudioSource &m_audioSource;
+};
+
+QWindowsAudioSource::QWindowsAudioSource(ComPtr<IMMDevice> device, QObject *parent)
+ : QPlatformAudioSource(parent),
+ m_timer(new QTimer(this)),
+ m_device(std::move(device)),
+ m_ourSink(new OurSink(*this))
+{
+ m_ourSink->open(QIODevice::ReadOnly|QIODevice::Unbuffered);
+ m_timer->setTimerType(Qt::PreciseTimer);
+ m_timer->setSingleShot(true);
+ m_timer->callOnTimeout(this, &QWindowsAudioSource::pullCaptureClient);
+}
+
+void QWindowsAudioSource::setVolume(qreal volume)
+{
+ m_volume = qBound(qreal(0), volume, qreal(1));
+}
+
+qreal QWindowsAudioSource::volume() const
+{
+ return m_volume;
+}
+
+QWindowsAudioSource::~QWindowsAudioSource()
+{
+ stop();
+}
+
+QAudio::Error QWindowsAudioSource::error() const
+{
+ return m_errorState;
+}
+
+QAudio::State QWindowsAudioSource::state() const
+{
+ return m_deviceState;
+}
+
+void QWindowsAudioSource::setFormat(const QAudioFormat& fmt)
+{
+ if (m_deviceState == QAudio::StoppedState) {
+ m_format = fmt;
+ } else {
+ if (m_format != fmt) {
+ qWarning() << "Cannot set a new audio format, in the current state ("
+ << m_deviceState << ")";
+ }
+ }
+}
+
+QAudioFormat QWindowsAudioSource::format() const
+{
+ return m_format;
+}
+
+void QWindowsAudioSource::deviceStateChange(QAudio::State state, QAudio::Error error)
+{
+ if (state != m_deviceState) {
+ bool wasActive = m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::IdleState;
+ bool isActive = state == QAudio::ActiveState || state == QAudio::IdleState;
+
+ if (isActive && !wasActive) {
+ m_audioClient->Start();
+ qCDebug(qLcAudioSource) << "Audio client started";
+
+ } else if (wasActive && !isActive) {
+ m_timer->stop();
+ m_audioClient->Stop();
+ qCDebug(qLcAudioSource) << "Audio client stopped";
+ }
+
+ m_deviceState = state;
+ emit stateChanged(m_deviceState);
+ }
+
+ if (error != m_errorState) {
+ m_errorState = error;
+ emit errorChanged(error);
+ }
+}
+
+QByteArray QWindowsAudioSource::readCaptureClientBuffer()
+{
+ UINT32 actualFrames = 0;
+ BYTE *data = nullptr;
+ DWORD flags = 0;
+ HRESULT hr = m_captureClient->GetBuffer(&data, &actualFrames, &flags, nullptr, nullptr);
+ if (FAILED(hr)) {
+ qWarning() << "IAudioCaptureClient::GetBuffer failed" << errorString(hr);
+ deviceStateChange(QAudio::IdleState, QAudio::IOError);
+ return {};
+ }
+
+ if (actualFrames == 0)
+ return {};
+
+ QByteArray out;
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
+ out.resize(m_resampler.outputFormat().bytesForDuration(
+ m_resampler.inputFormat().framesForDuration(actualFrames)),
+ 0);
+ } else {
+ out = m_resampler.resample(
+ { data, m_resampler.inputFormat().bytesForFrames(actualFrames) });
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_resampler.outputFormat(), out.data(), out.data(), out.size());
+ }
+
+ hr = m_captureClient->ReleaseBuffer(actualFrames);
+ if (FAILED(hr)) {
+ qWarning() << "IAudioCaptureClient::ReleaseBuffer failed" << errorString(hr);
+ deviceStateChange(QAudio::IdleState, QAudio::IOError);
+ return {};
+ }
+
+ return out;
+}
+
+void QWindowsAudioSource::schedulePull()
+{
+ auto allocated = QWindowsAudioUtils::audioClientFramesAllocated(m_audioClient.Get());
+ auto inUse = QWindowsAudioUtils::audioClientFramesInUse(m_audioClient.Get());
+
+ if (!allocated || !inUse) {
+ deviceStateChange(QAudio::IdleState, QAudio::IOError);
+ } else {
+ // Schedule the next audio pull immediately if the audio buffer is more
+ // than half-full or wait until the audio source fills at least half of it.
+ if (*inUse > *allocated / 2) {
+ m_timer->start(0);
+ } else {
+ auto timeToHalfBuffer = m_resampler.inputFormat().durationForFrames(*allocated / 2 - *inUse);
+ m_timer->start(timeToHalfBuffer / 1000);
+ }
+ }
+}
+
+void QWindowsAudioSource::pullCaptureClient()
+{
+ qCDebug(qLcAudioSource) << "Pull captureClient";
+ while (true) {
+ auto out = readCaptureClientBuffer();
+ if (out.isEmpty())
+ break;
+
+ if (m_clientSink) {
+ qint64 written = m_clientSink->write(out.data(), out.size());
+ if (written != out.size())
+ qCDebug(qLcAudioSource) << "Did not write all data to the output";
+
+ } else {
+ m_clientBufferResidue += out;
+ emit m_ourSink->readyRead();
+ }
+ }
+
+ schedulePull();
+}
+
+void QWindowsAudioSource::start(QIODevice* device)
+{
+ qCDebug(qLcAudioSource) << "start(ioDevice)";
+ if (m_deviceState != QAudio::StoppedState)
+ close();
+
+ if (device == nullptr)
+ return;
+
+ if (!open()) {
+ m_errorState = QAudio::OpenError;
+ emit errorChanged(QAudio::OpenError);
+ return;
+ }
+
+ m_clientSink = device;
+ schedulePull();
+ deviceStateChange(QAudio::ActiveState, QAudio::NoError);
+}
+
+QIODevice* QWindowsAudioSource::start()
+{
+ qCDebug(qLcAudioSource) << "start()";
+ if (m_deviceState != QAudio::StoppedState)
+ close();
+
+ if (!open()) {
+ m_errorState = QAudio::OpenError;
+ emit errorChanged(QAudio::OpenError);
+ return nullptr;
+ }
+
+ schedulePull();
+ deviceStateChange(QAudio::IdleState, QAudio::NoError);
+ return m_ourSink;
+}
+
+void QWindowsAudioSource::stop()
+{
+ if (m_deviceState == QAudio::StoppedState)
+ return;
+
+ close();
+}
+
+bool QWindowsAudioSource::open()
+{
+ HRESULT hr = m_device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER,
+ nullptr, (void**)m_audioClient.GetAddressOf());
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioSource) << "Failed to activate audio device" << errorString(hr);
+ return false;
+ }
+
+ QComTaskResource<WAVEFORMATEX> pwfx;
+ hr = m_audioClient->GetMixFormat(pwfx.address());
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioSource) << "Format unsupported" << errorString(hr);
+ return false;
+ }
+
+ if (!m_resampler.setup(QWindowsAudioUtils::waveFormatExToFormat(*pwfx), m_format)) {
+ qCWarning(qLcAudioSource) << "Failed to set up resampler";
+ return false;
+ }
+
+ if (m_bufferSize == 0)
+ m_bufferSize = m_format.sampleRate() * m_format.bytesPerFrame() / 5; // 200ms
+
+ REFERENCE_TIME requestedDuration = m_format.durationForBytes(m_bufferSize);
+
+ hr = m_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, requestedDuration, 0, pwfx.get(),
+ nullptr);
+
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioSource) << "Failed to initialize audio client" << errorString(hr);
+ return false;
+ }
+
+ auto framesAllocated = QWindowsAudioUtils::audioClientFramesAllocated(m_audioClient.Get());
+ if (!framesAllocated) {
+ qCWarning(qLcAudioSource) << "Failed to get audio client buffer size";
+ return false;
+ }
+
+ m_bufferSize = m_format.bytesForDuration(
+ m_resampler.inputFormat().durationForFrames(*framesAllocated));
+
+ hr = m_audioClient->GetService(__uuidof(IAudioCaptureClient), (void**)m_captureClient.GetAddressOf());
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioSource) << "Failed to obtain audio client rendering service" << errorString(hr);
+ return false;
+ }
+
+ return true;
+}
+
+void QWindowsAudioSource::close()
+{
+ qCDebug(qLcAudioSource) << "close()";
+ if (m_deviceState == QAudio::StoppedState)
+ return;
+
+ deviceStateChange(QAudio::StoppedState, QAudio::NoError);
+
+ m_clientBufferResidue.clear();
+ m_captureClient.Reset();
+ m_audioClient.Reset();
+ m_clientSink = nullptr;
+}
+
+qsizetype QWindowsAudioSource::bytesReady() const
+{
+ if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
+ return 0;
+
+ auto frames = QWindowsAudioUtils::audioClientFramesInUse(m_audioClient.Get());
+ if (frames) {
+ auto clientBufferSize = m_resampler.outputFormat().bytesForDuration(
+ m_resampler.inputFormat().durationForFrames(*frames));
+
+ return clientBufferSize + m_clientBufferResidue.size();
+
+ } else {
+ return 0;
+ }
+}
+
+qint64 QWindowsAudioSource::read(char* data, qint64 len)
+{
+ deviceStateChange(QAudio::ActiveState, QAudio::NoError);
+ schedulePull();
+
+ if (data == nullptr || len < 0)
+ return -1;
+
+ auto offset = 0;
+ if (!m_clientBufferResidue.isEmpty()) {
+ auto copyLen = qMin(m_clientBufferResidue.size(), len);
+ memcpy(data, m_clientBufferResidue.data(), copyLen);
+ len -= copyLen;
+ offset += copyLen;
+ }
+
+ m_clientBufferResidue = QByteArray{ m_clientBufferResidue.data() + offset,
+ m_clientBufferResidue.size() - offset };
+
+ if (len > 0) {
+ auto out = readCaptureClientBuffer();
+ if (!out.isEmpty()) {
+ qsizetype copyLen = qMin(out.size(), len);
+ memcpy(data + offset, out.data(), copyLen);
+ offset += copyLen;
+
+ m_clientBufferResidue = QByteArray{ out.data() + copyLen, out.size() - copyLen };
+ }
+ }
+
+ return offset;
+}
+
+void QWindowsAudioSource::resume()
+{
+ qCDebug(qLcAudioSource) << "resume()";
+ if (m_deviceState == QAudio::SuspendedState) {
+ deviceStateChange(QAudio::ActiveState, QAudio::NoError);
+ pullCaptureClient();
+ }
+}
+
+void QWindowsAudioSource::setBufferSize(qsizetype value)
+{
+ m_bufferSize = value;
+}
+
+qsizetype QWindowsAudioSource::bufferSize() const
+{
+ return m_bufferSize;
+}
+
+qint64 QWindowsAudioSource::processedUSecs() const
+{
+ if (m_deviceState == QAudio::StoppedState)
+ return 0;
+
+ return m_resampler.outputFormat().durationForBytes(m_resampler.totalOutputBytes());
+}
+
+void QWindowsAudioSource::suspend()
+{
+ qCDebug(qLcAudioSource) << "suspend";
+ if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::IdleState)
+ deviceStateChange(QAudio::SuspendedState, QAudio::NoError);
+}
+
+void QWindowsAudioSource::reset()
+{
+ stop();
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/windows/qwindowsaudiosource_p.h b/src/multimedia/windows/qwindowsaudiosource_p.h
new file mode 100644
index 000000000..68d57bbe1
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudiosource_p.h
@@ -0,0 +1,96 @@
+// 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 QWINDOWSAUDIOINPUT_H
+#define QWINDOWSAUDIOINPUT_H
+
+#include "qwindowsaudioutils_p.h"
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qbytearray.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodevice.h>
+#include <private/qaudiosystem_p.h>
+
+#include <qwindowsresampler_p.h>
+
+struct IMMDevice;
+struct IAudioClient;
+struct IAudioCaptureClient;
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+
+class QWindowsAudioSource : public QPlatformAudioSource
+{
+ Q_OBJECT
+public:
+ QWindowsAudioSource(ComPtr<IMMDevice> device, QObject *parent);
+ ~QWindowsAudioSource();
+
+ qint64 read(char* data, qint64 len);
+
+ void setFormat(const QAudioFormat& fmt) override;
+ QAudioFormat format() const override;
+ QIODevice* start() override;
+ void start(QIODevice* device) 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 setVolume(qreal volume) override;
+ qreal volume() const override;
+
+private:
+ void deviceStateChange(QAudio::State state, QAudio::Error error);
+ void pullCaptureClient();
+ void schedulePull();
+ QByteArray readCaptureClientBuffer();
+
+ QTimer *m_timer = nullptr;
+ ComPtr<IMMDevice> m_device;
+ ComPtr<IAudioClient> m_audioClient;
+ ComPtr<IAudioCaptureClient> m_captureClient;
+ QWindowsResampler m_resampler;
+ int m_bufferSize = 0;
+ qreal m_volume = 1.0;
+
+ QIODevice* m_ourSink = nullptr;
+ QIODevice* m_clientSink = nullptr;
+ QAudioFormat m_format;
+ QAudio::Error m_errorState = QAudio::NoError;
+ QAudio::State m_deviceState = QAudio::StoppedState;
+
+ QByteArray m_clientBufferResidue;
+
+ bool open();
+ void close();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/windows/qwindowsaudioutils.cpp b/src/multimedia/windows/qwindowsaudioutils.cpp
new file mode 100644
index 000000000..dce4a2135
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudioutils.cpp
@@ -0,0 +1,208 @@
+// 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 "qwindowsaudioutils_p.h"
+#include "qwindowsmediafoundation_p.h"
+#include "qdebug.h"
+#include "ks.h"
+#include "ksmedia.h"
+
+#include <audioclient.h>
+
+QT_BEGIN_NAMESPACE
+
+static QAudioFormat::AudioChannelPosition channelFormatMap[] =
+ { QAudioFormat::FrontLeft // SPEAKER_FRONT_LEFT (0x1)
+ , QAudioFormat::FrontRight // SPEAKER_FRONT_RIGHT (0x2)
+ , QAudioFormat::FrontCenter // SPEAKER_FRONT_CENTER (0x4)
+ , QAudioFormat::LFE // SPEAKER_LOW_FREQUENCY (0x8)
+ , QAudioFormat::BackLeft // SPEAKER_BACK_LEFT (0x10)
+ , QAudioFormat::BackRight // SPEAKER_BACK_RIGHT (0x20)
+ , QAudioFormat::FrontLeftOfCenter // SPEAKER_FRONT_LEFT_OF_CENTER (0x40)
+ , QAudioFormat::FrontRightOfCenter// SPEAKER_FRONT_RIGHT_OF_CENTER (0x80)
+ , QAudioFormat::BackCenter // SPEAKER_BACK_CENTER (0x100)
+ , QAudioFormat::SideLeft // SPEAKER_SIDE_LEFT (0x200)
+ , QAudioFormat::SideRight // SPEAKER_SIDE_RIGHT (0x400)
+ , QAudioFormat::TopCenter // SPEAKER_TOP_CENTER (0x800)
+ , QAudioFormat::TopFrontLeft // SPEAKER_TOP_FRONT_LEFT (0x1000)
+ , QAudioFormat::TopFrontCenter // SPEAKER_TOP_FRONT_CENTER (0x2000)
+ , QAudioFormat::TopFrontRight // SPEAKER_TOP_FRONT_RIGHT (0x4000)
+ , QAudioFormat::TopBackLeft // SPEAKER_TOP_BACK_LEFT (0x8000)
+ , QAudioFormat::TopBackCenter // SPEAKER_TOP_BACK_CENTER (0x10000)
+ , QAudioFormat::TopBackRight // SPEAKER_TOP_BACK_RIGHT (0x20000)
+ };
+
+QAudioFormat::ChannelConfig QWindowsAudioUtils::maskToChannelConfig(UINT32 mask, int count)
+{
+ quint32 config = 0;
+ int set = 0;
+ for (auto c : channelFormatMap) {
+ if (mask & 1) {
+ config |= QAudioFormat::channelConfig(c);
+ ++set;
+ }
+ if (set >= count)
+ break;
+ mask >>= 1;
+ }
+ return QAudioFormat::ChannelConfig(config);
+}
+
+static UINT32 channelConfigToMask(QAudioFormat::ChannelConfig config)
+{
+ UINT32 mask = 0;
+ quint32 i = 0;
+ for (auto c : channelFormatMap) {
+ if (config & QAudioFormat::channelConfig(c))
+ mask |= 1 << i;
+ ++i;
+ }
+ return mask;
+}
+
+bool QWindowsAudioUtils::formatToWaveFormatExtensible(const QAudioFormat &format, WAVEFORMATEXTENSIBLE &wfx)
+{
+ if (!format.isValid())
+ return false;
+
+ wfx.Format.nSamplesPerSec = format.sampleRate();
+ wfx.Format.wBitsPerSample = wfx.Samples.wValidBitsPerSample = format.bytesPerSample()*8;
+ wfx.Format.nChannels = format.channelCount();
+ wfx.Format.nBlockAlign = (wfx.Format.wBitsPerSample / 8) * wfx.Format.nChannels;
+ wfx.Format.nAvgBytesPerSec = wfx.Format.nBlockAlign * wfx.Format.nSamplesPerSec;
+ wfx.Format.cbSize = 0;
+
+ if (format.sampleFormat() == QAudioFormat::Float) {
+ wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ } else {
+ wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }
+
+ if (format.channelCount() > 2) {
+ wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ wfx.Format.cbSize = 22;
+ wfx.dwChannelMask = format.channelConfig() == QAudioFormat::ChannelConfigUnknown ? KSAUDIO_SPEAKER_DIRECTOUT
+ : DWORD(format.channelConfig());
+ }
+
+ return true;
+}
+
+QAudioFormat QWindowsAudioUtils::waveFormatExToFormat(const WAVEFORMATEX &in)
+{
+ QAudioFormat out;
+ out.setSampleRate(in.nSamplesPerSec);
+ out.setChannelCount(in.nChannels);
+ if (in.wFormatTag == WAVE_FORMAT_PCM) {
+ if (in.wBitsPerSample == 8)
+ out.setSampleFormat(QAudioFormat::UInt8);
+ else if (in.wBitsPerSample == 16)
+ out.setSampleFormat(QAudioFormat::Int16);
+ else if (in.wBitsPerSample == 32)
+ out.setSampleFormat(QAudioFormat::Int32);
+ } else if (in.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
+ if (in.cbSize >= 22) {
+ auto wfe = reinterpret_cast<const WAVEFORMATEXTENSIBLE &>(in);
+ if (wfe.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
+ out.setSampleFormat(QAudioFormat::Float);
+ if (qPopulationCount(wfe.dwChannelMask) >= in.nChannels)
+ out.setChannelConfig(maskToChannelConfig(wfe.dwChannelMask, in.nChannels));
+ }
+ } else if (in.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
+ out.setSampleFormat(QAudioFormat::Float);
+ }
+
+ return out;
+}
+
+QAudioFormat QWindowsAudioUtils::mediaTypeToFormat(IMFMediaType *mediaType)
+{
+ QAudioFormat format;
+ if (!mediaType)
+ return format;
+
+ UINT32 val = 0;
+ if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) {
+ format.setChannelCount(int(val));
+ } else {
+ qWarning() << "Could not determine channel count from IMFMediaType";
+ return {};
+ }
+
+ if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_CHANNEL_MASK, &val))) {
+ if (int(qPopulationCount(val)) >= format.channelCount())
+ format.setChannelConfig(maskToChannelConfig(val, format.channelCount()));
+ }
+
+ if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) {
+ format.setSampleRate(int(val));
+ }
+ UINT32 bitsPerSample = 0;
+ mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample);
+
+ GUID subType;
+ if (SUCCEEDED(mediaType->GetGUID(MF_MT_SUBTYPE, &subType))) {
+ if (subType == MFAudioFormat_Float) {
+ format.setSampleFormat(QAudioFormat::Float);
+ } else if (bitsPerSample == 8) {
+ format.setSampleFormat(QAudioFormat::UInt8);
+ } else if (bitsPerSample == 16) {
+ format.setSampleFormat(QAudioFormat::Int16);
+ } else if (bitsPerSample == 32){
+ format.setSampleFormat(QAudioFormat::Int32);
+ }
+ }
+ return format;
+}
+
+ComPtr<IMFMediaType> QWindowsAudioUtils::formatToMediaType(QWindowsMediaFoundation &wmf, const QAudioFormat &format)
+{
+ ComPtr<IMFMediaType> mediaType;
+
+ if (!format.isValid())
+ return mediaType;
+
+ wmf.mfCreateMediaType(mediaType.GetAddressOf());
+
+ mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
+ if (format.sampleFormat() == QAudioFormat::Float) {
+ mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
+ } else {
+ mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
+ }
+
+ mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, UINT32(format.channelCount()));
+ if (format.channelConfig() != QAudioFormat::ChannelConfigUnknown)
+ mediaType->SetUINT32(MF_MT_AUDIO_CHANNEL_MASK, channelConfigToMask(format.channelConfig()));
+ mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, UINT32(format.sampleRate()));
+ auto alignmentBlock = UINT32(format.bytesPerFrame());
+ mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, alignmentBlock);
+ auto avgBytesPerSec = UINT32(format.sampleRate() * format.bytesPerFrame());
+ mediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, avgBytesPerSec);
+ mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, UINT32(format.bytesPerSample()*8));
+ mediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+
+ return mediaType;
+}
+
+std::optional<quint32> QWindowsAudioUtils::audioClientFramesInUse(IAudioClient *client)
+{
+ Q_ASSERT(client);
+ UINT32 framesPadding = 0;
+ if (SUCCEEDED(client->GetCurrentPadding(&framesPadding)))
+ return framesPadding;
+ return {};
+}
+
+std::optional<quint32> QWindowsAudioUtils::audioClientFramesAllocated(IAudioClient *client)
+{
+ Q_ASSERT(client);
+ UINT32 bufferFrameCount = 0;
+ if (SUCCEEDED(client->GetBufferSize(&bufferFrameCount)))
+ return bufferFrameCount;
+ return {};
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/windows/qwindowsaudioutils_p.h b/src/multimedia/windows/qwindowsaudioutils_p.h
new file mode 100644
index 000000000..9382f372f
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudioutils_p.h
@@ -0,0 +1,45 @@
+// 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 QWINDOWSAUDIOUTILS_H
+#define QWINDOWSAUDIOUTILS_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 <qaudioformat.h>
+#include <QtCore/qt_windows.h>
+#include <private/qcomptr_p.h>
+#include <mmreg.h>
+
+#include <optional>
+
+struct IAudioClient;
+struct IMFMediaType;
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsMediaFoundation;
+
+namespace QWindowsAudioUtils
+{
+ bool formatToWaveFormatExtensible(const QAudioFormat &format, WAVEFORMATEXTENSIBLE &wfx);
+ QAudioFormat waveFormatExToFormat(const WAVEFORMATEX &in);
+ Q_MULTIMEDIA_EXPORT QAudioFormat mediaTypeToFormat(IMFMediaType *mediaType);
+ ComPtr<IMFMediaType> formatToMediaType(QWindowsMediaFoundation &, const QAudioFormat &format);
+ QAudioFormat::ChannelConfig maskToChannelConfig(UINT32 mask, int count);
+ std::optional<quint32> audioClientFramesInUse(IAudioClient *client);
+ std::optional<quint32> audioClientFramesAllocated(IAudioClient *client);
+}
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSAUDIOUTILS_H
diff --git a/src/multimedia/windows/qwindowsmediadevices.cpp b/src/multimedia/windows/qwindowsmediadevices.cpp
new file mode 100644
index 000000000..c622a721c
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmediadevices.cpp
@@ -0,0 +1,345 @@
+// 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 "qwindowsmediadevices_p.h"
+#include "qmediadevices.h"
+#include "qvarlengtharray.h"
+
+#include "qwindowsaudiosource_p.h"
+#include "qwindowsaudiosink_p.h"
+#include "qwindowsaudiodevice_p.h"
+#include "qcomtaskresource_p.h"
+
+#include <mmsystem.h>
+#include <mmddk.h>
+#include <mfobjects.h>
+#include <mfidl.h>
+#include <mferror.h>
+#include <mmdeviceapi.h>
+#include <qwindowsmfdefs_p.h>
+
+#include <QtCore/qmap.h>
+#include <private/qcomobject_p.h>
+#include <private/qsystemerror_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class CMMNotificationClient : public QComObject<IMMNotificationClient>
+{
+ ComPtr<IMMDeviceEnumerator> m_enumerator;
+ QWindowsMediaDevices *m_windowsMediaDevices;
+ QMap<QString, DWORD> m_deviceState;
+
+public:
+ CMMNotificationClient(QWindowsMediaDevices *windowsMediaDevices,
+ ComPtr<IMMDeviceEnumerator> enumerator,
+ QMap<QString, DWORD> &&deviceState)
+ : m_enumerator(enumerator),
+ m_windowsMediaDevices(windowsMediaDevices),
+ m_deviceState(deviceState)
+ {}
+
+ HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR) override
+ {
+ if (role == ERole::eMultimedia)
+ emitAudioDevicesChanged(flow);
+
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR deviceID) override
+ {
+ auto it = m_deviceState.find(QString::fromWCharArray(deviceID));
+ if (it == std::end(m_deviceState)) {
+ m_deviceState.insert(QString::fromWCharArray(deviceID), DEVICE_STATE_ACTIVE);
+ emitAudioDevicesChanged(deviceID);
+ }
+
+ return S_OK;
+ };
+
+ HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR deviceID) override
+ {
+ auto key = QString::fromWCharArray(deviceID);
+ auto it = m_deviceState.find(key);
+ if (it != std::end(m_deviceState)) {
+ if (it.value() == DEVICE_STATE_ACTIVE)
+ emitAudioDevicesChanged(deviceID);
+ m_deviceState.remove(key);
+ }
+
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR deviceID, DWORD newState) override
+ {
+ if (auto it = m_deviceState.find(QString::fromWCharArray(deviceID)); it != std::end(m_deviceState)) {
+ // If either the old state or the new state is active emit device change
+ if ((it.value() == DEVICE_STATE_ACTIVE) != (newState == DEVICE_STATE_ACTIVE)) {
+ emitAudioDevicesChanged(deviceID);
+ }
+ it.value() = newState;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) override
+ {
+ return S_OK;
+ }
+
+ void emitAudioDevicesChanged(EDataFlow flow)
+ {
+ // windowsMediaDevice may be deleted as we are executing the callback
+ if (flow == EDataFlow::eCapture) {
+ emit m_windowsMediaDevices->audioInputsChanged();
+ } else if (flow == EDataFlow::eRender) {
+ emit m_windowsMediaDevices->audioOutputsChanged();
+ }
+ }
+
+ void emitAudioDevicesChanged(LPCWSTR deviceID)
+ {
+ ComPtr<IMMDevice> device;
+ ComPtr<IMMEndpoint> endpoint;
+ EDataFlow flow;
+
+ if (SUCCEEDED(m_enumerator->GetDevice(deviceID, device.GetAddressOf()))
+ && SUCCEEDED(device->QueryInterface(__uuidof(IMMEndpoint), (void**)endpoint.GetAddressOf()))
+ && SUCCEEDED(endpoint->GetDataFlow(&flow)))
+ {
+ emitAudioDevicesChanged(flow);
+ }
+ }
+
+private:
+ // Destructor is not public. Caller should call Release.
+ ~CMMNotificationClient() override = default;
+};
+
+QWindowsMediaDevices::QWindowsMediaDevices()
+ : QPlatformMediaDevices()
+{
+ auto hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
+ CLSCTX_INPROC_SERVER,__uuidof(IMMDeviceEnumerator),
+ (void**)&m_deviceEnumerator);
+
+ if (FAILED(hr)) {
+ qWarning("Failed to instantiate IMMDeviceEnumerator (%s)."
+ "Audio device change notification will be disabled",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return;
+ }
+
+ QMap<QString, DWORD> devState;
+ ComPtr<IMMDeviceCollection> devColl;
+ UINT count = 0;
+
+ if (SUCCEEDED(m_deviceEnumerator->EnumAudioEndpoints(EDataFlow::eAll, DEVICE_STATEMASK_ALL, devColl.GetAddressOf()))
+ && SUCCEEDED(devColl->GetCount(&count)))
+ {
+ for (UINT i = 0; i < count; i++) {
+ ComPtr<IMMDevice> device;
+ DWORD state = 0;
+ QComTaskResource<WCHAR> id;
+
+ if (SUCCEEDED(devColl->Item(i, device.GetAddressOf()))
+ && SUCCEEDED(device->GetState(&state))
+ && SUCCEEDED(device->GetId(id.address()))) {
+ devState.insert(QString::fromWCharArray(id.get()), state);
+ }
+ }
+ }
+
+
+ m_notificationClient = makeComObject<CMMNotificationClient>(this, m_deviceEnumerator, std::move(devState));
+ m_deviceEnumerator->RegisterEndpointNotificationCallback(m_notificationClient.Get());
+}
+
+QWindowsMediaDevices::~QWindowsMediaDevices()
+{
+ if (m_deviceEnumerator) {
+ // Note: Calling UnregisterEndpointNotificationCallback after CoUninitialize
+ // will abruptly terminate application, preventing remaining destructors from
+ // being called (QTBUG-120198).
+ m_deviceEnumerator->UnregisterEndpointNotificationCallback(m_notificationClient.Get());
+ }
+ if (m_warmUpAudioClient) {
+ HRESULT hr = m_warmUpAudioClient->Stop();
+ if (FAILED(hr)) {
+ qWarning() << "Failed to stop audio engine" << hr;
+ }
+ }
+
+ m_deviceEnumerator.Reset();
+ m_notificationClient.Reset();
+ m_warmUpAudioClient.Reset();
+}
+
+QList<QAudioDevice> QWindowsMediaDevices::availableDevices(QAudioDevice::Mode mode) const
+{
+ if (!m_deviceEnumerator)
+ return {};
+
+ const auto audioOut = mode == QAudioDevice::Output;
+
+ const auto defaultAudioDeviceID = [this, audioOut]{
+ const auto dataFlow = audioOut ? EDataFlow::eRender : EDataFlow::eCapture;
+ ComPtr<IMMDevice> dev;
+ QComTaskResource<WCHAR> id;
+ QString sid;
+
+ if (SUCCEEDED(m_deviceEnumerator->GetDefaultAudioEndpoint(dataFlow, ERole::eMultimedia, dev.GetAddressOf()))) {
+ if (dev && SUCCEEDED(dev->GetId(id.address()))) {
+ sid = QString::fromWCharArray(id.get());
+ }
+ }
+ return sid.toUtf8();
+ }();
+
+ QList<QAudioDevice> devices;
+
+ auto waveDevices = audioOut ? waveOutGetNumDevs() : waveInGetNumDevs();
+
+ for (auto waveID = 0u; waveID < waveDevices; waveID++) {
+ auto wave = IntToPtr(waveID);
+ auto waveMessage = [wave, audioOut](UINT msg, auto p0, auto p1) {
+ return audioOut ? waveOutMessage((HWAVEOUT)wave, msg, (DWORD_PTR)p0, (DWORD_PTR)p1)
+ : waveInMessage((HWAVEIN)wave, msg, (DWORD_PTR)p0, (DWORD_PTR)p1);
+ };
+
+ size_t len = 0;
+ if (waveMessage(DRV_QUERYFUNCTIONINSTANCEIDSIZE, &len, 0) != MMSYSERR_NOERROR)
+ continue;
+
+ QVarLengthArray<WCHAR> id(len);
+ if (waveMessage(DRV_QUERYFUNCTIONINSTANCEID, id.data(), len) != MMSYSERR_NOERROR)
+ continue;
+
+ ComPtr<IMMDevice> device;
+ ComPtr<IPropertyStore> props;
+ if (FAILED(m_deviceEnumerator->GetDevice(id.data(), device.GetAddressOf()))
+ || FAILED(device->OpenPropertyStore(STGM_READ, props.GetAddressOf()))) {
+ continue;
+ }
+
+ PROPVARIANT varName;
+ PropVariantInit(&varName);
+
+ if (SUCCEEDED(props->GetValue(QMM_PKEY_Device_FriendlyName, &varName))) {
+ auto description = QString::fromWCharArray(varName.pwszVal);
+ auto strID = QString::fromWCharArray(id.data()).toUtf8();
+
+ auto dev = new QWindowsAudioDeviceInfo(strID, device, waveID, description, mode);
+ dev->isDefault = strID == defaultAudioDeviceID;
+
+ devices.append(dev->create());
+ }
+ PropVariantClear(&varName);
+ }
+
+ return devices;
+}
+
+QList<QAudioDevice> QWindowsMediaDevices::audioInputs() const
+{
+ return availableDevices(QAudioDevice::Input);
+}
+
+QList<QAudioDevice> QWindowsMediaDevices::audioOutputs() const
+{
+ return availableDevices(QAudioDevice::Output);
+}
+
+QPlatformAudioSource *QWindowsMediaDevices::createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ const auto *devInfo = static_cast<const QWindowsAudioDeviceInfo *>(deviceInfo.handle());
+ return new QWindowsAudioSource(devInfo->immDev(), parent);
+}
+
+QPlatformAudioSink *QWindowsMediaDevices::createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ const auto *devInfo = static_cast<const QWindowsAudioDeviceInfo *>(deviceInfo.handle());
+ return new QWindowsAudioSink(devInfo->immDev(), parent);
+}
+
+static bool isPrepareAudioEnabled()
+{
+ static bool isDisableAudioPrepareSet = false;
+ static const int disableAudioPrepare =
+ qEnvironmentVariableIntValue("QT_DISABLE_AUDIO_PREPARE", &isDisableAudioPrepareSet);
+
+ return !isDisableAudioPrepareSet || disableAudioPrepare == 0;
+}
+
+void QWindowsMediaDevices::prepareAudio()
+{
+ if (!isPrepareAudioEnabled())
+ return;
+
+ if (m_isAudioClientWarmedUp.exchange(true))
+ return;
+
+ ComPtr<IMMDeviceEnumerator> deviceEnumerator;
+ HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
+ __uuidof(IMMDeviceEnumerator),
+ reinterpret_cast<void **>(deviceEnumerator.GetAddressOf()));
+ if (FAILED(hr)) {
+ qWarning() << "Failed to create device enumerator" << hr;
+ return;
+ }
+
+ ComPtr<IMMDevice> device;
+ hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, device.GetAddressOf());
+ if (FAILED(hr)) {
+ if (hr != E_NOTFOUND)
+ qWarning() << "Failed to retrieve default audio endpoint" << hr;
+ return;
+ }
+
+ hr = device->Activate(__uuidof(IAudioClient3), CLSCTX_ALL, nullptr,
+ reinterpret_cast<void **>(m_warmUpAudioClient.GetAddressOf()));
+ if (FAILED(hr)) {
+ qWarning() << "Failed to activate audio engine" << hr;
+ return;
+ }
+
+ QComTaskResource<WAVEFORMATEX> deviceFormat;
+ UINT32 currentPeriodInFrames = 0;
+ hr = m_warmUpAudioClient->GetCurrentSharedModeEnginePeriod(deviceFormat.address(),
+ &currentPeriodInFrames);
+ if (FAILED(hr)) {
+ qWarning() << "Failed to retrieve the current format and periodicity of the audio engine"
+ << hr;
+ return;
+ }
+
+ UINT32 defaultPeriodInFrames = 0;
+ UINT32 fundamentalPeriodInFrames = 0;
+ UINT32 minPeriodInFrames = 0;
+ UINT32 maxPeriodInFrames = 0;
+ hr = m_warmUpAudioClient->GetSharedModeEnginePeriod(deviceFormat.get(), &defaultPeriodInFrames,
+ &fundamentalPeriodInFrames,
+ &minPeriodInFrames, &maxPeriodInFrames);
+ if (FAILED(hr)) {
+ qWarning() << "Failed to retrieve the range of periodicities supported by the audio engine"
+ << hr;
+ return;
+ }
+
+ hr = m_warmUpAudioClient->InitializeSharedAudioStream(
+ AUDCLNT_SHAREMODE_SHARED, minPeriodInFrames, deviceFormat.get(), nullptr);
+ if (FAILED(hr)) {
+ qWarning() << "Failed to initialize audio engine stream" << hr;
+ return;
+ }
+
+ hr = m_warmUpAudioClient->Start();
+ if (FAILED(hr))
+ qWarning() << "Failed to start audio engine" << hr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/windows/qwindowsmediadevices_p.h b/src/multimedia/windows/qwindowsmediadevices_p.h
new file mode 100644
index 000000000..c82be8a0d
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmediadevices_p.h
@@ -0,0 +1,65 @@
+// 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
+
+#ifndef QWINDOWSMEDIADEVICES_H
+#define QWINDOWSMEDIADEVICES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qplatformmediadevices_p.h>
+#include <private/qcomptr_p.h>
+#include <QtCore/private/qfunctions_win_p.h>
+#include <private/qwindowsmediafoundation_p.h>
+
+#include <qaudiodevice.h>
+
+struct IAudioClient3;
+struct IMMDeviceEnumerator;
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsEngine;
+class CMMNotificationClient;
+
+class QWindowsMediaDevices : public QPlatformMediaDevices
+{
+public:
+ QWindowsMediaDevices();
+ virtual ~QWindowsMediaDevices();
+
+ QList<QAudioDevice> audioInputs() const override;
+ QList<QAudioDevice> audioOutputs() const override;
+ QPlatformAudioSource *createAudioSource(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+ QPlatformAudioSink *createAudioSink(const QAudioDevice &deviceInfo,
+ QObject *parent) override;
+
+ void prepareAudio() override;
+
+private:
+ QComHelper m_comRuntime;
+ QMFRuntimeInit m_wmfRuntime{ QWindowsMediaFoundation::instance() };
+ QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode) const;
+
+ ComPtr<IMMDeviceEnumerator> m_deviceEnumerator;
+ ComPtr<CMMNotificationClient> m_notificationClient;
+ // The "warm-up" audio client is required to run in the background in order to keep audio engine
+ // ready for audio output immediately after creating any other subsequent audio client.
+ ComPtr<IAudioClient3> m_warmUpAudioClient;
+ std::atomic_bool m_isAudioClientWarmedUp = false;
+
+ friend CMMNotificationClient;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/windows/qwindowsmediafoundation.cpp b/src/multimedia/windows/qwindowsmediafoundation.cpp
new file mode 100644
index 000000000..7094c9551
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmediafoundation.cpp
@@ -0,0 +1,70 @@
+// 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 "qwindowsmediafoundation_p.h"
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+Q_GLOBAL_STATIC(QWindowsMediaFoundation, s_wmf);
+
+template <typename T>
+bool setProcAddress(QSystemLibrary &lib, T &f, const char name[])
+{
+ f = reinterpret_cast<T>(lib.resolve(name));
+ return static_cast<bool>(f);
+}
+
+} // namespace
+
+QWindowsMediaFoundation *QWindowsMediaFoundation::instance()
+{
+ if (s_wmf->valid())
+ return s_wmf;
+
+ return nullptr;
+}
+
+QWindowsMediaFoundation::QWindowsMediaFoundation()
+{
+ if (!m_mfplat.load(false))
+ return;
+
+ m_valid = setProcAddress(m_mfplat, mfStartup, "MFStartup")
+ && setProcAddress(m_mfplat, mfShutdown, "MFShutdown")
+ && setProcAddress(m_mfplat, mfCreateMediaType, "MFCreateMediaType")
+ && setProcAddress(m_mfplat, mfCreateMemoryBuffer, "MFCreateMemoryBuffer")
+ && setProcAddress(m_mfplat, mfCreateSample, "MFCreateSample");
+
+ Q_ASSERT(m_valid); // If it is not valid at this point, we have a programming bug
+}
+
+QWindowsMediaFoundation::~QWindowsMediaFoundation() = default;
+
+bool QWindowsMediaFoundation::valid() const
+{
+ return m_valid;
+}
+
+QMFRuntimeInit::QMFRuntimeInit(QWindowsMediaFoundation *wmf)
+ : m_wmf{ wmf }, m_initResult{ wmf ? m_wmf->mfStartup(MF_VERSION, MFSTARTUP_FULL) : E_FAIL }
+{
+ if (m_initResult != S_OK)
+ qErrnoWarning(m_initResult, "Failed to initialize Windows Media Foundation");
+}
+
+QMFRuntimeInit::~QMFRuntimeInit()
+{
+ // According to documentation MFShutdown should be called
+ // also when MFStartup failed. This is wrong.
+ if (FAILED(m_initResult))
+ return;
+
+ const HRESULT hr = m_wmf->mfShutdown();
+ if (hr != S_OK)
+ qErrnoWarning(hr, "Failed to shut down Windows Media Foundation");
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/windows/qwindowsmediafoundation_p.h b/src/multimedia/windows/qwindowsmediafoundation_p.h
new file mode 100644
index 000000000..6dabc261e
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmediafoundation_p.h
@@ -0,0 +1,59 @@
+// 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
+
+#ifndef QWINDOWSMEDIAFOUNDATION_H
+#define QWINDOWSMEDIAFOUNDATION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtmultimediaglobal_p.h>
+#include <QtCore/private/qsystemlibrary_p.h>
+#include <mfapi.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsMediaFoundation
+{
+public:
+ static QWindowsMediaFoundation *instance();
+
+ QWindowsMediaFoundation();
+ ~QWindowsMediaFoundation();
+
+ bool valid() const;
+
+ decltype(&::MFStartup) mfStartup = nullptr;
+ decltype(&::MFShutdown) mfShutdown = nullptr;
+ decltype(&::MFCreateMediaType) mfCreateMediaType = nullptr;
+ decltype(&::MFCreateMemoryBuffer) mfCreateMemoryBuffer = nullptr;
+ decltype(&::MFCreateSample) mfCreateSample = nullptr;
+
+private:
+ QSystemLibrary m_mfplat{ QStringLiteral("Mfplat.dll") };
+ bool m_valid = false;
+};
+
+class QMFRuntimeInit
+{
+ Q_DISABLE_COPY_MOVE(QMFRuntimeInit)
+public:
+ QMFRuntimeInit(QWindowsMediaFoundation *wmf);
+ ~QMFRuntimeInit();
+
+private:
+ QWindowsMediaFoundation *m_wmf;
+ HRESULT m_initResult;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSMEDIAFOUNDATION_H
diff --git a/src/multimedia/windows/qwindowsmfdefs.cpp b/src/multimedia/windows/qwindowsmfdefs.cpp
new file mode 100644
index 000000000..ef8c99922
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmfdefs.cpp
@@ -0,0 +1,26 @@
+// 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 "qwindowsmfdefs_p.h"
+
+const GUID QMM_MFTranscodeContainerType_ADTS = {0x132fd27d, 0x0f02, 0x43de, {0xa3, 0x01, 0x38, 0xfb, 0xbb, 0xb3, 0x83, 0x4e}};
+const GUID QMM_MFTranscodeContainerType_ASF = {0x430f6f6e, 0xb6bf, 0x4fc1, {0xa0, 0xbd, 0x9e, 0xe4, 0x6e, 0xee, 0x2a, 0xfb}};
+const GUID QMM_MFTranscodeContainerType_AVI = {0x7edfe8af, 0x402f, 0x4d76, {0xa3, 0x3c, 0x61, 0x9f, 0xd1, 0x57, 0xd0, 0xf1}};
+const GUID QMM_MFTranscodeContainerType_FLAC = {0x31344aa3, 0x05a9, 0x42b5, {0x90, 0x1b, 0x8e, 0x9d, 0x42, 0x57, 0xf7, 0x5e}};
+const GUID QMM_MFTranscodeContainerType_MP3 = {0xe438b912, 0x83f1, 0x4de6, {0x9e, 0x3a, 0x9f, 0xfb, 0xc6, 0xdd, 0x24, 0xd1}};
+const GUID QMM_MFTranscodeContainerType_MPEG4 = {0xdc6cd05d, 0xb9d0, 0x40ef, {0xbd, 0x35, 0xfa, 0x62, 0x2c, 0x1a, 0xb2, 0x8a}};
+const GUID QMM_MFTranscodeContainerType_WAVE = {0x64c3453c, 0x0f26, 0x4741, {0xbe, 0x63, 0x87, 0xbd, 0xf8, 0xbb, 0x93, 0x5b}};
+
+const GUID QMM_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID = {0x8ac3587a, 0x4ae7, 0x42d8, {0x99, 0xe0, 0x0a, 0x60, 0x13, 0xee, 0xf9, 0x0f}};
+const GUID QMM_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID = {0x14dd9a1c, 0x7cff, 0x41be, {0xb1, 0xb9, 0xba, 0x1a, 0xc6, 0xec, 0xb5, 0x71}};
+const GUID QMM_MF_TRANSCODE_CONTAINERTYPE = {0x150ff23f, 0x4abc, 0x478b, {0xac, 0x4f, 0xe1, 0x91, 0x6f, 0xba, 0x1c, 0xca}};
+
+const GUID QMM_MF_SD_STREAM_NAME = {0x4f1b099d, 0xd314, 0x41e5, {0xa7, 0x81, 0x7f, 0xef, 0xaa, 0x4c, 0x50, 0x1f}};
+const GUID QMM_MF_SD_LANGUAGE = {0xaf2180, 0xbdc2, 0x423c, {0xab, 0xca, 0xf5, 0x3, 0x59, 0x3b, 0xc1, 0x21}};
+
+const GUID QMM_KSCATEGORY_VIDEO_CAMERA = {0xe5323777, 0xf976, 0x4f5b, {0x9b, 0x55, 0xb9, 0x46, 0x99, 0xc4, 0x6e, 0x44}};
+const GUID QMM_KSCATEGORY_SENSOR_CAMERA = {0x24e552d7, 0x6523, 0x47f7, {0xa6, 0x47, 0xd3, 0x46, 0x5b, 0xf1, 0xf5, 0xca}};
+const GUID QMM_MR_POLICY_VOLUME_SERVICE = {0x1abaa2ac, 0x9d3b, 0x47c6, {0xab, 0x48, 0xc5, 0x95, 0x6, 0xde, 0x78, 0x4d}};
+
+const PROPERTYKEY QMM_PKEY_Device_FriendlyName = {{0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}}, 14};
+
diff --git a/src/multimedia/windows/qwindowsmfdefs_p.h b/src/multimedia/windows/qwindowsmfdefs_p.h
new file mode 100644
index 000000000..4bb90dbe3
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmfdefs_p.h
@@ -0,0 +1,94 @@
+// 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
+
+#ifndef QWINDOWSMFDEFS_P_H
+#define QWINDOWSMFDEFS_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 <qtmultimediaexports.h>
+#include <d3d9.h>
+#include <dxva2api.h>
+#include <mfidl.h>
+
+// Stuff that is missing or incorrecty defined in MinGW.
+
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MFTranscodeContainerType_ADTS;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MFTranscodeContainerType_ASF;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MFTranscodeContainerType_AVI;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MFTranscodeContainerType_FLAC;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MFTranscodeContainerType_MP3;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MFTranscodeContainerType_MPEG4;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MFTranscodeContainerType_WAVE;
+
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MF_TRANSCODE_CONTAINERTYPE;
+
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MF_SD_STREAM_NAME;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MF_SD_LANGUAGE;
+
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_KSCATEGORY_VIDEO_CAMERA;
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_KSCATEGORY_SENSOR_CAMERA;
+
+Q_MULTIMEDIA_EXPORT extern const GUID QMM_MR_POLICY_VOLUME_SERVICE;
+
+Q_MULTIMEDIA_EXPORT extern const PROPERTYKEY QMM_PKEY_Device_FriendlyName;
+
+extern "C" HRESULT WINAPI MFCreateDeviceSource(IMFAttributes *pAttributes, IMFMediaSource **ppSource);
+
+#define QMM_MFSESSION_GETFULLTOPOLOGY_CURRENT 1
+#define QMM_PRESENTATION_CURRENT_POSITION 0x7fffffffffffffff
+#define QMM_WININET_E_CANNOT_CONNECT ((HRESULT)0x80072EFDL)
+
+#ifndef __IMFVideoProcessor_INTERFACE_DEFINED__
+#define __IMFVideoProcessor_INTERFACE_DEFINED__
+DEFINE_GUID(IID_IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E);
+MIDL_INTERFACE("6AB0000C-FECE-4d1f-A2AC-A9573530656E")
+IMFVideoProcessor : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoProcessorModes(UINT *, GUID **) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorCaps(LPGUID, DXVA2_VideoProcessorCaps *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorMode(LPGUID) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetVideoProcessorMode(LPGUID) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetProcAmpRange(DWORD, DXVA2_ValueRange *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetFilteringRange(DWORD, DXVA2_ValueRange *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetBackgroundColor(COLORREF *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetBackgroundColor(COLORREF) = 0;
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E)
+#endif
+#endif // __IMFVideoProcessor_INTERFACE_DEFINED__
+
+#ifndef __IMFSimpleAudioVolume_INTERFACE_DEFINED__
+#define __IMFSimpleAudioVolume_INTERFACE_DEFINED__
+DEFINE_GUID(IID_IMFSimpleAudioVolume, 0x089EDF13, 0xCF71, 0x4338, 0x8D,0x13, 0x9E,0x56,0x9D,0xBD,0xC3,0x19);
+MIDL_INTERFACE("089EDF13-CF71-4338-8D13-9E569DBDC319")
+IMFSimpleAudioVolume : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE SetMasterVolume(float) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetMasterVolume(float *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetMute(BOOL) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetMute(BOOL *) = 0;
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IMFSimpleAudioVolume, 0x089EDF13, 0xCF71, 0x4338, 0x8D,0x13, 0x9E,0x56,0x9D,0xBD,0xC3,0x19)
+#endif
+#endif // __IMFSimpleAudioVolume_INTERFACE_DEFINED__
+
+#endif // QWINDOWSMFDEFS_P_H
+
diff --git a/src/multimedia/platform/windows/common/qwindowsmultimediautils.cpp b/src/multimedia/windows/qwindowsmultimediautils.cpp
index ad6a234eb..258cb3e96 100644
--- a/src/multimedia/platform/windows/common/qwindowsmultimediautils.cpp
+++ b/src/multimedia/windows/qwindowsmultimediautils.cpp
@@ -1,46 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#if defined(WINVER) && WINVER < _WIN32_WINNT_WIN10
+# undef WINVER
+#endif
+#if !defined(WINVER)
+# define WINVER _WIN32_WINNT_WIN10 // Enables newer audio formats.
+#endif
#include "qwindowsmultimediautils_p.h"
+#include <initguid.h>
#include <mfapi.h>
#include <mfidl.h>
+#include <qwindowsmfdefs_p.h>
+#include <system_error>
QT_BEGIN_NAMESPACE
@@ -78,6 +52,8 @@ QVideoFrameFormat::PixelFormat QWindowsMultimediaUtils::pixelFormatFromMediaSubt
return QVideoFrameFormat::Format_Y8;
if (subtype == MFVideoFormat_L16)
return QVideoFrameFormat::Format_Y16;
+ if (subtype == MFVideoFormat_MJPG)
+ return QVideoFrameFormat::Format_Jpeg;
return QVideoFrameFormat::Format_Invalid;
}
@@ -199,13 +175,13 @@ GUID QWindowsMultimediaUtils::containerForVideoFileFormat(QMediaFormat::FileForm
{
switch (format) {
case QMediaFormat::FileFormat::MPEG4:
- return MFTranscodeContainerType_MPEG4;
+ return QMM_MFTranscodeContainerType_MPEG4;
case QMediaFormat::FileFormat::WMV:
- return MFTranscodeContainerType_ASF;
+ return QMM_MFTranscodeContainerType_ASF;
case QMediaFormat::FileFormat::AVI:
- return MFTranscodeContainerType_AVI;
+ return QMM_MFTranscodeContainerType_AVI;
default:
- return MFTranscodeContainerType_MPEG4;
+ return QMM_MFTranscodeContainerType_MPEG4;
}
}
@@ -213,20 +189,27 @@ GUID QWindowsMultimediaUtils::containerForAudioFileFormat(QMediaFormat::FileForm
{
switch (format) {
case QMediaFormat::FileFormat::MP3:
- return MFTranscodeContainerType_MP3;
+ return QMM_MFTranscodeContainerType_MP3;
case QMediaFormat::FileFormat::AAC:
- return MFTranscodeContainerType_ADTS;
+ return QMM_MFTranscodeContainerType_ADTS;
case QMediaFormat::FileFormat::Mpeg4Audio:
- return MFTranscodeContainerType_MPEG4;
+ return QMM_MFTranscodeContainerType_MPEG4;
case QMediaFormat::FileFormat::WMA:
- return MFTranscodeContainerType_ASF;
+ return QMM_MFTranscodeContainerType_ASF;
case QMediaFormat::FileFormat::FLAC:
- return MFTranscodeContainerType_FLAC;
+ return QMM_MFTranscodeContainerType_FLAC;
case QMediaFormat::FileFormat::Wave:
- return MFTranscodeContainerType_WAVE;
+ return QMM_MFTranscodeContainerType_WAVE;
default:
- return MFTranscodeContainerType_MPEG4;
+ return QMM_MFTranscodeContainerType_MPEG4;
}
}
+QString QWindowsMultimediaUtils::errorString(HRESULT hr)
+{
+ return QStringLiteral("%1 %2")
+ .arg(quint32(hr), 8, 16)
+ .arg(QString::fromStdString(std::system_category().message(hr)));
+}
+
QT_END_NAMESPACE
diff --git a/src/multimedia/windows/qwindowsmultimediautils_p.h b/src/multimedia/windows/qwindowsmultimediautils_p.h
new file mode 100644
index 000000000..58ecd425f
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmultimediautils_p.h
@@ -0,0 +1,47 @@
+// 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
+
+#ifndef QWINDOWSMULTIMEDIATUTILS_P_H
+#define QWINDOWSMULTIMEDIATUTILS_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 <private/qtmultimediaglobal_p.h>
+#include <private/qplatformmediaformatinfo_p.h>
+#include <qvideoframeformat.h>
+#include <guiddef.h>
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QWindowsMultimediaUtils {
+
+ Q_MULTIMEDIA_EXPORT QVideoFrameFormat::PixelFormat pixelFormatFromMediaSubtype(const GUID &subtype);
+
+ Q_MULTIMEDIA_EXPORT GUID videoFormatForCodec(QMediaFormat::VideoCodec codec);
+
+ Q_MULTIMEDIA_EXPORT QMediaFormat::VideoCodec codecForVideoFormat(GUID format);
+
+ Q_MULTIMEDIA_EXPORT GUID audioFormatForCodec(QMediaFormat::AudioCodec codec);
+
+ Q_MULTIMEDIA_EXPORT QMediaFormat::AudioCodec codecForAudioFormat(GUID format);
+
+ Q_MULTIMEDIA_EXPORT GUID containerForVideoFileFormat(QMediaFormat::FileFormat format);
+
+ Q_MULTIMEDIA_EXPORT GUID containerForAudioFileFormat(QMediaFormat::FileFormat format);
+
+ Q_MULTIMEDIA_EXPORT QString errorString(HRESULT hr);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/windows/qwindowsresampler.cpp b/src/multimedia/windows/qwindowsresampler.cpp
new file mode 100644
index 000000000..3c50c0c19
--- /dev/null
+++ b/src/multimedia/windows/qwindowsresampler.cpp
@@ -0,0 +1,241 @@
+// 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 "qwindowsresampler_p.h"
+#include <qwindowsaudioutils_p.h>
+#include <qloggingcategory.h>
+#include <QUuid>
+
+#include <wmcodecdsp.h>
+#include <mftransform.h>
+#include <mferror.h>
+
+QT_BEGIN_NAMESPACE
+
+QUuid qIID_IMFTransform(0xbf94c121, 0x5b05, 0x4e6f, 0x80,0x00, 0xba,0x59,0x89,0x61,0x41,0x4d);
+QUuid qCLSID_CResamplerMediaObject("f447b69e-1884-4a7e-8055-346f74d6edb3");
+
+static Q_LOGGING_CATEGORY(qLcAudioResampler, "qt.multimedia.audioresampler")
+
+QWindowsResampler::QWindowsResampler()
+{
+ CoCreateInstance(qCLSID_CResamplerMediaObject, nullptr, CLSCTX_INPROC_SERVER,
+ qIID_IMFTransform, (LPVOID*)(m_resampler.GetAddressOf()));
+ if (m_resampler)
+ m_resampler->AddInputStreams(1, &m_inputStreamID);
+}
+
+QWindowsResampler::~QWindowsResampler() = default;
+
+quint64 QWindowsResampler::outputBufferSize(quint64 inputBufferSize) const
+{
+ if (m_inputFormat.isValid() && m_outputFormat.isValid())
+ return m_outputFormat.bytesForDuration(m_inputFormat.durationForBytes(inputBufferSize));
+ else
+ return 0;
+}
+
+quint64 QWindowsResampler::inputBufferSize(quint64 outputBufferSize) const
+{
+ if (m_inputFormat.isValid() && m_outputFormat.isValid())
+ return m_inputFormat.bytesForDuration(m_outputFormat.durationForBytes(outputBufferSize));
+ else
+ return 0;
+}
+
+HRESULT QWindowsResampler::processInput(const QByteArrayView &in)
+{
+ ComPtr<IMFSample> sample;
+ HRESULT hr = m_wmf->mfCreateSample(sample.GetAddressOf());
+ if (FAILED(hr))
+ return hr;
+
+ ComPtr<IMFMediaBuffer> buffer;
+ hr = m_wmf->mfCreateMemoryBuffer(in.size(), buffer.GetAddressOf());
+ if (FAILED(hr))
+ return hr;
+
+ BYTE *data = nullptr;
+ DWORD maxLen = 0;
+ DWORD currentLen = 0;
+ hr = buffer->Lock(&data, &maxLen, &currentLen);
+ if (FAILED(hr))
+ return hr;
+
+ memcpy(data, in.data(), in.size());
+
+ hr = buffer->Unlock();
+ if (FAILED(hr))
+ return hr;
+
+ hr = buffer->SetCurrentLength(in.size());
+ if (FAILED(hr))
+ return hr;
+
+ hr = sample->AddBuffer(buffer.Get());
+ if (FAILED(hr))
+ return hr;
+
+ return m_resampler->ProcessInput(m_inputStreamID, sample.Get(), 0);
+}
+
+HRESULT QWindowsResampler::processOutput(QByteArray &out)
+{
+ ComPtr<IMFSample> sample;
+ ComPtr<IMFMediaBuffer> buffer;
+
+ if (m_resamplerNeedsSampleBuffer) {
+ HRESULT hr = m_wmf->mfCreateSample(sample.GetAddressOf());
+ if (FAILED(hr))
+ return hr;
+
+ auto expectedOutputSize = outputBufferSize(m_totalInputBytes) - m_totalOutputBytes;
+ hr = m_wmf->mfCreateMemoryBuffer(expectedOutputSize, buffer.GetAddressOf());
+ if (FAILED(hr))
+ return hr;
+
+ hr = sample->AddBuffer(buffer.Get());
+ if (FAILED(hr))
+ return hr;
+ }
+
+ HRESULT hr = S_OK;
+
+ MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
+ outputDataBuffer.dwStreamID = 0;
+ do {
+ outputDataBuffer.pEvents = nullptr;
+ outputDataBuffer.dwStatus = 0;
+ outputDataBuffer.pSample = m_resamplerNeedsSampleBuffer ? sample.Get() : nullptr;
+ DWORD status = 0;
+ hr = m_resampler->ProcessOutput(0, 1, &outputDataBuffer, &status);
+ if (SUCCEEDED(hr)) {
+ ComPtr<IMFMediaBuffer> outputBuffer;
+ outputDataBuffer.pSample->ConvertToContiguousBuffer(outputBuffer.GetAddressOf());
+ DWORD len = 0;
+ BYTE *data = nullptr;
+ hr = outputBuffer->Lock(&data, nullptr, &len);
+ if (SUCCEEDED(hr))
+ out.push_back(QByteArray(reinterpret_cast<char *>(data), len));
+ outputBuffer->Unlock();
+ }
+ } while (SUCCEEDED(hr));
+
+ if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
+ hr = S_OK;
+
+ return hr;
+}
+
+QByteArray QWindowsResampler::resample(const QByteArrayView &in)
+{
+ m_totalInputBytes += in.size();
+
+ if (m_inputFormat == m_outputFormat) {
+ m_totalOutputBytes += in.size();
+ return {in.data(), in.size()};
+
+ } else {
+ Q_ASSERT(m_resampler && m_wmf);
+
+ QByteArray out;
+ HRESULT hr = processInput(in);
+ if (SUCCEEDED(hr))
+ hr = processOutput(out);
+
+ if (FAILED(hr))
+ qCWarning(qLcAudioResampler) << "Resampling failed" << hr;
+
+ m_totalOutputBytes += out.size();
+ return out;
+ }
+}
+
+QByteArray QWindowsResampler::resample(IMFSample *sample)
+{
+ Q_ASSERT(sample);
+
+ DWORD totalLength = 0;
+ HRESULT hr = sample->GetTotalLength(&totalLength);
+ if (FAILED(hr))
+ return {};
+
+ m_totalInputBytes += totalLength;
+
+ QByteArray out;
+
+ if (m_inputFormat == m_outputFormat) {
+ ComPtr<IMFMediaBuffer> outputBuffer;
+ sample->ConvertToContiguousBuffer(outputBuffer.GetAddressOf());
+ DWORD len = 0;
+ BYTE *data = nullptr;
+ hr = outputBuffer->Lock(&data, nullptr, &len);
+ if (SUCCEEDED(hr))
+ out.push_back(QByteArray(reinterpret_cast<char *>(data), len));
+ outputBuffer->Unlock();
+
+ } else {
+ Q_ASSERT(m_resampler && m_wmf);
+
+ hr = m_resampler->ProcessInput(m_inputStreamID, sample, 0);
+ if (SUCCEEDED(hr))
+ hr = processOutput(out);
+
+ if (FAILED(hr))
+ qCWarning(qLcAudioResampler) << "Resampling failed" << hr;
+ }
+
+ m_totalOutputBytes += out.size();
+
+ return out;
+}
+
+bool QWindowsResampler::setup(const QAudioFormat &fin, const QAudioFormat &fout)
+{
+ qCDebug(qLcAudioResampler) << "Setup audio resampler" << fin << "->" << fout;
+
+ m_totalInputBytes = 0;
+ m_totalOutputBytes = 0;
+
+ if (fin == fout) {
+ qCDebug(qLcAudioResampler) << "Pass through mode";
+ m_inputFormat = fin;
+ m_outputFormat = fout;
+ return true;
+ }
+
+ if (!m_resampler || !m_wmf)
+ return false;
+
+ ComPtr<IMFMediaType> min = QWindowsAudioUtils::formatToMediaType(*m_wmf, fin);
+ ComPtr<IMFMediaType> mout = QWindowsAudioUtils::formatToMediaType(*m_wmf, fout);
+
+ HRESULT hr = m_resampler->SetInputType(m_inputStreamID, min.Get(), 0);
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioResampler) << "Failed to set input type" << hr;
+ return false;
+ }
+
+ hr = m_resampler->SetOutputType(0, mout.Get(), 0);
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioResampler) << "Failed to set output type" << hr;
+ return false;
+ }
+
+ MFT_OUTPUT_STREAM_INFO streamInfo;
+ hr = m_resampler->GetOutputStreamInfo(0, &streamInfo);
+ if (FAILED(hr)) {
+ qCWarning(qLcAudioResampler) << "Could not obtain stream info" << hr;
+ return false;
+ }
+
+ m_resamplerNeedsSampleBuffer = (streamInfo.dwFlags
+ & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) == 0;
+
+ m_inputFormat = fin;
+ m_outputFormat = fout;
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/windows/qwindowsresampler_p.h b/src/multimedia/windows/qwindowsresampler_p.h
new file mode 100644
index 000000000..5885bffa6
--- /dev/null
+++ b/src/multimedia/windows/qwindowsresampler_p.h
@@ -0,0 +1,75 @@
+// 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
+
+
+#ifndef QT_QWINDOWSRESAMPLER_H
+#define QT_QWINDOWSRESAMPLER_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 <qbytearray.h>
+#include <qbytearrayview.h>
+#include <qaudioformat.h>
+#include <private/qcomptr_p.h>
+#include <private/qwindowsmediafoundation_p.h>
+#include <qt_windows.h>
+#include <mftransform.h>
+#include <QtCore/private/qfunctions_win_p.h>
+
+struct IMFSample;
+struct IMFTransform;
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsMediaFoundation;
+
+class Q_MULTIMEDIA_EXPORT QWindowsResampler
+{
+public:
+ QWindowsResampler();
+ ~QWindowsResampler();
+
+ bool setup(const QAudioFormat &in, const QAudioFormat &out);
+
+ QByteArray resample(const QByteArrayView &in);
+ QByteArray resample(IMFSample *sample);
+
+ QAudioFormat inputFormat() const { return m_inputFormat; }
+ QAudioFormat outputFormat() const { return m_outputFormat; }
+
+ quint64 outputBufferSize(quint64 inputBufferSize) const;
+ quint64 inputBufferSize(quint64 outputBufferSize) const;
+
+ quint64 totalInputBytes() const { return m_totalInputBytes; }
+ quint64 totalOutputBytes() const { return m_totalOutputBytes; }
+
+private:
+ HRESULT processInput(const QByteArrayView &in);
+ HRESULT processOutput(QByteArray &out);
+
+ QComHelper m_comRuntime;
+ QWindowsMediaFoundation *m_wmf{ QWindowsMediaFoundation::instance() };
+ QMFRuntimeInit m_wmfRuntime{ m_wmf };
+ ComPtr<IMFTransform> m_resampler;
+
+ bool m_resamplerNeedsSampleBuffer = false;
+ quint64 m_totalInputBytes = 0;
+ quint64 m_totalOutputBytes = 0;
+ QAudioFormat m_inputFormat;
+ QAudioFormat m_outputFormat;
+
+ DWORD m_inputStreamID = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_QWINDOWSRESAMPLER_H